排序总结

合集下载
相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

内排序总结

排序的基本概念:

1.稳定的:如果待排序的表中,存在多个关键字相同的记录,经过

排序后这些具有相同关键字的记录之间的相对次序保持不变,则称这种排序方法是稳定的,反之,是不稳定的。

2.排序的分类:插入排序、选择排序、交换排序、归并排序和基数

排序。

一.插入排序(直接插入排序、希尔排序)

思想:每次将一个待排序的记录,按其关键字的大小插入到前

面已经排好序的字表中的适当位置,直到全部记录插入完为止。

1.直接插入排序(稳定的,复杂度O(n^2))

代码:

void InsertSort(TypeR[],int n){

//先假设第一个元素已经有序,从第二个开始依次和前面的元素比较,比前面的小则前移

inti,j;

Type temp;

for ( i = 1; i < n; i++)

{ temp=R[i];

j=i-1;//从右向左在有序表中找到R[i]的插入位置

while(j>=0 &&temp.key

{ R[j+1]=R[j];//将关键字大于R[i].key的记录后移

j--;

}

R[j+1]=temp;//在R[j+1]处插入R[i]

}

}

分析:初始表正序时,比较次数最小为n-1,总移动次数为2;初始表反序时,比较次数最大为n(n-1)/2,移动次数最大为(n-1)(n+4)/2.算法

的平均时间复杂度为Q(n^2),辅助空间复杂度为Q(1),是就地排序,是一种稳定的排序方法。

2.希尔排序

思想:实际上是一种分组插入方法。先取定一个小于n的整数d1作为第一个增量,把表的全部记录分成d1个组,所有距离为d1的倍数的记录放在同一组中,在各组内进行直接插入排序;然后,取第二个增量d2(

代码:

void ShellSort(Type R[],int n)

{ int i,j,gap;

Type temp;

gap=n/2;//增量置初值

while(gap>0)

{ for(i=gap;i

{

temp=R[i];

j=i-gap;

while(j>=0 &&temp.key

{

R[j+gap]=R[j];

j=j-gap;

}

R[j+gap]=temp;

j=j-gap;

}

gap=gap/2;//减小增量

}

}

分析:该算法的时间复杂度为O(nlog2 n),辅助空间复杂度为O(1),是一个就地排序,也是一种不稳定排序。

二.选择排序(直接选择排序和堆排序)

思想:每一趟从待排序的记录中选择关键字最小的记录,顺序放在一排好序的子表的最后,直到全部记录排序完毕。(适合于从大量的记录中选择一部分排序记录)

1.直接选择排序

思想:第i趟排序开始时,当前有序区和无序区分别为R[0…i-1]和R[i..n-1],该趟排序则是从当前无序区中选出关键字最小的记录R[k],将它与无序区的第一个记录R[i]互换,使R[0…i]和R[i+1…n-1]分别变为新的有序区和新的无序区。

代码:

void SelectSort(Type R[],int n)

{

int i,j,k;

Type temp;

for(i=0;i

{

k=i;

for(j=i+1;j

if(R[j].key

k=j;//k记下目前找到的最小关键字所在的位置

if(k!=i)//交换R[i]和R[k]

{

temp=R[i];

R[i]=R[k];

R[k]=temp;

}

}

}

分析:无论表的初始状态为何,总的比较次数为n(n-1)/2,当初始表为正序时,移动次数为0,当初始表为反序时移动次数为3(n-1)。空间复杂度为O(1),为就地排序,是不稳定排序方法。

3.堆排序

简介:堆的定义:n个关键字序列k1…kn当且仅当满足以下条件时成为堆(1<=i<=n/2)(1)ki<=k2i且ki<=k2i+1(小根堆) 或(2)ki>=k2i 且ki>=k2i+1(大根堆)。

思想:堆排序是一种树形排序,在排序过程中,将R[1…n]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系,在当前无序区中选择关键字最大(或最小)的记录。

具体做法:把待排序的表的关键字存放在数组R[1..n](为了与二叉树的顺序存储结构一致,堆排序的数据序列的下标从1开始)中,将R 看做一棵二叉树,每个结点表示一个记录,原表的第一个记录R[1]作为二叉树的根,以下各记录依次逐层从左到右顺序排列,构成一棵完全二叉树,结点R[i]的左孩子是R[2i],右孩子是R[2i+1],双亲是R[i/2]。

采用筛选算法构建堆:假若完全二叉树的某一个结点i对于它的左子树、右子树已是堆,接下来需要将R[2i].key与R[2i+1].key之中的最大者与R[i].key比较,若R[i].key较小则交换,这有可能破坏下一级的堆。于是继续采用上述方法构造下一级的堆。直到完全二叉树中结点i构成堆为止。对于任意一棵完全二叉树,从i=n/2---1,反复利用上述思想建堆。大者“上浮”,小者被“筛选”下去。

代码:(调整堆)

void sift(Type R[],int low,int high)

{

相关文档
最新文档