一般而言我们所需要了解的排序有几种种:冒泡排序,简单选择排序,堆排序,归并排序,快速排序,桶排序。
而需要我们了解原理的有表排序与基数排序
冒泡排序
原理:
- 比较相邻的两个元素,如果前一个元素大于(小于)后一个元素,则交换。
- 第一趟排序第一个与第二个一对比较与交换,随后第二个与第三个比较交换,直到最后两个,这样就会将最大(最小)的数移动至最后一位。
- 第二趟将第二大(第二小)的数移动到最后一位。
- ……
- 因此我们需要n-1趟
for(int i=0; i<n; i++)
{
for(int j=0; j<n-i; j++)
{
if(a[j]>a[j+1]
{
int t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
}
时间复杂度:O(n2)
简单选择排序
简单选择排序我觉得是最符合人的思维的排序之一。
原理: 他其实很简单,在i到n的里面寻找最小的,并且与第i个值交换位置。
for(int i=0;i<n-1;i++)
{
int minnum=a[i];
for(int j=0;j<n;j++)
{
if(a[i]<minnum)
{
minnum=a[i];
}
}
if(minnum!=a[i])
swap(minnum,a[i]);
}
堆排序
我之前写了了关于二叉堆的内容,其中就包括了堆排序
二叉堆
归并排序
我以前写过一篇归并排序寻找逆序数的博客,就不在这里多讲了。
逆序数的寻找方法
快速排序
快排我也单独写过博客,不过写的有点粗糙,是看着啊哈算法的思路写的。
快速排序
桶排序
桶排序是一种牺牲空间,换取时间的算法。
原理: 桶排序适合知道需要排序的数的范围大小,然后以此范围开一个数组,最后将每个数放到他数组中对应的位置里,就和把一个一个数放到一个一个桶里一样,所以叫桶排序。
c语言代码
#include<stdio.h>
int main()
{
int a[10]= {0},i,j,x;
for(i=0; i<10; i++)
{
scanf("%d",&x);
a[x]++;
}
for(i=0; i<10; i++)
for(j=0; j<a[i]; j++)
printf("%d ",i);
return 0;
}
表排序
表排序是可以用来解决那些排序非数字的序列,或者移动序列会有很大的花费的序列,比如你要整理一排书籍,如果你用冒泡排序的思想那么就会不断移动书的位置。
那么这种情况就可以需要我们的表排序来解决了。
这里只讲解一下思路,因为代码我还没写出来(黑脸),留待日后添加。
a | [0] | [1] | [2] | [3] | [4] | [5] | [6] | [7] |
---|---|---|---|---|---|---|---|---|
key | f | d | c | a | g | b | h | e |
table | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
那这个时候其实我们并不需要移动实际的元素,我们只需要移动指向他们的指针就好了,比较指针我们可以使用插入排序。
基数排序
其实我觉得,基数排序就是升级版的桶排序,他只是把一些地方优化了而已。
举个栗子,比如我给你十个数,他的范围只有1-10,那么我们可以开一个大小为十的数组,这样可以很方便,并且空间占用也不大。
但是,如果我们还是给你十个数,但是他得数的范围从0到1e6随机的,那么我们需要开1e6的数组大小,这样明显占用了大量的内存空间。
然后浙大的网课里面介绍了一种便利的方法:次级优先。
比如像刚刚那个问题,0到1e6的大小的数组,我们正常的桶排序是要开1e6大小的数组,然而我们转化一下思路,我们还是开0-9这么多个的数组,然后我们以位数来鉴别存储。
先从个位开始比较大小存储,再从十位的数字开始存储,直到所有的数都存储到了0这个桶中,那么我们的排序序号便是0的里面的元素。