数据的6种排序方法

今天讲了堆排序,就这以前学过的排序方法,我来做一个总结

 

1、选择排序:

选择排序是比较基础的排序方法,需要两个循环,用于对每一个数进行查找和替换,不用多说,代码如下:

<span style="color:#000000;BACKGROUND-COLOR: #ffff99">#include<cstdio>
<span style="font-size:12px;">int a[101];
</span>int main()
{
	int n,t,i,j;
	scanf("%d",&n);
	for(i=0;i<n;i++)
		scanf("%d",&a[i]);
	for(i=0;i<n-1;i++)
		for(j=i+1;j<n;j++)
			if(a[i]>a[j])
			{
				t=a[i];
				a[i]=a[j];
				a[j]=t;
			}
	for(i=0;i<n;i++)
		printf("%d ",a[i]);
}</span>

其实也没什么优点,关键是好想,对于初学者,是必须掌握的

 

2、冒泡排序:

跟选择排序差不多,只是选择排序先从前面确定数,而冒泡排序恰恰相反

代码如下:

<span style="color:#000000;BACKGROUND-COLOR: #ffff99">#include<cstdio>
int a[101];
int main()
{
	int n,t,i,j;
	scanf("%d",&n);
	for(i=0;i<n;i++)
		scanf("%d",&a[i]);
	for(i=0;i<n-1;i++)
		for(j=0;j<n-i-1;j++)
			if(a[j]>a[j+1])
			{
				t=a[j+1];
				a[j+1]=a[j];
				a[j]=t;
			}
	for(i=0;i<n;i++)
		printf("%d ",a[i]);
}</span>

这个就不必多说了吧

 

3、桶排序:

这个其实根本不叫排序,只是把一个数装入与它数值一样的数组小房间里罢了,再一个个输出

代码如下:

<span style="color:#000000;BACKGROUND-COLOR: #ffff99">#include<cstdio>
int a[100001];
int main()
{
	int n,i,k;
	scanf("%d",&n);
	for(i=0;i<n;i++)
	{
		scanf("%d",&k);
		a[k]++;
	}
	for(i=0;i<100001;i++)
		while(a[i])
		{
			printf("%d ",i);
			a[i]--;
		}
}</span>


桶排序的优点在于,当数据个数很大时,几乎不会耗时,但一旦单个数值很大的话,会出现数组崩溃或无法设立那么大的数组

 

4、快速排序:

快速排序是指一个数组从中间划开,中间那个数为m,当 l > m && r < m 时,交换 l 和 r,这个方法可以跳过符合标准的数

代码如下:

<span style="color:#000000;BACKGROUND-COLOR: #ffff99">#include<cstdio>
int a[101];
void sort(int l,int r)
{
	int i,j,m,t;
	i=l,j=r;
	m=(l+r)/2;//一刀两断
	do//先做一遍再说
	{
		while(a[i]<a[m]) i++;
		while(a[j]>a[m]) j--;
		if(i<=j)
		{
			t=a[i],a[i]=a[j],a[j]=t;//作交换
			i++;
			j--;
		}
	}while(i<=j);
	if(l<j) sort(l,j);//二分继续找
	if(i<r) sort(i,r);
}
int main()
{
	int n,i;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
		scanf("%d",&a[i]);
	sort(1,n);
	for(i=1;i<=n;i++)
		printf("%d ",a[i]);
}</span>

快排虽快,但是极不稳定,真正稳定的排序方法,是下面的归并排序


5、归并排序

归并排序是指将数组划分成一个个小分段,一个个小分段进行排序,最后在合并起来排序,有二分查找的思想在里面

代码如下:

<span style="color:#000000;BACKGROUND-COLOR: #ffff99">#include<cstdio>
int a[101];
void sort(int l,int r)
{
	int s[101]={0};
	int m,i,j,k;
	if(l==r)//只剩一个就无视了
		return;
	m=(l+r)/2;
	sort(l,m);//二分查找
	sort(m+1,r);
	i=l,j=m+1,k=l;
	while(i<=m&&j<=r)
	{
		if(a[i]<=a[j])//s 数组的挑选
		{
			s[k]=a[i];
			i++;
			k++;
		}
		else
		{
			s[k]=a[j];
			j++;
			k++;
		}
	}
	while(i<=m)//剩下的一口气塞进去
	{
		s[k]=a[i];i++;k++;
	}
	while(j<=r)
	{
		s[k]=a[j];k++;j++;
	}
	for(i=l;i<=r;i++)//有借有还
		a[i]=s[i];
}
int main()
{
	int n,i;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
		scanf("%d",&a[i]);
	sort(1,n);
	for(i=1;i<=n;i++)
		printf("%d ",a[i]);
}</span>

归并排序非常的稳定,且时间复杂度极低

下面来看一个例题 (  ⊙ o ⊙  )

