第10章-内排序第2讲-插入排序(直接插入-折半插入-希尔)
数据结构-内排序

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 直接插入排序举例
数据结构-第十章-内部排序

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.某内排序方法的稳定性是指( D )。
【南京理工大学 1997 一、10(2分)】A.该排序算法不允许有相同的关键字记录 B.该排序算法允许有相同的关键字记录C.平均时间为0(n log n)的排序方法 D.以上都不对2.下面给出的四种排序法中( D )排序法是不稳定性排序法。
【北京航空航天大学 1999 一、10 (2分)】 A. 插入 B. 冒泡 C. 二路归并 D. 堆积3.下列排序算法中,其中(D )是稳定的。
【福州大学 1998 一、3 (2分)】A. 堆排序,冒泡排序B. 快速排序,堆排序C. 直接选择排序,归并排序D. 归并排序,冒泡排序4.稳定的排序方法是( B )【北方交通大学 2000 二、3(2分)】A.直接插入排序和快速排序 B.折半插入排序和起泡排序C.简单选择排序和四路归并排序 D.树形选择排序和shell排序5.下列排序方法中,哪一个是稳定的排序方法?( B )【北方交通大学 2001 一、8(2分)】A.直接选择排序 B.二分法插入排序 C.希尔排序 D.快速排序6. 快速排序方法在( D )情况下最不利于发挥其长处。
【燕山大学 2001 一、3 (2分)】A. 要排序的数据量太大B. 要排序的数据中含有多个相同值C. 要排序的数据个数为奇数D. 要排序的数据已基本有序7. 以下序列不是堆的是( D )。
【西安电子科技大学 2001应用一、5 (2分)】A. (100,85,98,77,80,60,82,40,20,10,66)B. (100,98,85,82,80,77,66,60,40,20,10)C. (10,20,40,60,66,77,80,82,85,98,100)D. (100,85,40,77,80,60,66,98,82,10,20)8.下列四个序列中,哪一个是堆( C )。
【北京工商大学 2001 一、8 (3分)】A. 75,65,30,15,25,45,20,10B. 75,65,45,10,30,25,20,15C. 75,45,65,30,15,25,20,10D. 75,45,65,10,25,30,20,159.从未排序序列中依次取出一个元素与已排序序列中的元素依次进行比较,然后将其放在已排序序列的合适位置,该排序方法称为( A )排序法。
c++几种基本的插入排序(图文)
c++⼏种基本的插⼊排序(图⽂)1.插⼊排序插⼊排序(Insertion Sort)是⼀种简单直观的排序算法。
它的⼯作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插⼊。
插⼊排序在实现上,通常采⽤in-place排序(即只需⽤到O(1)的额外空间的排序),因⽽在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插⼊空间。
时间复杂度:O(n^2);算法描述:1.从第⼀个元素开始,该元素可以认为已经被排序2.取出下⼀个元素,在已经排序的元素序列中从后向前扫描3.如果该元素(已排序)⼤于新元素,将该元素移到下⼀位置4.重复步骤3,直到找到已排序的元素⼩于或者等于新元素的位置5.将新元素插⼊到该位置后6.重复步骤2~5动画演⽰:作者:Swfung8算法演⽰:/***直接插⼊排序*/void InsertSort(int a[], int len){int i, j, key;for(i = 1; i < len; ++i){key = a[i];for(j = i-1; j >=0; --j){if(a[j] > key)a[j+1] = a[j];elsebreak;}a[j+1] = key;}}2.折半插⼊排序折半插⼊排序(binary insertion sort)是对插⼊排序算法的⼀种改进,所谓排序算法过程,就是不断的依次将元素插⼊前⾯已排好序的序列中。
时间复杂度O(n^2);算法描述:在将⼀个新元素插⼊已排好序的数组的过程中,寻找插⼊点时,将待插⼊区域的⾸元素设置为a[low],末元素设置为a[high],则轮⽐较时将待插⼊元素与a[m],其中m=(low+high)/2相⽐较,如果⽐参考元素⼤,则选择a[low]到a[m-1]为新的插⼊区域(即high=m-1),否则选择a[m+1]到a[high]为新的插⼊区域(即low=m+1),如此直⾄low<=high不成⽴,即将此位置之后所有元素后移⼀位,并将新元素插⼊a[high+1]算法演⽰:/***折半插⼊排序*/void BinsertSort(int a[], int len){int i, j;int low, high, mid;int key;for(i = 1; i < len; i++){key = a[i];low = 1; high = i-1;while (low <= high){mid = (low+high)/2;if(key < a[mid])high = mid-1;elselow = mid+1;}for(j = i-1; j >=high+1; --j)a[j+1] = a[j];a[high+1] = key;}}3.希尔排序希尔排序,也称为递减增量排序算法,是插⼊排序的⼀种⾼效的改进版本。
数据结构(严蔚敏)第10章
一、什么是排序?
排序是计算机内经常进行的一种操作, 其目的是将一组“无序”的记录序列调 整为“有序”的记录序列。
例如:将下列关键字序列 52, 49, 80, 36, 14, 58, 61, 23, 97, 75
调整为
14, 23, 36, 49, 52, 58, 61 ,75, 80, 97 .页 08.06.2020
10. 2 插入排序
.页 08.06.2020
一趟直接插入排序的基本思想:
有序序列R[1..i-1]
无序序列 R[i..n]
R[i]
有序序列R[1..i]
无序序列 R[i+1..n]
.页 08.06.2020
实现“一趟插入排序”可分三步进行:
1.在R[1..i-1]中查找R[i]的插入位置,
R[1..j].key R[i].key < R[j+1..i-1].key;
有序序列区 无 序 序 列 区
经过一趟排序
08.06.2020
有序序列区 无 序 序 列 区
.页
基于不同的“扩大” 有序序列长 度的方法,内部排序方法大致可分 下列几种类型:
插入类 交换类 选择类
归并类 其它方法
.页 08.06.2020
#待de排fin记e M录A的XS数IZ据E 类10型00定// 义待排如顺下序:表最大长度
第十章 排序
.页 08.06.2020
【课前思考】
1. 你熟悉排序吗?你过去曾经学过哪些排序方法? 在第一章中曾以选择排序和起泡排序为例讨论算 法实践复杂度,不知你还记得吗? 2. 你自己有没有编过排序的程序?是用的什么策 略?
.页 08.06.2020
【学习目标】
第十章排序
依次类推,则完成排序。
正序:时间复杂度为O(n) 逆序:时间复杂度为O(n2)
适合于数据较少的情况。
2013-5-13 排序n个记录的文件最多需要n-1趟冒泡排序。 举例:图8-2-5
25
思想:小的 浮起,大的 沉底。
25 56 49 78 11 65 41 36
初 始 关 键 字
25 49 56 11 65 41 36 78
第 一 趟 排 序 后
25 49 11 56 41 36 65
25 11 49 41 36 56
11 25 41 36 49
11 25 36 41
11 25 36
简单选择排序、堆排序。
1、简单选择排序
思想:首先从1~n个元素中选 出关键字最小的记录交换到第 一个位置上。然后再从第2 个 到第n个元素中选出次小的记 录交换到第二个位置上,依次 类推。
时间复杂度为O(n2), 适用于待排序元素较少的情况。
3 j 3 k 3 k 3
互换
9 9 j 9 9
1 1 1 j 1 k 8
插入算法如下:
9
方法:Ki与Ki-1,K i-2,…K1依次比较,直到找到应插入的位置。 void insertSort(RedType L[ ],int n)
{ int i ,j; for(i=2; i<=n; i++) if(L[i].key<L[i-1].key)
{
L[0]=L[i];
L[j+1]=L[j]; L[j+1]=L[0];
数据结构 排序
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”和“基本有序”两 方面改进。
将待排序的记录划分成几组,从而减少参 与直接插入排序的数据量,当经过几次分 组排序后,记录的排列已经基本有序,这 个时候再对所有的记录实施直接插入排序。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
希尔排序
直接插入ห้องสมุดไป่ตู้序
大约时间=102=100
d=5:分为5组,时间约为5×22=20
+
d=2:分为2组,时间约为2×52=50
+
d=1:分为1组,几乎有序,时间约为10
= 80
15/20
希尔排序算法不稳定的反例:希尔排序法是一种不稳定的排序算 法。
3 5 10 8 7 2 8 1 20 6
d=2
算法最后一趟对所有数据进行了直接插入排序,所以 结果一定是正确的。
12/20
一趟希尔排序过程
将记录序列分成若干子序列,分别对每个子序列进行直接插入排序。
例如:将 n 个记录分成 d 个子序列:
{ R[0], R[d], R[2d],…, R[kd] } { R[1], R[1+d], R[1+2d],…,R[1+kd] }
1/20
基本思路
有序区
一个一个地 插入
无序区
不一定是全局有序(整体有序) 全局有序区 的元素在后面排序中不再发生位置的改变
主要的插入排序方法:
(1)直接插入排序 (2)折半插入排序 (3)希尔排序
2/20
基本思路
R[0]
有序区
…… R[i-1]
无序区
R[i]
……
R[n-1]
一趟排序
R[0]
……
R[i-1] R[i]
6/20
算法分析
最好的情况(关键字在记录序列中正序):
“比较”的次数:
n 1
1 n 1
i 1
“移动”的次数: 0
最坏的情况(关键字在记录序列中反序):
“比较”的次数:
“移动”的次数:
n1 i n(n 1)
i 1
2
n1 (i 2) (n 1)(n 4)
i 1
2
总的平均比较和移动次数约为
n1
(9,8,7,6,5,4,3,2,1,0) (8,9,7,6,5,4,3,2,1,0) (7,8,9,6,5,4,3,2,1,0) (6,7,8,9,5,4,3,2,1,0) (5,6,7,8,9,4,3,2,1,0) (4,5,6,7,8,9,3,2,1,0) (3,4,5,6,7,8,9,2,1,0) (2,3,4,5,6,7,8,9,1,0) (1,2,3,4,5,6,7,8,9,0) (0,1,2,3,4,5,6,7,8,9)
R[j]大时便后移
使R[0..i]有序 扩大有序区
4/20
【例10-1:p369】 设待排序的表有10个元素,其关键字 分别为(9,8,7,6,5,4,3,2,1,0)。说明采用直接插 入排序方法进行排序的过程。
5/20
初始: i=1: i=2: i=3: i=4: i=5: i=6: i=7: i=8: i=9:
3 1 7 2 8 5 10 6 20 8
相对位置发生改变
希尔排序是不稳定的
16/20
【例(补充)】 希尔排序的组内排序采用的是( )。
A.直接插入排序
B.折半插入排序
C.快速排序
D.归并排序
说明:本题为2015年全国考研题
17/20
18/20
直接插 入排序
0 123 45
8 76 5 6 78 9
d=d/2=1 0 1 2 3 4 5
直接插 入排序
0
123
45
6 78 9 6 78 9
注意:对于d=1的一趟,排序前的数据已将近正序!
14/20
希尔排序的时间复杂度约为O(n1.3)。
为什么希尔排序比直接插入排序好? 例如:有10个元素要排序。
算法分析
折半插入排序:在R[0..i-1]中查找插入R[i]的位置,折半 查找的平均关键字比较次数为log2(i+1)-1,平均移动元素的次数 为i/2+2,所以平均时间复杂度为:
n1 ( log 2(i 1) 1 i 2) O(n2)
i 1
2
折半插入排序采用折半查找,查找效率提高。但元素移动次 数不变,仅仅将分散移动改为集合移动。
有序区
R[i+1] …… 无序区
R[n-1]
初始时,有序区只有一个元素R[0] i=1~n-1,共经过n-1趟排序
3/20
一趟直接插入排序:在有序区中插入R[i]的过程。
有序区R[0..i-1]
R[i] 当R[i].key<R[i-1].key时
j R[j+1]=tmp
j=i-1 插入位置
tmp 无序区R[i..n-1]
i 1
(
i 2
i 2
2)
n1 i 1
(i
2)
(n
1)(n 2
4)
O(n2)
最好:O(n)
最坏:O(n2) 平均:O(n2)
7/20
基本思路
查找采用折半查找方法,称为二分插入排序或折半插入排序。
有序区
R[0]
…… R[i-1]
无序区
R[i]
……
R[n-1]
采用折半查找在有序区找 到插入的位置
8/20
9/20
【例(补充)】对同一待排序序列分别进行折半插入排序和 直接插入排序,两者之间可能的不同之处是( )。
A.排序的总趟数 B.元素的移动次数 C.使用辅助空间的数量 D.元素之间的比较次数
说明:本题为2012年全国考研题
10/20
11/20
基本思路
① d=n/2 ② 将排序序列分为d个组,在各组内进行直接插入排序 ③ 递减d=d/2,重复② ,直到d=1
… { R[d-1],R[2d-1],R[3d-1],…,R[(k+1)d-1] }
一组 一组
一组
相距d个位置的记录分为一组
13/20
【例10-2:p373】
初始序列 9 8 7 6
d=5
9 876
直接插 入排序
4 321
54 54 09
3 21 0 3 21 0 8 76 5
d=d/2=2 4 3 2 1 0 9