zoukankan      html  css  js  c++  java
  • 数据的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哈哈~


     

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

  • 相关阅读:
    SQL Server 2017 左补齐
    Mac下面配置oh-my-ssh
    关于VSTS自动Build报错问题之Microsoft.Net.Compilers
    Angular5中提取公共组件之radio list
    Angular5中提取公共组件之checkbox list
    关于博客园开放API的授权问题解决
    记开发个人图书收藏清单小程序开发(十)DB开发——新增图书信息
    Keepalived + Nginx:负载均衡+高可用服务 --keepalived介绍及应用
    Nginx:综合架构负载均衡 -- nginx负载均衡企业实践应用
    Nginx:综合架构负载均衡 -- nginx负载均衡介绍部署及应用
  • 原文地址:https://www.cnblogs.com/Darknesses/p/12002572.html
Copyright © 2011-2022 走看看