数据结构第十章内部排序-插入排序
数据结构-内排序
Shell排序的性能分析
Shell排序的时间复杂度在O(nlog2n)和O(n2)间, Knuth的 统计结论是,平均比较次数和记录平均移动次数在n1.25与 1.6n1.25之间
Shell排序是一种不稳定的排序方法
最后谈一下delta的取法。 Shell最初的方案是delta=n/2, delta=delta/2,直到delta=1。Knuth的方案是delta=delta/3 +1。其它方案有:都取奇数为好;或delta互质为好等等。 而使用象1, 2, 4, 8, …或1, 3, 6, 9, …这样的增量序列就不太 合适,因为这样会使几个元素多次被分到一组中,从而造 成重复排序,产生大量无用的比较操作
另外,在无序子表中向前移动的过程中,如果没 有交换元素,则说明无序子表已有序,无须再做 排序
24
冒泡排序算法实现
1 void bubble_sort(RecType R[ ], int n) { 2 //待排序元素用一个数组R表示,数组有n个记录
3 int i, j; 4 bool swap=TRUE; //判断无序子表是否已有序的变量
内排序和外排序 按照排序过程中使用内、外存的不 同将排序方法分为内排序和外排序。若待排序记录全 部在内存中,称为内排序;若待排序记录的数量很大, 以致内存一次不能容纳全部记录,在排序过程中需要 进行内、外存交换,称为外排序。本章仅讨论内排序
内排序可分为五大类:插入排序、交换排序、选择排 序、归并排序和基数排序
直接插入排序(straight insert sort) 折半插入排序(binary insert sort) Shell排序(Shell sort)
10
10.2.1 直接插入排序举例
严蔚敏 数据结构第十章 内部排序的具体代码(c++,附测试数据)
int exchange = 1;
SortData temp;
while ( i < n && exchange ){
exchange = 0; //标志置为0,假定未交换
for ( int j = n-1; j >= i; j-- )
QSort(L,1,L.length);
}//QuickSort
//**************************************************
//直接选择排序
void SelectSort ( SortData V[ ], int n ) {
for ( int i = 0; i < n-1; i++ ) {
if LT(L.r[i].key,L.r[i-1].key){
L.r[0]=L.r[i];
for ( j = i-1; LT(L.r[0].key,L.r[j].key); --j )
L.r[j+1]=L.r[j];
L.r[j+1]=L.r[0];
//*******************************************
//直接插入排序
void InsertSort ( SqList &L ) {
//按非递减顺序对表进行排序,从后向前顺序比较
int i,j;
for ( i = 2; i <= L.length; ++ i)
low=1;high=i-1; //查找范围由1到i-1
while(low<=high){
数据结构-第十章-内部排序
0
1
2
3
4
5
6
7
8
i=5
MAXINT 49 2 3
MAXINT 49 6 3 MAXINT 49 6 3 MAXINT 49 6 8
38 1
38 1 38 1 38 1
65 97 5 0
65 5 65 5 65 5 97 0 97 0 97 0
76 4
76 4 76 4 76 4
13
27
49
i=6
最坏情况下,待排记录按关键字非递增有序 排列(逆序)时,第 i 趟时第 i+1 个对象 必须与前面 i 个对象都做排序码比较, 并且 每做1次比较就要做1次数据移动。总比较 次 数 为 (n+2)(n-1)/2 次 , 总 移 动 次 数 为 (n+4)(n-1)/2。 在平均情况下的排序码比较次数和对象移 动次数约为 n2/4。因此,直接插入排序的 时间复杂度为 O(n2)。 直接插入排序是一种稳定的排序方法。
折半插入排序 (Binary Insertsort)
基本思想 既然每个要插入记录之前的纪录 已经按关键字有序排列,在查找插入位 臵时就没有必要逐个关键字比较,可以 使用折半查找来实现。由此进行的插入 排序称之为折半插入排序。
折半插入排序的算法
void BInsertSort (SqList &L){ for (i=2;i<=L.length;++i){ L.r[0]=L.r[i]; low=1;high=i-1; //查找范围由1到i-1 while(low<=high){ m=(low+high)/2; if LT(L.r[0].key,L.r[m].key) high=m-1; else low=m+1; }//while 折半查找 for (j=i-1;j>=high+1;--j) L.r[j+1]=L.r[j]; //折半查找结束后high+1位臵即为插入位臵 L.r[high+1]=L.r[0]; }//for }//BInsertSort
源代码--数据结构与算法(Python版)chap10 排序
交换类
(2)快速排序 快速排序采用分而治之(Divide and Conquer)
的策略将问题分解成若干个较小的子问题,采用 相同的方法一一解决后,再将子问题的结果整合 成最终答案。快速排序的每一轮处理其实就是将 这一的基准数定位,直到所有的数都排序完成 为止。
21
快速排序的基本步骤:
1. 选定一个基准值(通常可选第一个元素); 2. 将比基准值小的数值移到基准值左边,形
14
• 交换类
交换类排序的基本思想是:通过交换无序序列 中的记录得到其中关键字最小或最大的记录,并将 其加入到有序子序列中,最终形成有序序列。交换 类排序可分为冒泡排序和快速排序等。
15
交换类
(1)冒泡排序 两两比较待排序记录的关键字,发现两
个记录的次序相反时即进行交换,直到没有 反序的记录为止。因为元素会经由交换慢慢 浮到序列顶端,故称之为冒泡排序。
3. 最后对这个组进行插入排序。步长的选法 一般为 d1 约为 n/2,d2 为 d1 /2, d3 为 d2/2 ,…, di = 1。
11
【例】给定序列(11,9,84,32,92,26,58,91,35, 27,46,28,75,29,37,12 ),步长设为d1 =5、d2 =3、 d3 =1,希尔排序过程如下:
for i in range(1,len(alist)):
#外循环n-1
for j in range(i,0,-1):
#内循环
if alist[j]<alist[j-1]:
alist[j],alist[j-1]=alist[j-1],alist[j] #交换
li=[59,12,77,64,72,69,46,89,31,9] print('before: ',li) insert_sort(li) print('after: ',li)
数据结构答案 第10章 排序学习与指导
第10章排序10.1 知识点分析1.排序基本概念:(1)排序将数据元素的任意序列,重新排列成一个按关键字有序(递增或递减)的序列的过程称为排序。
(2)排序方法的稳定和不稳定若对任意的数据元素序列,使用某个排序方法,对它按关键字进行排序,若对原先具有相同键值元素间的位置关系,排序前与排序后保持一致,称此排序方法是稳定的;反之,则称为不稳定的。
(3)内排序整个排序过程都在内存进行的排序称为内排序,本书仅讨论内排序。
(4)外排序待排序的数据元素量大,以致内存一次不能容纳全部记录,在排序过程中需要对外存进行访问的排序称为外排序。
2.直接插入排序直接插入排序法是将一个记录插到已排序好的有序表中,从而得到一个新的,记录数增1的有序表。
3.二分插入排序二分插入排序法是用二分查找法在有序表中找到正确的插入位置,然后移动记录,空出插入位置,再进行插入的排序方法。
4.希尔排序希尔排序的基本思想是:先选取一个小于n的整数d1作为第一个增量,把待排序的数据分成d1个组,所有距离为d1的倍数的记录放在同一个组内,在各组内进行直接插入排序,每一趟排序会使数据更接近于有序。
然后,取第二个增量d2,d2< d1,重复进行上述分组和排序,直至所取的增量d i=1(其中d i< d i-1 < ……< d2< d1),即所有记录在同一组进行直接插入排序后为止。
5.冒泡排序冒泡法是指每相邻两个记录关键字比大小,大的记录往下沉(也可以小的往上浮)。
每一遍把最后一个下沉的位置记下,下一遍只需检查比较到此为止;到所有记录都不发生下沉时,整个过程结束。
6.快速排序快速排序法是通过一趟排序,将待排序的记录组分割成独立的两部分,其中前一部分记录的关键字均比枢轴记录的关键字小;后一部分记录的关键字均比枢轴记录的关键字大,枢轴记录得到了它在整个序列中的最终位置并被存放好。
第二趟再分别对分割成两部分子序列,再进行快速排序,这两部分子序列中的枢轴记录也得到了最终在序列中的位置而被存放好,并且它们又分别分割出独立的两个子序列……。
第十章_排序方法(数据结构ppt-严蔚敏)
第二个问题解决方法——筛选
方法:输出堆顶元素之后,以堆中最后一个元素替代之;然 后将根结点值与左、右子树的根结点值进行比较,并与其中 小者进行交换;重复上述操作,直至叶子结点,将得到新的 堆,称这个从堆顶至叶子的调整过程为“筛选”
例 38 50 97 76
13 27 65 49 13 38
97 27 38 50 76
2 (n 4)(n 1) 记录移动次数: (i 1) 2 i 2
i 2 n
若待排序记录是随机的,取平均值 n2 关键字比较次数: T(n)=O(n² ) 4 记录移动次数:
空间复杂度:S(n)=O(1)
n2 4
折半插入排序
排序过程:用折半查找方法确定插入位置的排序叫~
初始时令i=s,j=t 首先从j所指位置向前搜索第一个关键字小于x的记录,并和rp 交换 再从i所指位置起向后搜索,找到第一个关键字大于x的记录, 和rp交换 重复上述两步,直至i==j为止 再分别对两个子序列进行快速排序,直到每个子序列只含有 一个记录为止
x 例 初始关键字: 27 49 i 完成一趟排序: ( 27 38 13 49 65 i 13) 49 97 76 j 97 49 13 j 97 65 49 27 50 j 50)
13 38
76 65 27 49
堆排序:将无序序列建成一个堆,得到关键字最小 (或最大)的记录;输出堆顶的最小(大)值后,使 剩余的n-1个元素重又建成一个堆,则可得到n个元素 的次小值;重复执行,得到一个有序序列,这个过程 叫~ 堆排序需解决的两个问题:
如何由一个无序序列建成一个堆? 如何在输出堆顶元素之后,调整剩余元素,使之成为一个新 的堆?
按排序所需工作量
北航数据结构课件 (10)
( 1,4,6 , 12 8,8 12 , 6,11,… )
例
49
temp
temp>K[j] j=0 38 97 76 65 13 27 50
… (若干趟后)
K[j+1]=K[ j ]; j=j−1;
65
38
49
76 65
76 97
65 97
13
27
50
K[j+1]=temp;
38
49
65
76
97
核心思想
首先确定一个元素的间隔数gap。 将参加排序的元素按照gap分隔成若干个子序列 ( 即分别把那些位置相隔为gap的元素看作一个子序 列),然后对各个子序列采用 某一种排序方法 进行排 序;此后减小gap值,重复上述过程,直到gap<1。
一种减小gap的方法:
gap1 = n/2 gapi = gapi-1/2
1.时间性能 —— 排序过程中元素之间的比较次数与元素的
移动次数。 本章讨论各种排序方法的时间复杂度 时主要按照最差情况下所需要的比较次数 来进行。
2.空间性能 —— 除了存放参加排序的元素之外,排序过程
中所需要的其他辅助空间。
3.排序稳定性 —— 对于值相同的两个元素,排序前后的先后
次序不变,则称该方法为稳定性排序方法, 否则,称为非稳定性排序方法。
算 法
泡排序法的排序趟数与原始序列中数 据元素的排列有关,因此,排序的趟数为 一个范围,即[1..n-1]。
什么情况下至少排序一趟 什么情况下要排序n-1趟
O(n
2)
结论
泡排序方法比较适合于 参加排序的序列的原始状态 基本有序的情况
泡排序法是 稳定性排序方法。
严蔚敏《数据结构》复习笔记及习题 (内部排序)【圣才出品】
第10章内部排序10.1 复习笔记一、概述1.排序的相关概念(1)排序:重新排列表中元素,使其按照关键字递增或递减排列的过程。
(2)内部排序:待排序记录存放在计算机的随机存储器中进行排序的过程。
(3)外部排序:待排序记录数据量大,内存不能一次性容纳全部记录,排序时需对外存进行访问的过程。
2.排序算法的评价(1)时间复杂度(2)空间复杂度(3)稳定性在设计排序算法时,除了考虑算法的时间和空间复杂度外,还需考虑算法的稳定性,稳定性定义如下:待排序列中两个元素R i,R j对应的关键字K i=K j,且排序前R i在R j前面,若选择某一种算法对该序列排序后,R i仍在R j前面,则称该排序算法是稳定的,否则是不稳定的。
二、插入排序1.直接插入排序(1)算法分析将待排序记录分为有序子序列和无序子序列两部分,每次将无序序列中的元素插入到有序序列中的正确位置上。
即:先将序列中的第1个记录看成是一个有序的子序列,然后从第2个记录起逐个进行插入,直至整个序列变成按关键字非递减的有序序列为止,整个排序过程进行n-1趟插入。
其算法实现如下:(2)算法评价①时间复杂度:平均情况下,考虑待排序列是随机的,其时间复杂度为O(n2)。
②空间复杂度:仅使用常数个辅助单元,空间复杂度为O(1)。
③稳定性:每次插入元素都是从后向前先比较再插入,不存在相同元素位置交换,所以算法是稳定的。
2.折半插入排序(1)算法分析当排序表顺序存储时,可以先折半查找出待插位置,再对该位置后的元素统一后移,并完成插入操作。
其算法实现如下:(2)算法评价①时间复杂度:折半插入排序只是减少了元素比较次数,其他的均与直接插入排序相同,因此时间复杂度仍为O(n2)。
②空间复杂度:与直接插入排序相同,为O(1)。
③稳定性:与直接插入排序相同,是稳定的算法。
3.希尔排序(1)算法分析先将整个待排记录序列分割成为若干子序列(形如L[i,i+d,i+2d,…,i+kd]),分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。
数据结构考研试题精选及答案第10章排序
第10章 排序排序排序一、选择题 1.某内排序方法的稳定性是指.某内排序方法的稳定性是指( )( )( )。
【南京理工大学【南京理工大学 1997 1997 1997 一、一、一、101010((2分)】 A .该排序算法不允许有相同的关键字记录该排序算法不允许有相同的关键字记录 B B B..该排序算法允许有相同的关键字记录记录C .平均时间为0(n log n n log n)的排序方法)的排序方法)的排序方法D D D.以上都不对.以上都不对.以上都不对2.下面给出的四种排序法中下面给出的四种排序法中( )( )( )排序法是不稳定性排序法。
排序法是不稳定性排序法。
【北京航空航天大学北京航空航天大学 1999 1999 1999 一、一、10 10 ((2分)】 A. A. 插入插入插入 B. B. B. 冒泡冒泡冒泡 C. C. C. 二路归并二路归并二路归并 D. D. D. 堆积堆积堆积 3.下列排序算法中,其中(.下列排序算法中,其中( )是稳定的。
)是稳定的。
)是稳定的。
【福州大学【福州大学 1998 1998 1998 一、一、一、3 (23 (2分)】A. A. 堆排序,冒泡排序堆排序,冒泡排序堆排序,冒泡排序B. B. B. 快速排序,堆排序快速排序,堆排序快速排序,堆排序C. C. 直接选择排序,归并排序直接选择排序,归并排序直接选择排序,归并排序D. D. D. 归并排序,冒泡排序归并排序,冒泡排序归并排序,冒泡排序4.稳定的排序方法是(.稳定的排序方法是( )) 【北方交通大学【北方交通大学【北方交通大学 2000 2000 2000 二、二、二、33(2分)】 A .直接插入排序和快速排序.直接插入排序和快速排序 B B B.折半插入排序和起泡排序.折半插入排序和起泡排序.折半插入排序和起泡排序C .简单选择排序和四路归并排序.简单选择排序和四路归并排序D D D.树形选择排序和.树形选择排序和shell 排序排序5.下列排序方法中,哪一个是稳定的排序方法?(.下列排序方法中,哪一个是稳定的排序方法?( ) 【北方交通大学【北方交通大学【北方交通大学 2001 2001 2001 一、一、一、88(2分)】A .直接选择排序.直接选择排序B B B.二分法插入排序.二分法插入排序.二分法插入排序C C C.希尔排序.希尔排序.希尔排序D D D.快速排序.快速排序.快速排序6.若要求尽可能快地对序列进行稳定的排序,则应选(.若要求尽可能快地对序列进行稳定的排序,则应选(A A .快速排序.快速排序 B B B.归并排序.归并排序.归并排序 C C C.冒.冒泡排序)。
数据结构 排序
2019/9/7
30
10.4.1 简单选择排序
待排记录序列的状态为:
有序序列R[1..i-1] 无序序列 R[i..n]
有序序列中所有记录的关键字均小于无序序列中记 录的关键字,第i趟简单选择排序是从无序序列 R[i..n]的n-i+1记录中选出关键字最小的记录加入 有序序列
2019/9/7
5
排序的类型定义
#define MAXSIZE 20 // 待排序记录的个数
typedef int KeyType;
typedef struct
{ KeyType key;
InfoType otherinfo; ∥记录其它数据域
} RecType;
typedef struct {
RecType r[MAXSIZE+1];
分别进行快速排序:[17] 28 [33] 结束 结束
[51 62] 87 [96] 51 [62] 结束
结束
快速排序后的序列: 17 28 33 51 51 62 87 96
2019/9/7
26
自测题 4 快速排序示例
对下列一组关键字 (46,58,15,45,90,18,10,62) 试写出快速排序的每一趟的排序结果
final↑ ↑first
i=8
[51 51 62 87 96 17 28 33]
final↑ ↑first
2019/9/7
14
希尔(shell )排序
基本思想:从“减小n”和“基本有序”两 方面改进。
将待排序的记录划分成几组,从而减少参 与直接插入排序的数据量,当经过几次分 组排序后,记录的排列已经基本有序,这 个时候再对所有的记录实施直接插入排序。
数据结构(C语言版CHAP10
分组方法:选定一增量d,将间隔为d的记录作为一组 例 待排记录 49 38 65 97 76 13 27 49 55 04 d=5 d=3 49 13 13 13 04 38 27 27 04 13 65 49 49 49 27 97 55 55 38 38 76 04 04 27 49 13 27 49 49 38 65 49 38 65 49 55 65 49 55 65 55 97 97 97 76 04 76 76 76 97
10.1
概 述
排序也是数据处理中经常使用的一种操作.例 高考考生信息管理 系统提供了将考生按总分排序,按单科排序的功能; 1 排序定义 设R1 R2 R3 … Rn 是n个记录,k1,k2, k3 … kn为它们的关键字,排序 就是将记录按关键字递增(或递减)的次序排列起来. 2 分类 按记录的存放位置分类有 内排序:待排记录放在内存 外排序:待排记录放在外存 按排序原则分类(内排序) 插入排序 交换排7,76,13,27,49 是待排序列
稳性排序的应用: 例 股票交易系统 考虑一种股票交易(清华紫光)) 1)顾客输入:股东帐号,股票代码,申购价格,数量,股票交易系统 将用户申购请求插入申购队列队尾; 2)股票交易系统按如下原则交易: A)申购价高者先成交 B)申购价相同者按申购时间先后顺序成交 结束 第 5 页
76 38 49 65 97 76 13 27 49
L.r[5]复制为哨兵 0 1 2 3 4 5 6 7 8 9
76 38 49 65 97 97 13 27 49
L.r[0].key < L.r[4].key, L.r[4]记录后移 L.r[0].key≥ L.r[3].key 找到插入位置 插入! 0 1 2 3 4 5 6 7 8 9
数据结构使用C语言版朱战立丛书版本排序
{ span = d[m];
//取本次的增量值
for<k = 0; k < span; k++> //共span个小组
{
//组内是直接插入排序,区别是每次不是增1而是增
span
for<i = k; i < n-span; i = i+span>
{ temp = a[i+span];
j = i;
while<j > -1 && temp.key < a[j].key>
优点:实现简单
缺点:每趟只能确定一个元素,表长为n时需要n-1趟
算法如下:
void SelectSort<DataType a[], int n>
{
int i, j, small;
DataType temp;
for<i = 0; i < n-1; i++>
{ small = i;
//设第i个数据元素关键字
(a)初始最大堆 40
32
9
5
10
40 32 9 5 10 50 76 88 (d)交换顶点50后 9
5
76
50
40
5
10
9
32
76 50 40 5 10 9 32 88 (b)交换顶点88后 32
10
9
5
32 10 9 5 40 50 76 88 (e)交换顶点40后
5
9 5 10 32 40 50 76 88
{ a[j+span] = a[j];
j = j-span;
65
数据结构Ch10习题答案
第十章内部排序一、择题1.用直接插入排序法对下面四个表进行(由小到大)排序,比较次数最少的是(B)。
A.(94,32,40,90,80,46,21,69)插32,比2次插40,比2次插90,比2次插80,比3次插46,比4次插21,比7次插69,比4次B.(21,32,46,40,80,69,90,94)插32,比1次插46,比1次插40,比2次插80,比1次插69,比2次插90,比1次插94,比1次C.(32,40,21,46,69,94,90,80)插40,比1次插21,比3次插46,比1次插69,比1次插94,比1次插90,比2次插80,比3次D.(90,69,80,46,21,32,94,40)插69,比2次插80,比2次插46,比4次插21,比5次插32,比5次插94,比1次插40,比6次2.下列排序方法中,哪一个是稳定的排序方法(BD)。
A.希尔排序B.直接选择排序C.堆排序D.冒泡排序下列3题基于如下代码:for(i=2;i<=n;i++){ x=A[i];j=i-1;while(j>0&&A[j]>x){ A[j+1]=A[j];j--;}A[j+1]=x}3.这一段代码所描述的排序方法称作(A)。
A.插入排序B.冒泡排序C.选择排序D.快速排序4.这一段代码所描述的排序方法的平均执行时间为(D)A.O(log2n) B.O(n) C.O(nlog2n) D.O(n2)5.假设这段代码开始执行时,数组A中的元素已经按值的递增次序排好了序,则这段代码的执行时间为(B)。
A.O(log2n) B.O(n) C.O(nlog2n) D.O(n2)6.在快速排序过程中,每次被划分的表(或了表)分成左、右两个子表,考虑这两个子表,下列结论一定正确是(B)。
A.左、右两个子表都已各自排好序B.左边子表中的元素都不大于右边子表中的元素C.左边子表的长度小于右边子表的长度D.左、右两个子表中元素的平均值相等7.对n个记录进行堆排序,最坏情况下的执行时间为(C)。
数据结构第十、十一章:排序
14
9.2 交换排序
冒泡排序
排序过程
将第一个记录的关键字与第二个记录的关键字进行比较, 将第一个记录的关键字与第二个记录的关键字进行比较,若 为逆序r[1].key>r[2].key,则交换;然后比较第二个记录与 为逆序 ,则交换; 第三个记录;依次类推,直至第n-1个记录和第 个记录比较 个记录和第n个记录比较 第三个记录;依次类推,直至第 个记录和第 为止——第一趟冒泡排序,结果关键字最大的记录被安置在 第一趟冒泡排序, 为止 第一趟冒泡排序 最后一个记录上 对前n-1个记录进行第二趟冒泡排序,结果使关键字次大的 个记录进行第二趟冒泡排序, 对前 个记录进行第二趟冒泡排序 记录被安置在第n-1个记录位置 记录被安置在第 个记录位置 重复上述过程,直到“ 重复上述过程,直到“在一趟排序过程中没有进行过交换记 录的操作” 录的操作”为止
按待排序记录所在位置
内部排序: 内部排序:待排序记录存放在内存 外部排序: 外部排序:排序过程中需对外存进行访问的排序
稳定排序和不稳定排序 假设Ki=Kj(1≤i≤n,1≤j≤n,i≠j),且在排序前的序列中Ri领先 假设 ( , , ),且在排序前的序列中 领先 ),且在排序前的序列中 于Rj(即i<j)。若在排序后的排序中Ri仍领先于 ,即那些具 ( )。若在排序后的排序中 仍领先于Rj, )。若在排序后的排序中 仍领先于 有相同关键字的记录,经过排序后它们的相对次序仍然保持不变, 有相同关键字的记录,经过排序后它们的相对次序仍然保持不变, 则称这种排序方法是稳定的;反之,若Rj领先于 ,则称所用的 则称这种排序方法是稳定的;反之, 领先于Ri, 领先于 方法是不稳定的。 方法是不稳定的。 按排序依据原则
4
例
数据结构课程的内容
空间效率: O(1) 稳定性:稳定
23
折半插入排序算法
void BiInsertSort(SqList *L)
{ int i,j, low,high,m;
for(i=2;i<=L->length;i++)
{ L->r[0]=L->r[i]; low=1; high=i-1;
(KCN)和对象移动次数(RMN)分别为:
比较次数:n i = (n +2)(n -1)
i=2
2
移动次数:n(i +1)= (n +4)(n -1)
i=2
2
时间复杂度为O(n2)。
54 32 1 44 5 3 2 1 33 4 5 2 1 22 3 4 5 1 11 2 3 4 5
比较i次(依次与前面的i-1个记录进行比较,并和哨兵比较1次),移动i+1次(前面的i-1个记录依次向后移动,另外开始 19
13
*表示后一个25
例2:关键字序列T= (21,25,49,25*,16,08),
请写出直接插入排序的具体实现过程。 解:假设该序列已存入一维数组V[7]中,将V[0]作为缓冲或
暂存单元(Temp)。则程序执行过程为:
初态:
完成!
22410暂存59685*
021816
21516
2425951*
2459*
定义:
设有记录序列:{ R1、R2………Rn } 其相应的 关键字序列为: { K1、K2………Kn }; 若存在一种 确定的关系:Kx<=Ky<=…<= Kz则将记录序列 { R1、 R2……….Rn}排成按该关键字有序的序列: { Rx、 Ry……….Rz}的操作,称之为排序。
严蔚敏版《数据结构(C语言版)》-内部排序-第10章
high=mid-1 ; else low=mid+1 ;
}
/* 查找插入位置 */
for (j=i-1; j>=high+1; j--)
L->R[j+1]=L->R[j];
L->R[high+1]=L->R[0]; /* 插入到相
应位置 */
}
}
从时间上比较,折半插入排序仅仅减少了关键字的 比较次数,却没有减少记录的移动次数,故时间复杂度 仍然为O(n2) 。
待排序的记录类型的定义如下:
#define MAX_SIZE 100
Typedef int KeyType ;
typedef struct RecType
{ KeyType key ;
/* 关键字码 */
infoType otherinfo ; /* 其他域 */
}RecType ;
typedef struct Sqlist
③ 记录存储在一组连续地址的存储空间:构造另一 个辅助表来保存各个记录的存放地址(指针) :排序 过程不需要移动记录,而仅需修改辅助表中的指针, 排序后视具体情况决定是否调整记录的存储位置。
①比较适合记录数较少的情况;而②、③则适合 记录数较少的情况。
为讨论方便,假设待排序的记录是以①的情况存 储,且设排序是按升序排列的;关键字是一些可直接用 比较运算符进行比较的类型。
(n-1)(n+1)
2
移动次数:∑n (i+1)=
i=2
(n-1)(n+4)
2
一般地,认为待排序的记录可能出现的各种排列的
概率相同,则取以上两种情况的平均值,作为排序的关
数据结构第十章 排序
10.2 插入排序 插入排序
直接插入排序 折半插入排序 2-路插入排序 表插入排序 希尔排序
10.2.1 直接插入排序
基本操作:将一个记录插入到已排好序的有序表中, 从而得到一个新的、记录数增1的有序表。
例:有一组待排序的记录的关键字初始序列如下:
(49,38,65,97,76,13,27,49`)
(4)归并排序 (5)基数排序
按内排过程中所需的工作量分类:
(1)简单的排序方法,其时间复杂度为O(n×n)
(2)先进的排序方法,其时间复杂度为O(nlogn);
(3)基数排序,其时间复杂度为O(d(n+rd))
排序算法的两种基本操作:
(1)比较两个关键字的大小; (2)将记录从一个位置移至另一个位置;
算法实现的关键设计:
将d看成是一个循环数组,并设两个指针first和final分别指示排序过 程中得到的有序序列中的第一个记录和最后一个记录在d中的位置.
例:有一组待排序的记录的关键字初始排列如下:
(49,38,65,97,76,13,27,49`) 16
[初始关键字] 49 38 65 97 76 13 27 49`
18
10.2.3 希尔排序 从直接插入排序
待排序序列基本有序可提高效率 回顾 待排序序列的记录数n很小时可提高效率
希尔排序的基本思想:
先将整个待排记录序列分割成为若干子序列分别进行
直接插入排序,待整个序列中的记录“基本有序”时,再对 全
体记例录:有进一行组一待次排直序接的插记入录排的序关. 键字初始排列如下: (49,38,65,97,76,13,27,49`)
} 12
直接插入排序的性能分析: 10. 3
(1)空间:只需一个记录的辅助空间r[0].
常用的内部排序方法
常用的内部排序方法有:交换排序(冒泡排序、快速排序)、选择排序(简单选择排序、堆排序)、插入排序(直接插入排序、希尔排序)、归并排序、基数排序(一关键字、多关键字)。
一、冒泡排序:1.基本思想:两两比较待排序数据元素的大小,发现两个数据元素的次序相反时即进行交换,直到没有反序的数据元素为止。
2.排序过程:设想被排序的数组R[1..N]垂直竖立,将每个数据元素看作有重量的气泡,根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R,凡扫描到违反本原则的轻气泡,就使其向上"漂浮",如此反复进行,直至最后任何两个气泡都是轻者在上,重者在下为止。
【示例】:49 13 13 13 13 13 13 1338 49 27 27 27 27 27 2765 38 49 38 38 38 38 3897 65 38 49 49 49 49 4976 97 65 49 49 49 49 4913 76 97 65 65 65 65 6527 27 76 97 76 76 76 7649 49 49 76 97 97 97 97二、快速排序(Quick Sort)1.基本思想:在当前无序区R[1..H]中任取一个数据元素作为比较的"基准"(不妨记为X),用此基准将当前无序区划分为左右两个较小的无序区:R[1..I-1]和R[I+1..H],且左边的无序子区中数据元素均小于等于基准元素,右边的无序子区中数据元素均大于等于基准元素,而基准X 则位于最终排序的位置上,即R[1..I-1]≤X.Key≤R[I+1..H](1≤I≤H),当R[1..I-1]和R[I+1..H]均非空时,分别对它们进行上述的划分过程,直至所有无序子区中的数据元素均已排序为止。
2.排序过程:【示例】:初始关键字[49 38 65 97 76 13 27 49]第一次交换后[27 38 65 97 76 13 49 49]第二次交换后[27 38 49 97 76 13 65 49]J向左扫描,位置不变,第三次交换后[27 38 13 97 76 49 65 49]I向右扫描,位置不变,第四次交换后[27 38 13 49 76 97 65 49]J向左扫描[27 38 13 49 76 97 65 49](一次划分过程)初始关键字[49 38 65 97 76 13 27 49]一趟排序之后[27 38 13]49 [76 97 65 49]二趟排序之后[13]27 [38]49 [49 65]76 [97]三趟排序之后13 27 38 49 49 [65]76 97最后的排序结果13 27 38 49 49 65 76 97三、简单选择排序1.基本思想:每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
外部排序:文件中的记录太大,无法全部
将其同时调入内存进行的排序.
排序定义
设有记录序列:{ R1,R2 , … ,Rn }, 其相应的关键字 序列为:K1, K 2 ,, K n ;
若存在1,2, … ,n的一种排列
1
p1, p2 ,, pn , 使关键字
2 n
非递减(或非递增): K p K p K;p
插入排序
1.直接插入排序
基本思想:每一次将一个待排序的记录,按其关键字大小插入 到前面已经排好序的有序表中,从而得到一个新的、记录数增 1的有序表。
例: 已知 21、25、22、10、25*、18,用直接插入法将其排序。
0 1 2 3 4 5 6
21
25
22
10
25* 18
直接插入排序过程示例
r 0 1 21 i=2 i=3 i=4 i=5 i=6 22 10 25 18 21 21 21 10 10 10 2 25 25 25 22 15 15 15 3 22 22 22 25 21 21 18 4 10 10 10 10 5 25* 25* 25* 25* 25* 25* 25 6 18 18 18 18 18 18 25*
时间复杂度: T(n)=O(n² )
void binsort(JD r[],int n) { int i,j,x,s,m,k; for(i=2;i<=n;i++) { r[0]=r[i]; x=r[i].key; ‘用择半查找找待插记录的位置 s=1; j=i-1; while(s<=j) { m=(s+j)/2; if(x<r[m].key) j=m-1; else s=m+1; } ‘从i-1 到 s向右移动一个位置 for(k=i-1;k>=s;k--) r[k+1]=r[k]; ‘插入 r[s]=r[0]; } }
3. 2-路插入排序
49 38 65 97 76 13 27 49
当第一个数据在序列 中间位置时,可减少 移动次数,不减少比 较次数。
(49)
(49) (49 65) (49 65 97) (49 65 76 97) (49 65 76 97) (38) (38) (38) (38) (13 38)
i 2
1 n 1
n
记录移动次数:不需移动记录
例如
0
1
2
3
4
5
6
7
13 27 38 49 65 76 97
若待排序记录按关键字从大到小排列(逆序) 关键字比较次数: 记录移动次数:
(n 2)(n 1) i 2 i 2 n (n 4)(n 1) (i 1) 2 i 2
假设待排序的一组记录存放在地址连续的一组存 储单元上。
# define MAXSIZE 20 typedef int KeyType; typedef struct { KeyType key; InfoType otherinfo; } RedType; typedef struct { RedType r [MAXSIZE + 1 ] ; // r[0] 空或作哨兵 int length; } SqList;
例
0
i=1
1 2 3 4 5 6 7 (49) 38 65 97 76 13 27
i=2 38 (38 49) 65 97 76 13 27 i=3 65 (38 49 65) 97 76 13 27 i=4 97 (38 49 65 97) 76 13 27
i=5 76 (38 49 65 76 97) 13 27
Maxint 49 38 65 97 76 13 27 49 2 3 1 4 0
Maxint 49 38 65 97 76 13 27 49 2 3 1 5 0 4
Maxint 49 38 65 97 76 13 27 49 6 3 1 5 0 4 2 Maxint 49 38 65 97 76 13 27 49 6 3 1 5 0 4 7 2 Maxint 49 38 65 97 76 13 27 49 6 8 1 5 0 4 7 2 3
待排记录的数据类型
待排序的记录序列有三种存储方式: 1) 存放在地址连续的一组存储单元上; 2) 存放在静态链表中,记录之间的次序关系由指针指示,则 实现排序不需要移动记录,仅需要修改指针即可; 3) 存储在一组地址连续的存储单元内,同时另设一个指示各 个记录存储位置的地址向量,在排序过程中不移动记录本 身,而移动地址向量中这些记录的“地址”,在排序结束 之后再根据地址向量中的值调整记录的存储位置. 本文假设待排序记录存放在地址连续的一组存储单元上
的记录被安置在第n-1个记录位置;
重复上述过程,直到“在一趟排序过程中没有进行过交换 记录的操作”为止.
例
1 2 3 4
49 38 49 38 65 97 76 97 76 13 13 97 27 27 97 30 30 97
2. 折半插入排序
排序过程: 用折半查找方法确定插入位置的排序
例
i=1 i=2 13
i=7 6 i=8 20 i=8 20
…...
(30) 13 70 85 39 42 6 (13 30) 70 85 39 42 6
(6 (6 s (6 s 13 13 30 30 39 39 42 70 42 70 42 70
交换排序
1. 起泡排序(Bubble Sort)
排序过程
将第一、第二个记录的关键字进行比较,若 r[1].key>r[2].key,则交换;然后比较第二与第三个记 录;依次类推,直至第n-1个和第n个记录比较为止——第
一趟冒泡排序,结果关键字最大的记录被安置在最后一个 记录上;
对前n-1个记录进行第二趟冒泡排序,结果使关键字次大
r[0]的作用? 暂存单元 监视哨
25
25 21
问题1:如何构造初始的有序序列
解决方法: 将第1个记录看成是初始有序表,然后从第2个记录起依次插 入到这个有序表中,直到将第n个记录插入。 算法描述: for (i=2; i<=n; i++) { 插入第i个记录,即第i趟直接插入排序; }
问题2:如何查找待插入记录的插入位置?
0
1
2
3
4
5
Байду номын сангаас
6
7
8
Maxint 49 38 65 97 76 13 27 49 1 0
Maxint 49 38 65 97 76 13 27 49
2 0 1
Maxint 49 38 65 97 76 13 27 49
2
3
1
0
Maxint 49 38 65 97 76 13 27 49 2 3 1 4 0
5. 希尔排序(Shell) (缩小增量法)
排序过程: 先取一个正整数d1<n,把所有相隔d1的记录 放一组,组内进行直接插入排序; 然后取d2<d1,重复上述分组和排序操作; 直至di=1,即所有记录放进一个组中排序为止。
例
初始:
49 38 65 97 76 13 27
48 48
55 55
4 4
20 20
85 ) 20 85 ) 20 j 85 ) 20
m 13 30 39 m
13 13 j j 30 39 s mj 30 39
i=8 20 i=8 20
(6 (6
42 70 42 70
85 ) 20 85 ) 20
s
20 30 39 42 70 85 )
i=8 20
(6
13
算法描述
算法评价
复杂性
O(n2)
(49 65 76 97)
(49 49 65 76 97)
Final
(13 27 38)
(13 27 38)
First
4. 表插入排序
假设数据元素已存储在链表中,且0号单
元作为头结点,不移动记录而只是改变链指针 域,将记录按关键码建为一个有序链表。
首先,将表头结点和数组下标为1的结点构成一个循 环链表,即头结点指针域置1,下标为1结点的链域置 0,并在头结点数据域中存放比所有记录关键码都大 的整数。接下来,逐个结点向链表中插入即可。
n
例如 0 1 2 3 4 5 6 7 97 76 65 49 38 27 13
若待排序记录是随机的,取平均值
2 n 关键字比较次数: 4 2 n 记录移动次数: 4
T(n)=O(n² )
插入排序是一种稳定的排序方法。 原理:关键字相同的两个对象,在整个排 序过程中,不会通过比较而相互交换。
第十章
内部排序
1、插入排序 2、交换排序 3、选择排序 4、归并排序 5、基数排序
概
述
排 序 的 分 类
1. 按排序过程中使用的存储器分 a 内排序 b 外排序
2. 按文件的存储结构分 a 连续顺序文件排序 b 链表排序 3. 按排序的稳定性分 a 稳定性排序 b 不稳定性排序
内部排序:全部记录都可以同时调入内存 进行的排序;
r[0]有两个作用: 1. 进入循环之前暂存了r[i] 的值,使得不致于因记录 的后移而丢失r[i]的内容; 2. 在查找插入位置的循环 中充当哨兵。
整个排序过程为进行n-1趟插入,即先将序列中
第1个记录看成是一个有序子序列,然后从第2个记
录开始,逐个进行插入,直至整个序列有序。
算 法 描 述
typedef struct { int key; float info; }JD; ‘直接插入排序 void straisort(JD r[],int n) { int i,j; for(i=2;i<=n;i++) { r[0]=r[i]; ’哨兵 j=i-1;’从第i-1个位置起,和哨兵分别比较 while(r[0].key<r[j].key) { r[j+1]=r[j]; ’向右移动 j--; } r[j+1]=r[0]; } }