第九章:内部排序

排序:将一个数据元素(或记录)的任意序列,重新排列成一个按关键字有序的序列。

稳定性——若两个记录A和B的关键字值相等,且排序后A、B的先后次序保持不变,则称这种排序算法是稳定的。

1.插入排序

思想:每步将一个待排序的对象,按其关键码大小,插入到前面已经排好序的一组对象的适当位置上,直到对象全部插入为止。

简言之,边插入边排序,保证子序列中随时都是排好序的。

1)  直接插入排序

    在已形成的有序表中线性查找,并在适当位置插入,把原来位置上的元素向后顺移
 

时间效率: 因为在最坏情况下,所有元素的比较次数总和为(0+1+…+n-1)→O(n^2)。

其他情况下也要考虑移动元素的次数。 故时间复杂度为O(n^2)

空间效率:仅占用1个缓冲单元——O(1)

算法的稳定性:稳定

直接插入排序算法的实现:

void InsertSort ( SqList &L ) 

{ //对顺序表L作直接插入排序

 for ( i = 2;  i <=L.length; i++) //假定第一个记录有序

{

     L.r[0]= L.r[i];

       j=i-1 ;                      //先将待插入的元素放入“哨兵”位置

     while(L[0] .key<L[j].key)

    {  

        L.r[j+1]= L.r[j];

        j--  ;                    

    }      //只要子表元素比哨兵大就不断后移

    L.r[j+1]= L.r[0];      //直到子表元素小于哨兵,将哨兵值送入

                                 //当前要插入的位置(包括插入到表首)

}

}

2)折半插入排序

子表有序且为顺序存储结构,则插入时采用折半查找定可加速。

优点:比较次数大大减少,全部元素比较次数仅为O(nlog2n)。

时间效率:虽然比较次数大大减少,可惜移动次数并未减少, 所以排序效率仍为O(n^2) 。

空间效率:仍为 O(1)

稳 定  性: 稳定

 

3)希尔排序—不稳定

基本思想:先将整个待排记录序列分割成若干子序列,分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。

优点:让关键字值小的元素能很快前移,且序列若基本有序时,再用直接插入排序处理,时间效率会高很多。

时间效率:当n在某个特定范围内,希尔排序所需的比较和移动次数约为n^1.3,当n->无穷,可减少到n(log2n)^2

空间效率:O(1)
 

4)快速排序

基本思想:从待排序列中任取一个元素 (例如取第一个) 作为中心,所有比它小的元素一律前放,所有比它大的元素一律后放,形成左右两个子表;然后再对各子表重新选择中心元素并依此规则调整,直到每个子表的元素只剩一个。此时便为有序序列了。

优点:因为每趟可以确定不止一个元素的位置,而且呈指数增加,所以特别快!

前提:顺序存储结构
 

时间效率:O(nlog2n) —因为每趟确定的元素呈指数增加

空间效率:O(log2n)—因为递归要用栈(存每层low,high和pivot)

稳 定 性: 不 稳 定 — —因为有跳跃式交换。

算法:

int partition(SqList &L,int low,int high)

{

  L.r[0] = L.r[low];

  pivot key = L.r[low].key;

    while(low < high)

    {

     while(low<high&&L.r[high]>=pivot) high--;

     L.r[low] = L.r[high];

     while(low<high&&L.r[low]<=pivot) low++;

     L.r[high] = L.r[low];

    }

    L.r[low] = pivot;

    return low;

}

 

5)冒泡排序

基本思路:每趟不断将记录两两比较,并按“前小后大”(或“前大后小”)规则交换。

优点:每趟结束时,不仅能挤出一个最大值到最后面位置,还能同时部分理顺其他元素;一旦下趟没有交换发生,还可以提前结束排序。

前提:顺序存储结构
 

冒泡排序的算法分析:

时间效率:O(n^2) —因为要考虑最坏情况

空间效率:O(1) —只在交换时用到一个缓冲单元

稳 定 性: 稳定  —25和25*在排序前后的次序未改变

冒泡排序的优点:每一趟整理元素时,不仅可以完全确定一个元素的位置(挤出一个泡到表尾),还可以对前面的元素作一些整理,所以比一般的排序要快。

选择排序:选择排序的基本思想是:每一趟在后面n-i 个待排记录中选取关键字最小的记录作为有序序列中的第i  个记录。

6)简单选择排序

思路异常简单:每经过一趟比较就找出一个最小值,与待排序列最前面的位置互换即可。

——首先,在n个记录中选择最小者放到r[1]位置;然后,从剩余的n-1个记录中选择最小者放到r[2]位置;…如此进行下去,直到全部有序为止。

优点:实现简单

缺点:每趟只能确定一个元素,表长为n时需要n-1趟

前提:顺序存储结构
 

时间效率:O(n^2)——虽移动次数较少,但比较次数较多

空间效率:O(1)

算法稳定性——不稳定

Void SelectSort(SqList  &L ) 

{

for (i=1;  i<L.length; ++i)

{

     j = SelectMinKey(L,i);  //在L.r[i..L.length]中选择key最小的记录

     if( i!=j )   r[i] <--> r[j]; //与第i个记录交换

      } //for

  }  //SelectSort

 

7)堆排序

设有n个元素的序列 k1,k2,…,kn,当且仅当满足下述关系之一时,称之为堆。
 

如果让满足以上条件的元素序列 (k1,k2,…,kn)顺次排成一棵完全二叉树,则此树的特点是:树中所有结点的值均大于(或小于)其左右孩子,此树的根结点(即堆顶)必最大(或最小)。

堆排序算法分析:

时间效率:O(nlog2n)。因为整个排序过程中需要调用n-1次HeapAdjust( )算法,而算法本身耗时为log2n;

空间效率:O(1)。仅在第二个for循环中交换记录时用到一个临时变量temp。

稳定性: 不稳定。

优点:对小文件效果不明显,但对大文件有效。

 

8)归并排序----稳定

将两个或两个以上有序表组合成一个新的有序表。

时间复杂度:O(nlogn)

空间复杂度:和待排记录等数量的辅助空间。

 

9)基数排序

时间复杂度:对于n各记录(每个记录含d个关键字,每个关键字取值范围为rd个值)进行链式基数排序的时间复杂度为O(d(n+rd)),其中每一趟分配的时间复杂度为O(n),每一趟收集的时间复杂度为O(rd)

10)各种内部排序方法的比较讨论
 

(1) 从平均时间性能看,快速排序最佳,其所需时间最省,但快速排序的最坏情况下的时间性能不如堆排序和快速排序。后两者相比较,在n较大时,归并排序所需时间较堆排序省,但它所需的辅助存储量最多。

(2)基数排序的时间复杂度可写成O(dn)。因此,它最适用于n值很大而关键字较小的序列。

(3)从方法的稳定性来比较,基数排序是稳定的内排方法,所需时间复杂度为O(n^2)的简单排序方法也是稳定的,然而,快速排序、堆排序和希尔排序等时间性能较好的排序方法是不稳定的。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值