排序算法综述

1.排序算法综述

排序(sort)或分类                                       
    所谓排序,就是要整理文件中的记录,使之按关键字递增(或递减)次序排列起来。其确切定义如下:
    输入:n个记录R1,R2,…,Rn,其相应的关键字分别为K1,K2,…,Kn
  输出:Ril,Ri2,…,Rin,使得Ki1≤Ki2≤…≤Kin。(或Ki1≥Ki2≥…≥Kin)。
1.被排序对象--文件
  被排序的对象--文件由一组记录组成。
  记录则由若干个数据项(或域)组成。其中有一项可用来标识一个记录,称为关键字项。该数据项的值称为关键字(Key)。
  注意:  在不易产生混淆时,将关键字项简称为关键字。
2.排序运算的依据--关键字
     用来作排序运算依据的关键字,可以是数字类型,也可以是字符类型。
     关键字的选取应根据问题的要求而定。
【例】在高考成绩统计中将每个考生作为一个记录。每条记录包含准考证号、姓名、各科的分数和总分数等项内容。若要惟一地标识一个考生的记录,则必须用"准考证号"作为关键字。若要按照考生的总分数排名次,则需用"总分数"作为关键字。
排序的稳定性
     当待排序记录的关键字均不相同时,排序结果是惟一的,否则排序结果不唯一。
     在待排序的文件中,若存在多个关键字相同的记录,经过排序后这些具有相同关键字的记录之间的相对次序保持不变,该排序方法是稳定的;若具有相同关键字的记录之间的相对次序发生变化,则称这种排序方法是不稳定的
  注意:排序算法的稳定性是针对所有输入实例而言的。即在所有可能的输入实例中,只要有一个实例使得算法不满足稳定性要求,则该排序算法就是不稳定的。
排序方法的分类
1.按是否涉及数据的内、外存交换分

     在排序过程中,若整个文件都是放在内存中处理,排序时不涉及数据的内、外存交换,则称之为内部排序(简称内排序);反之,若排序过程中要进行数据的内、外存交换,则称之为外部排序
  注意:① 内排序适用于记录个数不很多的小文件
         ②外排序则适用于记录个数太多,不能一次将其全部记录放人内存的大文件。

2.按策略划分内部排序方法
     可以分为五类:交换排序、选择排序、插入排序、归并排序和分配排序。  

排序算法分析
1.排序算法的基本操作
     大多数排序算法都有两个基本的操作:
  (1) 比较两个关键字的大小;
  (2) 改变指向记录的指针或移动记录本身。
  注意: 第(2)种基本操作的实现依赖于待排序记录的存储方式。
2.待排文件的常用存储方式
1以顺序表(或直接用向量)作为存储结构
    排序过程:对记录本身进行物理重排(即通过关键字之间的比较判定,将记录移到合适的位置)
2以链表作为存储结构
  排序过程:无须移动记录,仅需修改指针。通常将这类排序称为链表(或链式)排序;
3用顺序的方式存储待排序的记录,但同时建立一个辅助表(如包括关键字和指向记录位置的指针组成的索引表)
  排序过程:只需对辅助表的表目进行物理重排(即只移动辅助表的表目,而不移动记录本身)。适用于难于在链表上实现,仍需避免排序过程中移动记录的排序方法。
3.排序算法性能评价
1评价排序算法好坏的标准
  评价排序算法好坏的标准主要有两条:
     ① 执行时间和所需的辅助空间
     ② 算法本身的复杂程度
2排序算法的空间复杂度
  若排序算法所需的辅助空间并不依赖于问题的规模n,即辅助空间是O(1),则称之为就地排序(In-PlaceSou)。
  非就地排序一般要求的辅助空间为O(n)。
3排序算法的时间开销
  大多数排序算法的时间开销主要是关键字之间的比较和记录的移动。有的排序算法其执行时间不仅依赖于问题的规模,还取决于输入实例中数据的状态。
文件的顺序存储结构表示
  #define n l00 //假设的文件长度,即待排序的记录数目

typedefint KeyType; //假设的关键字类型
  typedef struct{ //记录类型
    KeyType key;//关键字项
    InfoType otherinfo;//其它数据项,类型InfoType依赖于具体应用而定义
   }RecType;
  typedef RecType SeqList[n+1];//SeqList为顺序表类型,表中第0个单元一般用作哨兵
  注意:若关键字类型没有比较算符,则可事先定义宏或函数来表示比较运算。
【例】关键字为字符串时,可定义宏"#define LT(a,b)(Stromp((a),(b))<0)"。那么算法中"a<b"可用"LT(a,b)"取代。若使用C++,则定义重载的算符"<"更为方便。 

各种内部排序方法的比较和选择

按平均时间将排序分为四类:
1)平方阶(O(n2))排序
     一般称为简单排序,例如直接插入、直接选择和冒泡排序;
2)线性对数阶(O(nlgn))排序
     如快速、堆和归并排序;
3O(n1+)阶排序
     £是介于0和1之间的常数,即0<£<1,如希尔排序;
4)线性阶(O(n))排序
     如桶、箱和基数排序。
各种排序方法比较
     简单排序中直接插入最好,快速排序最快,当文件为正序时,直接插入和冒泡均最佳。
