各种排序算法

 

冒泡排序:是从左边第一个与右边的每一个都一个一个对比,如果大于的,则交换,然后用交换完的继续与更右边的元素对比,直到最后一个,最后n-1的位置存储的就是值最大的元素。。。然后再从左边开始...与右边对比,然后放到n-2位置上......然后n-3..最后再到0位置.....就排序完成

时间复杂度是O(n^2),而且正常情况下交换数据次数较多,效率比其他O(n^2)排序算法低一些,更不用说O(nlogn)的排序算法了

选择排序:从整个数组中找出最小的,与数组的第0元素交换,然后从索引1元素开始再往右找最小的元素,然后再与索引1元素交换。。。从索引2...索引3....索引n...排序完成(复杂度与冒泡差不多,代码具体效率会高一点,因为交换次数比较少)

时间复杂度O(n^2)

直接插入排序:一组数据无序的数组k,2, 5, 6, 0, 3, 9, 1, 7, 4, 8

当第i+1个元素小于第i个元素时,把第i+1个元素插入到0~i元素之间,插入后保证0~i+1元素之间是有序的。

(如果牺牲一点点空间的话,其实可以把有序的数据从原数组中分出来,放在另一个有序数组中)

以上面的数据为例,从左往右对比,k[2]>k[3],

所以此时需要把k[3]插入到k[0]~k[2]之间,并且保持有序。插入后数组为:0 , 2, 5, 6, 3, 9, 1, 7, 4, 8。

然后再从K[3]开始往右对比....剩下的与上面一样。

希尔排序:是对直接插入排序的改进。

将序列分为若组,分组不是逐段分的,而是设置一个增量d,距离为d的倍数为一组,再将d=d/2(也可以是d=d/3+1等等)进行分组,直至d=1,每次分组的数据都使用直接插入排序算法进行排序。 
分析:数组a[10]={5,8,4,3,9,6,1,7,2,10} 
5 8 4 3 9 6 1 7 2 10 
第一趟:n=10,d=n/2=5 

5 - - - - 6 
8 - - - - 1 
4 - - - - 7 
3 - - - - 2 
9 - - - -10 

这里分了五组,对着五组每组都使用直接插入排序。
排序完后的五组为:

5 - - - - 6 
1 - - - - 8 
4 - - - - 7 
2 - - - - 3
9 - - - -10 


得到:5 1 4 2 9 6 8 7 3 10 
第二趟:d=d/2=2 
5 - 4 - 9 - 8 - 3 
1 - 2 - 6 - 7 - 10 

这里分了两组,对着两组每组都分别使用直接插入排序。
排序完后的两组为:

3 - 4 - 5 - 8 - 9 
1 - 2 - 6 - 7 - 10 
得到:3 1 4 2 5 6 8 7 9 10 
第三趟:d=d/2=1 

当间隔d=1时,只分为一组

则直接对所有数据进行直接插入排序就行了。
得到:1 2 3 4 5 6 7 8 9 10 

 

堆排序:把一组无序的数据,先排成大顶堆或者小顶堆。当元素有n个,排成大顶堆时(存储结构是以数组形式存储),第一次把堆顶元素(死索引为0)与索引为n-1位置元素交换,然后重新把0~n-2之间的元素再排成大顶堆(此时操作范围是0~n-2之间,然后把堆顶元素进行下沉操作就行了)

归并排序

归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

归并排序示例:

                                        

实现方法:把一组数据每次分为两个序列,然后这两序列每个序列又再次分为两个序列。。。直到每个序列的元素只有一个为止(对应于上图的第一行)。然后第一个序列与第二个序列融合进一个大的序列,融合后这个大序列里面的元素保持有序(对应于上图的第二行)。。。然后这个大序列又与另一个大序列融合进一个更大的序列,融合后更大序列的元素是有序的(对应于上图的第三行)....直到最后融合的序列元素个数与总元素个数相等....

可以用递归实现,也可以用循环实现。

基数排序

第一步

以LSD为例,假设原来有一串数值如下所示:

73, 22, 93, 43, 55, 14, 28, 65, 39, 81

首先根据个位数的数值,在走访数值时将它们分配至编号0到9的桶子中:

0

1 81

2 22

3 73 93 43

4 14

5 55 65

6

7

8 28

9 39

第二步

接下来将这些桶子中的数值重新串接起来,成为以下的数列:

81, 22, 73, 93, 43, 14, 55, 65, 28, 39

接着再进行一次分配,这次是根据十位数来分配:

0

1 14

2 22 28

3 39

4 43

5 55

6 65

7 73

8 81

9 93

第三步

接下来将这些桶子中的数值重新串接起来,成为以下的数列:

14, 22, 28, 39, 43, 55, 65, 73, 81, 93

这时候整个数列已经排序完毕;如果排序的对象有三位数以上,则持续进行以上的动作直至最高位数为止。

LSD的基数排序适用于位数小的数列,如果位数多的话,使用MSD的效率会比较好。MSD的方式与LSD相反,是由高位数为基底开始进行分配,但在分配之后并不马上合并回一个数组中,而是在每个“桶子”中建立“子桶”,将每个桶子中的数值按照下一数位的值分配到“子桶”中。在进行完最低位数的分配后再合并回单一的数组中。

快速排序:

找第一个元素a[0]的值作为 基数,从数组最右边 往左对比,找出比a[0]小的值,与a[0]对换,然后记下这个值位置(假设a[9])。。现在a[9]是之前的a[0],然后,开始从数组的左边开始对比(由于a[0]现在的值是比小,所以 为了节省效率 没必要再对比了,让i++以后再比较,也就是从a[1]开始)。。此时从左往右,找到一个比基数大的值,再与基数交换……以此类推。。。第一个大循环结束后,该基数左边的数肯定比基数小,右边的比基数大(这样,基数在数组中的位置就确定了),然后,再把基数左边的数 看成一个新数组,右边的数也看成一个新数组,再利用前面的方法,各自再找一个基数……递归下去。。。然后,每个数都做过基数,那么 这些基数最终都会找到自己的位置,然后,排序完成。。

 

优化快速排序:

(1).基数的选择要更加合理,方法:每一个序列中头、中、尾选择三个元素,这三个中值处于中间大小的作为基数。

(2).交换次数可以减少,变成赋值运行。。把基数取出存在局部变量中,记住被交换后的元素的索引即可,被交换的其他元素只需直接赋值到基数所处位置。

把基数取出存在局部变量a中,存好当前的基数的索引到b中,当达到条件要交换时,把要交换的元素赋值到数组arr[b],然后更新b存储的值为被交换的元素的索引。。。然后再对比,当再次达到条件要交换时,重复上面的步骤。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值