前言
《数据结构最后一弹》——排序
看完本篇,你将了解:
①查找问题概述,二者的联系
②插入排序(直接插入排序、折半插入排序、2–路插入排序、表插入排序、希尔排序)
③交换排序(冒泡排序、快速排序)
④选择排序(简单选择排序、堆排序)
⑤归并排序
⑥基数排序(多关键字排序介绍)
一、查找问题概述
1.基本概念
(1)“排序”是基于数据逻辑结构T=(D,R)定义的一种重要的运算。
(2)功能是将一个数据元素的任意序列,依据关键字的大小,重新排列成一个有序的序列。
(3)D是数据元素集;
R是数据元素之间关系偶对集。
(4)为何要排序呢?
例子:由多个数据元素构成的序列中查找关键字等于某个具体值的数据元素。
讨论:如果数据元素元素的关键字无序的话,我们只能采用顺序查找方法,代价高。
反之,如果数据元素元素的关键字有序的话,则可以采用如折半查找的更高效率的查找方法。
(5)术语:能唯一标识数据元素的一个分量或多个分量的组合称为关键字;
不能唯一标识数据元素的分量称为次关键字。
注:如果一个排序的算法,对于数据元素按照次关键字排序后,能确保相同次关键字的数据元素排序前后,相对次序不变,则称该算法称为是稳定的,否则称该算法是不稳定的。
(6)内部排序:指对存储在计算机的主存储器(也称“内存”)中的数据进行排序的过程。
(7)外部排序:指对存储在计算机的外存储器(也称“外存”)中的数据进行排序的过程。
注:在此我们只讨论内部排序
2.内部排序
(1)插入排序
(2)交换排序
(3)选择排序
(4)归并排序
(5)基数排序
二、插入排序
1.直接插入排序法
(1)基本原理:先把a1看成一个有序的包含一个数据元素的序列。然后不断地在一个递增有序的序列(a1,…,ai-1)(2≤i≤n)中,插入一个数据元素a,使得a1,…ai-1,ai构成一个新的有序的序列。
(2)基本步骤
①确定插入位置;
②移动元素;
③填入新元素。
也可合并为 ①边确定插入位置边移动元素;
②填入新元素。
(3)正序情况:算法的比较次数和移动次数均达到最好,待插入元素仅仅与左边一个元素比较一次,不需要移动。
即:比较次数和移动次数分别为n-1次和0次
(4)逆序情况:算法的比较次数和移动次数均达到最坏
即:比较和移动次数分别为2+3+…+n次和(2+1)+(3+1)+…+(n+1)次。
(5)算法时间性能:Tbest(n)=O(n),Tworst(n)=O(n^2)
假设待排序的数据元素的各种排列概率相同,可以取上述最小值和最大值的均值作为算法的比较平均次数和移动平均次数,约为n^2/4次。
Taverage(n)= O(n^2)
(5)变种:
①半插入排序
②2-路插入排序
③表插入排序
④希尔排序
2.折半插入排序
(1)折半插入排序是利用待插入表的有序性,将上述直接插入排序中的顺序查找定位,改进采用为折半查找法定位。
(2)最坏情况降至O(nlog n),总移动元素次数不变,故算法最坏和最好时间复杂度不变
Tworst(n)=Taverage(n)= o(n^2)
3.2-路插入排序
(1)利用辅助数组的存储空间,首尾视为循环状态,以D[1]作为中间位置分为两个有序子表
将待排序的数据元素,分情况选择插入到这两个子表的某一表中
(2)算法思想:
①取出表L=(a, a2, a3,… , aj, … , an )的第1个元素a存入辅助空间D[1];
②取出表L的下一个元素ai(2≤i≤n),如果ai<D[1],则插入到D[1]之左边的有序子表,否则插入到D[1]之右边的有序子表;
③重复②,直到表L的最后一个元素an插入后为止
(3)算法时间性能:确定插入位置的最坏情况和平均情况的移动次数可减少大约一半
但比较次数不变,故算法最坏和最好时间复杂度不变
Tworst(n)=Taverage(n)= o(n^2)
4.表插入排序
(1)定义:表插入排序是基于静态链表的这样一种物理存贮结构,将待排序数据元素按照大小顺序建立起静态链表。
这个静态链表是以0下标为头结点的循环链表,头结点存储关键字的最大理论值MAXINT,担当“哨兵”作用。
(2)算法思想:
从表L=(a1,a2,a3,… , ai… , an)的第2个元素a2开始,直到最后一个元素an为止,逐个插入ai到以0下标为头结点的循环静态链表,使其仍然保持有序。
(3)插入每个元素ai的操作:
①确定插入位置,即从循环静态链表首结点开始,第一次遇到大于ai的元素x时,x所在结点之前为ai元素所在结点的插入位置;
②修改指针,即ai元素所在结点指向x所在结点,将x所在结点的前驱结点指向ai元素所在结点。
(4)算法时间性能:需要n-1趟插入,仅需2n次指针修改,避免数据元素移动的运算
比较次数与直接插入一样,故算法最坏和最好时间复杂度不变
Tworst(n)=Taverage(n)= o(n^2)
5.希尔排序
(1)直接插入排序的特性:待排序数据元素序列越接近正序,其时间复杂度会越低。
待排序数据元素序列为正序时,其时间复杂度会从O(n^2)逐渐降低至O(n)。
(2)基本思想:利用上述特性
先将整个待排序数据元素序列分割成若干个子序列分别进行直接插入排序,待整个序列中的数据元素“基本有序”时,
再对全体数据元素构成的序列进行一次直接插入排序。
(3)把在第i步中,整个序列分成的组数记为di。一共进行的排序趟数计做m。那么,这里应该满足如下一些条件:
①dm=1:最后总要进行一次直接插入排序
②当1<=i,j<=m,且 i<j时,di>dj
③当1<=i,j<=m,且i不等于j时,di和dj的最大公约数为1
(4)算法时间性能:时间开销与每一趟分组过程相关,准确的时间复杂度到目前为止尚无定论