影响排序效果的因素
     因为不同的排序方法适应不同的应用环境和要求,所以选择合适的排序方法应综合考虑下列因素:
  ①待排序的记录数目n;
  ②记录的大小(规模);
  ③关键字的结构及其初始状态;
  ④对稳定性的要求;
  ⑤语言工具的条件;
  ⑥存储结构;
  ⑦时间和辅助空间复杂度等。

不同条件下,排序方法的选择
(1)若n较小(如n≤50),可采用直接插入或直接选择排序。
     当记录规模较小时,直接插入排序较好;否则因为直接选择移动的记录数少于直接插人,应选直接选择排序为宜。
(2)若文件初始状态基本有序(指正序),则应选用直接插人、冒泡或随机的快速排序为宜;
(3)若n较大,则应采用时间复杂度为O(nlgn)的排序方法:快速排序、堆排序或归并排序。
     快速排序是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;
     堆排序所需的辅助空间少于快速排序,并且不会出现快速排序可能出现的最坏情况。这两种排序都是不稳定的。
     若要求排序稳定,则可选用归并排序。但本章介绍的从单个记录起进行两两归并的  排序算法并不值得提倡,通常可以将它和直接插入排序结合在一起使用。先利用直接插入排序求得较长的有序子文件,然后再两两归并之。因为直接插入排序是稳定的,所以改进后的归并排序仍是稳定的。

(4)在基于比较的排序方法中,每次比较两个关键字的大小之后,仅仅出现两种可能的转移,因此可以用一棵二叉树来描述比较判定过程。
     当文件的n个关键字随机分布时,任何借助于"比较"的排序算法,至少需要O(nlgn)的时间。
     箱排序和基数排序只需一步就会引起m种可能的转移,即把一个记录装入m个箱子之一,因此在一般情况下,箱排序和基数排序可能在O(n)时间内完成对n个记录的排序。但是,箱排序和基数排序只适用于像字符串和整数这类有明显结构特征的关键字,而当关键字的取值范围属于某个无穷集合(例如实数型关键字)时,无法使用箱排序和基数排序,这时只有借助于"比较"的方法来排序。
     若n很大,记录的关键字位数较少且可以分解时,采用基数排序较好。虽然桶排序对关键字的结构无要求,但它也只有在关键字是随机分布时才能使平均时间达到线性阶,否则为平方阶。同时要注意,箱、桶、基数这三种分配排序均假定了关键字若为数字时,则其值均是非负的,否则将其映射到箱(桶)号时,又要增加相应的时间。
(5)有的语言(如Fortran,Cobol或Basic等)没有提供指针及递归,导致实现归并、快速(它们用递归实现较简单)和基数(使用了指针)等排序算法变得复杂。此时可考虑用其它排序。
(6)本章给出的排序算法,输人数据均是存储在一个向量中。当记录的规模较大时,为避免耗费大量的时间去移动记录,可以用链表作为存储结构。譬如插入排序、归并排序、基数排序都易于在链表上实现,使之减少记录的移动次数。但有的排序方法,如快速排序和堆排序,在链表上却难于实现,在这种情况下,可以提取关键字建立索引表,然后对索引表进行排序。然而更为简单的方法是:引人一个整型向量t作为辅助表,排序前令t[i]=i(0≤i<n),若排序算法中要求交换R[i]和R[j],则只需交换t[i]和t[j]即可;排序

结束后,向量t就指示了记录之间的顺序关系:
       R[t[0]].key≤R[t[1]].key≤…≤R[t[n-1]].key
  若要求最终结果是:
       R[0].key≤R[1].key≤…≤R[n-1].key
则可以在排序结束后,再按辅助表所规定的次序重排各记录,完成这种重排的时间是O(n)。

2.交换排序

交换排序的基本思想是:两两比较待排序记录的关键字,发现两个记录的次序相反时即进行交换,直到没有反序的记录为止。
     应用交换排序基本思想的主要排序方法有:冒泡排序和快速排序。

2.1冒泡排序
1、排序方法
     将被排序的记录数组R[1..n]垂直排列,每个记录R[i]看作是重量为R[i].key的气泡。根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R:凡扫描到违反本原则的轻气泡,就使其向上"飘浮"。如此反复进行,直到最后任何两个气泡都是轻者在上,重者在下为止。
1)初始
     R[1..n]为无序区。
2)第一趟扫描
     从无序区底部向上依次比较相邻的两个气泡的重量,若发现轻者在下、重者在上,则交换二者的位置。即依次比较(R[n],R[n-1]),(R[n-1],R[n-2]),…,(R[2],R[1]);对于每对气泡(R[j+1],R[j]),若R[j+1].key<R[j].key,则交换R[j+1]和R[j]的内容。
     第一趟扫描完毕时,"最轻"的气泡就飘浮到该区间的顶部,即关键字最小的记录被放在最高位置R[1]上。
3)第二趟扫描
     扫描R[2..n]。扫描完毕时,"次轻"的气泡飘浮到R[2]的位置上……
     最后,经过n-1 趟扫描可得到有序区R[1..n]
  注意:  第i趟扫描时,R[1..i-1]和R[i..n]分别为当前的有序区和无序区。扫描仍是从无序区底部向上直至该区顶部。扫描完毕时,该区中最轻气泡飘浮到顶部位置R[i]上,结果是R[1..i]变为新的有序区。
2、冒泡排序过程示例
     对关键字序列为4938 65 97 76 13 27 49的文件进行冒泡排序的过程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值