描述考虑1,2,…,n的排列i1,i2,…,in,如果其中存在j,k,满足 j < k 且ij > ik,那么就称(ij,ik)是这个排列的一个逆序。一个排列含有逆序的个数称为这个排列的逆序数。例如排列 263451 含有8个逆序(2,1),(6,3),(6,4),(6,5),(6,1),(3,1),(4,1),(5,1),因此该排列的逆序数就是8。显然,由1,2,…,n 构成的所有n!个排列中,最小的逆序数是0,对应的排列就是1,2,…,n;最大的逆序数是n(n-1)/2,对应的排列就是n,(n-1),…,2,1。逆序数越大的排列与原始排列的差异度就越大。现给定1,2,…,n的一个排列,求它的逆序数。

输入

第一行是一个整数n,表示该排列有n个数(n <= 100000)。
第二行是n个不同的正整数,之间以空格隔开,表示该排列。

 

输出

输出该排列的逆序数。

 

样例输入6
2 6 3 4 5 1
 样例输出8

 

这道题就可以用归并排序,交换的时候加一下交换数就行了

代码如下:

<span style="color:#000000;BACKGROUND-COLOR: #ffff99">#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int a[100001],b[100001],n;
long long g;
void msort(int l,int r)
{
	int m,i,j,k;
	m=(l+r)/2;
	if(l==r)
		return;
	msort(l,m);
	msort(m+1,r);
	i=l;
	j=m+1;
	k=l;
	while(i<=m&&j<=r)
	{
		if(a[i]>a[j])
		{
			b[k]=a[j];
			g=g+m+1-i;//加上比其小的数的个数
			j++;
			k++;
		}
		else
		{
			b[k]=a[i];
			i++;
			k++;
		}
	}
	while(i<=m)
	{
		b[k]=a[i];
		i++;
		k++;
	}
	while(j<=r)
	{
		b[k]=a[j];
		j++;
		k++;
	}
	for(i=l;i<=r;i++)
		a[i]=b[i];
	return;
}
int main()
{
	int i;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
		scanf("%d",&a[i]);
	msort(1,n);
	printf("%lld",g);
}</span>


几乎就是复制粘贴的啊

 

6、堆排序

其实就是使用二叉树的特性来排序,通过交换来将最小数转移到根节点,再删除根节点,重新建树

可使用algorithm的函数

代码如下:

<span style="color:#000000;BACKGROUND-COLOR: #ffff99">#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[10005];
int k;
int main()
{
	int n,i;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		push_heap(a+1,a+i+1,greater<int>());//建树
	}
	for(i=1;i<=n;i++)
	{
		printf("%d ",a[1]);//输出树根
		pop_heap(a+1,a+n-i+2,greater<int>());//删除树根,重新建树
	}
}</span>

跟快排一样,比较的不稳定,但是很方便


下面再来看一个例题 (  ⊙ o ⊙  )

合并果子

题目描述
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。 多多决定把所有的果子合成一堆。每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。 假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。例如有3种果子,数目依次为1,2,9。可以先将 1、2堆合并,新堆数目为3,耗费体力为3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为 12。所以多多总共耗费体力=3+12=15。可以证明15为最小的体力耗费值。

输入
第1行:一个整数n(1≤n≤10000),表示果子的种类数。第2行:包含n个整数,用空格分隔,第i个整数ai(1≤ai≤20000)是第i种果子的数目。

输出
一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于2^31。

样例输入
3
1 2 9

样例输出
15

 

这道题就可以使用堆排序啦 ~ ( ≧ ▽ ≦ ) /~

使用的总力气用一个变量,一直加加就好啦

代码如下:

<span style="color:#000000;BACKGROUND-COLOR: #ffff99">#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[10005];
int k;
int main()
{
	//freopen("fruit.in","r",stdin);
	//freopen("fruit.out","w",stdout);
	int n,i;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		push_heap(a+1,a+i+1,greater<int>());
	}
	int x;
	for(i=1;i<n;i++)
	{
		x=a[1];
		pop_heap(a+1,a+n-i+2,greater<int>());
		x+=a[1];
		pop_heap(a+1,a+n-i+1,greater<int>());
		k+=x;
		a[n-i]=x;
		push_heap(a+1,a+n-i+1,greater<int>());
	}
	printf("%d",k);
}</span>


除了这种方法外,还可以使用优先队列

priority_queue<int,vector<int>,greater<int> >h;//注意:int> >h 之间必须有一个空格

 

代码如下:

<span style="color:#000000;BACKGROUND-COLOR: #ffff99">#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
priority_queue<int,vector<int>,greater<int> >h;
int main()
{
	//freopen("fruit2.in","r",stdin);
	//freopen("fruit2.out","w",stdout);
	int n,k,i;
	scanf("%d",&n);
	for(i=0;i<n;i++)
	{
		scanf("%d",&k);
		h.push(k);
	}
	k=0;
	int x=0;
	for(i=0;i<n-1;i++)
	{
		x+=h.top();
		h.pop();
		x+=h.top();
		h.pop();
		k+=x;
		h.push(x);
		x=0;
	}
	printf("%d",k);
}</span>

黑科技啊 ╮(╯▽╰)╭,这玩意可以把推进去的数自动排序,妈妈再也不用担心我的排序了 O(∩_∩)O哈哈~


 

好了,这就是我总结的排序方法啦,喜欢或者对你有所帮助的话,别忘了顶一下哟,蟹蟹 ~(≧▽≦)/~

原文地址:https://www.cnblogs.com/Darknesses/p/12002572.html