②在各个子序列中进行直接插入排序;
③取一个新的d(比原来的要小,一般取原来的1/2),重复执行1),2),直到d=1为止(此时,整个序列变成直接插入排序)。
例如:
利用希尔排序对下序列进行排序。
(72,73,71,23,94,16,15,68),n=8
过程:
1>第一次分组,取d=n/2=4,则对序列分组为:
对每个子序列直接插入排序得(4组):
7216152394737168
2>第二次分组,取d=2(原来的一半),对序列分组为:
对每个子序列直接插入排序得(2组):
1516712372689473
3>第三次分组,取d=1(原来的一半),序列为一组,直接插入排序得:
1516236871727394
排序完成。
说明:
步长的选择是迄今为止还没有完全解决的。
该算法的时间复杂度O(n1.5),是不稳定排序(因为存在着跳跃)。
『真题解析』
1.给出一组关键字T=(12,2,16,30,8,28,4,10,20,6,18),写出用下列算法从小到大排序时第一趟结束时的序列;
(1)希尔排序(第一趟排序的增量为5)
(2)快速排序(选第一个记录为枢轴(分隔))
(3)链式基数排序(基数为10)
【解析】
(1)一趟希尔排序:
12,2,10,20,6,18,4,16,30,8,28(D=5)
(2)一趟快速排序:
6,2,10,4,8,12,28,30,20,16,18
(3)链式基数排序LSD[0][1][2][3][4][5][6][7][8][9]
↓↓↓↓↓
分配30124168
↓↓↓↓
102628
↓↓
2018
收集:
→30→10→20→12→2→4→16→6→8→28→18
(六)快速排序
1.基本思想
快速排序是对冒泡排序的一种改进,其基本思想是:
通过一趟排序将待排序的记录分成独立的两部分,其中一部分记录的关键字比另一部分的关键字小。
然后对这两部分再继续排序,一直达到整个序列有序。
设待排序序列为{L.r[1],L.r[2],...,L.r[n]},首先任意选取一个记录(通常选择第一个记录L.r[1])作为支点(pivot),然后按照下述原则排列其余记录:
将所有关键字比L.r[1].key小的记录都安排在它的位置之前,将所有关键字比L.r[1].key大的记录都安排在它的位置之后。
可以发现,在安置的过程中,L.r[1]的确切位置将被最终确定。
设该支点(pivot)最后确定的位置为i,则将序列分割为左右两部分。
这个过程称为一趟快速排序。
2.具体步骤
设待排序序列用数组e[low..high]保存。
设置两个指针low和high,分别指向数组的开始位置和终止位置。
设支点记录为e[low],并将之暂存于t。
首先,从high的位置向前搜索,找到第一个小于t的记录,将这个记录和e[low]的值交换;然后,从low所指向的位置向后搜索,找到第一个值大于t的记录,将这个记录和e[high]的值交换。
重复以上步骤,直到low==high。
完成一趟排序,low(或者high)指向的位置就是第一个元素的确切位置。
(从两边向中间“夹挤”)。
第一趟完成后,确定了第一个元素的确切位置,同时生成了两个子序列,然后再对这两个序列使用同样的办法,最终实现整个序列的有序。
举例:
利用快速排序法对以下序列进行排序:
(49,38,65,97,76,13,27,49)
过程如下:
初始状态:
high向左移动(high--),直到找到小于t(49)的关键字27,将27的值赋给e[low],如下:
接着low开始向右移动(low++),直到找到大于t(49)的关键字65,将65的值赋给e[high],如下:
high继续左移(high--),直到一个小于t的数13,将之赋给e[low],如下:
low继续右移(low++),直到找到大于t(49)的关键字97,将之赋给e[high],如下:
high继续左移(high--),没有找到比t(49)还小的数,但是由于出现了high==low的情况,结束左移。
如下:
此时low(或者high)指向的位置就是第一个元素的确定位置:
e[low]=t;
经过以上一趟快速排序,可将原序列分为了两个序列,同时确定关键字49的确切位置,如下:
{27,38,13}49{76,97,65,49}
下面再分别对两个子需类进行快速排序,得最终结果:
{13}27{38}49{49,65}76{97}
49{65}
则最终得有序序列:
(13,27,38,49,49,6576,97)
说明:
在一趟排序中,支点最后才确定位置,故只需最后一步赋值即可,中间不必交换。
即,虽然快速排序是交换排序的一种,但是可以不用交换操作即可实现)
该算法由于有不相邻元素交换,故是不稳定排序,其时间复杂度为O(nlog2n),是内排序中最好的方法之一。
『真题解析』
1.我们知道,对于n个元素组成的线性表进行快速排序时,所需进行的比较次数与这n个元素的初始排序有关。
问:
(1)当n=7时,在最好情况下需进行多少次比较?
请说明理由。
(2)当n=7时,给出一个最好情况的初始排序的实例。
(3)当n=7时,在最坏情况下需进行多少次比较?
请说明理由。
(4)当n=7时,给出一个最坏情况的初始排序的实例。
【解析】
(1)在最好情况下,假设每次划分能得到两个长度相等的子文件,文件的长度n=2k-1,那么第一遍划分得到两个长度均为n/2的子文件,第二遍划分得到4个长度均为n/4的子文件,以此类推,总共进行k=log2(n+1)遍划分,各子文件的长度均为1,排序完毕。
当n=7时,k=3,在最好情况下,第一遍需比较6次,第二遍分别对两个子文件(长度均为3,k=2)进行排序,各需2次,共10次即可。
(2)在最好情况下快速排序的原始序列实例:
4,1,3,2,6,5,7。
(3)在最坏情况下,若每次用来划