第7章 排序
7.1排序的基本概念
(1)排序:就是重新排列表中的元素,使表中的元素满足按关键字递增或递减的过程
(2)算法稳定性:若待排序表中有两个元素R1和R2,其对应的关键字key1=key2,且在排序前R1在R2的前面,若使用某一排序算法排序后,R1仍然在R2的前面,则称这个排序算法是稳定,否则称排序算法是不稳定。
7.2插入排序
插入排序的基本思想:每次将一个待排序的记录按其关键字大小插入到前面已排好序的子序列中,直到全部记录插入完成
7.2.1直接插入排序
(1)直接插入排序的基本思想:
要将元素L(i)插入到已有序的子序列L[1…i-1],需要执行以下操作:
1)查找出L(i)在L[1…i-1]中的插入位置k。
2)将L[k…i-1]中所有元素全部后移一个位置
3)将L(i)复制到L(k)
为了实现对L[1…n]的排序,将L(2)~L(n)依次插入到前面已排好序的子序列中,初始假定L[1]是一个已经排好序的子序列。上述操作执行n-1次得到一个有序的表。
(2)直接插入排序的分析
空间复杂度:O(1)
时间复杂度:最好情况O(n)、平均情况O( )、最坏情况O( )
稳定性:稳定
适用性:线性表为顺序存储、链式存储
(3)例题:给出关键字序列{4,5,1,2,6,3}的直接插入排序过程
初始序列:4,5,1,2,6,3
第一趟:4,5,1,2,6,3(将5插入{4})
第二趟:1,4,5,2,6,3(将1插入{4,5})
第三趟:1,2,4,5,6,3(将2插入{1,4,5})
第四趟:1,2,4,5,6,3(将6插入{1,2,4,5})
第五趟:1,2,3,4,5,6(将3插入{1,2,4,5,6})
【分析】直接插入排序每趟排序后不能确定一个元素的最终位置,只有最后一趟结束后才能得到元素的最终位置。
(4)代码:
#include
using namespace std;
#define ElemType int
int main()
{
int i;
void InsertSort(ElemType A[],int n); //直接插入排序函数
ElemType A[10]={1,3,5,7,9,2,4,6,8,0};
InsertSort(A,10); //直接插入排序
for(i=1;i<=10;i++) //输出数组元素
cout<
7.2.2 折半插入排序
(1)折半插入排序的基本思想:
比较和移动操作分离,先折半查找出元素的待插入位置,然后统一地移动带插入的位置之后的所有元素,将带插入元素插入。
(2)折半插入排序的分析
空间复杂度:O(1)
时间复杂度:最好情况O( )、平均情况O( )、最坏情况O( )
稳定性:稳定
适用性:线性表为顺序存储
比较次数:O(nlog2n) ,比较次数与待排序表的初始状态无关,仅取决于表中的元素个数n;而元素的移动次数并没有改变,它依赖于待排序表的初始状态
(3)代码:
//折半插入排序
void InsertSort(ElemType A[],int n){
int i,j,low,high,mid;
for(i=2;i<=n;i++){ //依次将A[2]~A[n]插入前面已排序序列
A[0]=A[i]; //将A[i]暂存到A[0]
low=1;high=i-1; //设置折半查找的范围
while(low<=high){ //折半查找(默认递增有序)
mid=(low+high)/2; //取中间点
if(A[mid]>A[0]) high=mid-1; //查找左半子表
else low=mid+1; //查找右半子表
}
for(j=i-1;j>=high+1;--j)
A[j+1]=A[j]; //统一后移元素,空出插入位置
A[high+1]=A[0]; //插入操作
}
}
7.2.3 希尔(Shell)排序(缩小增量排序)
(1)希尔排序的基本思想:
先将待排序表分割成若干形如L[i,i+d,i+2d,…,i+kd]的子表,分别进行直接插入排序,当整个表中的元素已呈“基本有序”时,再对全体记录进行一次直接插入排序。
(2)希尔插入排序的分析
空间复杂度:O(1)
时间复杂度: 约O(n1.3 )
稳定性:不稳定
适用性:线性表为顺序存储
(3)例题:给出关键字序列{50,26,38,80,70,90,8,30,40,20}的希尔排序过程(取增量序列为d={5,3,1},排序结果为从小到大排列)
初始序列:50,26,38,80,70,90,8,30,40,20
第一趟(增量5):50,8,30,40,20,90,26,38,80,70
第二趟(增量3):26,8,30,40,20,80,50,38,90,70
第三趟(增量1):8,20,26,30,38,40,50,70,80,90
(4)代码:
//希尔排序
void ShellSort(ElemType A[],int n){
int dk,i,j;
for(dk=n/2;dk>=1;dk=dk/2) //步长变化
for(i=dk+1;i<=n;++i)
if(A[i]0&&A[0]