严蔚敏数据结构C语言 原PPT课件
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
8次
4358 3485 6552 5145 1354 3625 7272 2420 4707
n-i次
…
第n-1趟 排序结束
25
第25页/共58页
第10章 内部排序
10.3 交换类排序
①冒泡排序(相邻比逆法)
void BubbleSort(RecordType r[ ],int length)
{ n=length;
数
据
结
有序序列a[1..i-1]
构
a[i]
无序序列 a[i..n-1]
有序序列a[1..i]
无序序列 a[i+1..n-1]
7
第7页/共58页
第10章 内部排序 10.2 插入类排序
实现“一趟插入排序”可分三步进行:
1.在a[1..i-1]中查找a[i]的插入位置,
数
a[1..j].key a[i].key < a[j+1..i].key;
low = 1; high = i-1;
while (low<=high)
数
{
据
结
构
m= (low+high)/2;
if (L.r[0].key < L.r[m].klse low = m+1;
18
第18页/共58页
第10章 内部排序 10.2 插入类排序
③希尔排序 (又称缩小增量排序)
数 { R[1],R[1+d],R[1+2d],…,R[1+kd] }
据 { R[2],R[2+d],R[2+2d],…,R[2+kd] }
结
…
构 { R[d],R[2d],R[3d],…,R[kd],R[(k+1)d] }
其中,d 称为增量,它的值在排序过程中从 大到小逐渐缩小,直至最后一趟排序减为1。
数
据
L.r[0] = L.r[i];
结 构
在 L.r[1..i-1]中折半查找插入位置;
for ( j=i-1; j>=low; --j )
}}
L.r[j+1] = L.r[j];
L.r[low] = L.r[0];
17
第17页/共58页
第10章 内部排序
10.2 插入类排序
②折半插入排序
在 L.r[1..i-1]中折半查找插入位置;
} RecordType;
typedef struct
{
RcdType r[MAXSIZE+1];
int
length;
6
} SqList;
第6页/共58页
第10章 内部排序
10.2 插入类排序
将无序子序列中的一个或几个记录“插入”到有 序序列中,从而增加记录的有序子序列的长度。
一趟直接插入排序的基本思想:
①直接插入排序
对于在查找过程中找到的那些关键字不小于r[i].key的记录,并在查找的同时实现 记录向后移动;
数 据
for (j=i-1; r[0].key<r[j].key; --j); r[j+1] = r[j];
结
构
r[0]
r[i]
j 插入j=位i-置1
上述循环结束后可以直接进行“插入” r[j+1] = r[0];
数
据
基本思想:
结
通过交换逆序元素进行排序的方法。
构
①冒泡排序(相邻比逆法)
②快速排序
24
第24页/共58页
第10章 内部排序
10.3 交换类排序
①冒泡排序(相邻比逆法)
思想:在扫描的过程中顺次比较相邻的两个 元素的大小,若逆序就交换位置。
数 第1趟 据 结 构
第2趟
第i 趟
9次
48 6352 3625 7557 571754 173475 3775 9282 294280 4908
3
第3页/共58页
第10章 内部排序 10.1 概述
内部排序的方法 内部排序的过程: 是一个逐步扩大记录的有序序列长度的过程。
数
据
结
构
有序序列区
无序序列区
经过一趟排序
有序序列区
无序序列区
4
第4页/共58页
第10章 内部排序
10.1 概述
基于不同的“扩大” 有序序列长度的方法, 内部排序方法大致可分下列几种类型:
1
第1页/共58页
第10章 内部排序
10.1 概述 排序的定义: 假设含n个记录的序列为{ a0, a1, …, an-1 } 其相应的关键字序列为 { K0, K1, …,Kn-1 }
数
据
这些关键字相互之间可以进行比较,即在
结
它们之间存在着这样一个关系 :
构
Kp0≤Kp1≤…≤Kpn-1
按此固有关系将上式记录序列重新排列为 { ap0, ap1, …,apn-1 }
d3=1
05 1137 1173 42 46 55 9704 9740
21
第21页/共58页
第10章 内部排序
10.2 插入类排序
③希尔排序 (又称缩小增量排序)
void ShellInsert ( SqList &L, int dk ) {
for ( i=dk+1; i<=n; ++i )
if ( L.r[i].key< L.r[i-dk].key) {
第12页/共58页
第10章 内部排序
10.2 插入类排序
①直接插入排序
void InsertionSort ( SqList &L )
{
for ( i=2; i<=L.length; ++i )
if (L.r[i].key < L.r[i-1].key)
{
数
据
结
构
L.r[0] = L.r[i];
} }
即对无序的记录序列进行“一次划分”,
之后分别对分割所得两个子序列“递归”进行快速排序。
28
第28页/共58页
第10章 内部排序
10.3 交换类排序
②快速排序
一次划分(一趟快速排序) r[0]
数
48 3458 1642 35 4787 55 7174 6325 98
据
结
high
构
low low low low high high high high
据
结 构
2.将a[j+1..i]中的所有记录均后移一个位置;
3.将a[i] 插入(复制)到a[j+1]的位置上。
8
第8页/共58页
第10章 内部排序
10.2 插入类排序
不同的具体实现方法导致不同的算法描述
①直接插入排序(基于顺序查找)
数
据
②折半插入排序(基于折半查找)
结
构
③希尔排序(基于逐趟缩小增量)
L.r[0] = L.r[i];
for (j=i-dk; j>0&&(L.r[0].key<L.r[j].key);
数
j-=dk)
据
L.r[j+dk] = L.r[j];
结 构
L.r[j+dk] = L.r[0]; } }
22
第22页/共58页
第10章 内部排序 10.2 插入类排序
③希尔排序 (又称缩小增量排序)
基本思想: 对待排记录序列先作“宏观”调整,再作“微观”调整。
数 据 所谓“宏观”调整,指的是,“跳跃式”的插入排序。 结 构
19
第19页/共58页
第10章 内部排序
10.2 插入类排序
③希尔排序 (又称缩小增量排序)
具体做法为:
将记录序列分成若干子序列,分 别对每个子序列进行插入排序。
例如:将 n 个记录分成 d 个子序列:
29
第29页/共58页
第10章 内部排序
10.3 交换类排序
②快速排序
一趟快速排序算法
int QKpass (RecordType r[ ], int low, int high) {
数
据
从r[i-1]起向前进行顺序查找,监视哨设置在r[0];
结
构
r[0]
r[i]
r[0] = r[i];
j 插入j=位i-置1
for (j=i-1; r[0].key<r[j].key; --j);
循环结束表明r[i]的插入位置为 j +1
10
第10页/共58页
第10章 内部排序
10.2 插入类排序
第10章 内部排序
10.1 概述
排序是计算机内经常进行的一种操作,其目的是将 一组“无序”的记录序列调整为“有序”的记录序列。
数
例如:将下列关键字序列
据
结
52, 49, 80, 36, 14, 58, 61, 23, 97, 75
构
调整为
14, 23, 36, 49, 52, 58, 61, 75, 80, 97
for ( j=i-1; L.r[0].key < L.r[j].key; -- j ) L.r[j+1] = L.r[j];
L.r[j+1] = L.r[0];
13
第13页/共58页
第10章 内部排序 10.2 插入类排序
①直接插入排序
内部排序的时间分析:
实现内部排序的基本操作有两个:
数
据
(1)“比较”序列中两个关键字的大小;
数 据
插入类
结 构
交换类
选择类
归并类
其它方法
5
第5页/共58页
第10章 内部排序
10.1 概述
待排记录的数据类型定义如下:
#define MAXSIZE 1000
typedef int KeyType;
数
typedef struct
据
{
结
KeyType key;
构
OtherType other_data;
数 据
最好 有序
1
n-1
结
最坏 逆序 n-1 n(n-1)/2
构
27
第27页/共58页
第10章 内部排序
10.3 交换类排序
②快速排序
改进冒泡排序中一次交换只能消除一个逆序 的缺点,即实现一次交换消除多个逆序。
数 思想: 据 找一个记录,以它的关键字作为“枢轴”,凡其关键字 结 小于枢轴的记录均移动至该记录之前,凡其关键字 构 大于枢轴的记录均移动至该记录之后。
11
第11页/共58页
第10章 内部排序
10.2 插入类排序
①直接插入排序
令 i = 2,3,…, n, 实现整个序列的排序。
for ( i=2; i<=n; ++i )
if (r[i].key<r[i-1].key)
数
{
据 结
在 r[1..i-1]中查找r[i]的插入位置;
构
插入r[i] ;
}
12
20
第20页/共58页
第10章 内部排序 10.2 插入类排序
③希尔排序 (又称缩小增量排序)
数 据 d1=4 结 构
d2=2
46 55 13 42 94 17 05 70 46 1575 1053 42 94 1557 1035 70 0456 17 1035 42 4964 55 1943 70
数
据
结 构
例如:
插入 位置
i
L.r 14 36 49 52 58 61 80 23 97 75
low high low high
high
m
m
m
16
第16页/共58页
第10章 内部排序
10.2 插入类排序
②折半插入排序
void BiInsertionSort ( SqList &L )
{ for ( i=2; i<=L.length; ++i ) {
i2
2
“移动”的次数:
n (i 1) (n 4)(n 1)
i2
2
15
第15页/共58页
第10章 内部排序
10.2 插入类排序
②折半插入排序
因为 r[1..i-1] 是一个按关键字有序的有序序列,则 可以利用折半查找实现“在r[1..i-1]中查找r[i]的插 入位置”,如此实现的插入排序为折半插入排序。
void ShellSort (SqList &L, int dlta[], int t)
{
for (k=0; k<t; ++t)
ShellInsert(L, dlta[k]);
数
据
}
结
构
23
第23页/共58页
第10章 内部排序
10.3 交换类排序
通过“交换”无序序列中的记录从而得到其中关键字 最小或最大的记录,并将它加入到有序子序列中, 以此方法增加记录的有序子序列的长度。
for(i=1; i<=n-1; i++)
{
数
for(j=1;j<=n-i; ++j)
据
{
结 构
if(r[j].key>r[j+1].key) { x=a[j];r[j]=r[j+1];r[j+1]=x; }
}
}
}
26
第26页/共58页
第10章 内部排序 10.3 交换类排序
①冒泡排序
时间分析:
情况 序列 起泡次数 比较次数
④表插入排序(基于链表存储)
9
第9页/共58页
第10章 内部排序 10.2 插入类排序
①直接插入排序
利用顺序查找实现在r[1..i-1]中查找r[i]的插入位置 r[0]
第1 423567趟
513967545827 143485 643285 34655825 76547258 576572 176472 3757 98
结
构
(2)“移动”记录。
14
第14页/共58页
第10章 内部排序
10.2 插入类排序
①直接插入排序
对
于
直
数
接
据 结
插 入 排
构
序
最好的情况 (关键字在记录序列中顺序有序):
“比较”的次数: “移动”的次数:
n
1 n 1
i2
0
最坏的情况 (关键字在记录序列中逆序有序):
“比较”的次数:
n (i 1) (n 4)(n 1)
的操作称作排序。
2
第2页/共58页
第10章 内部排序
10.1 概述
内部排序
整个排序过程不需要访问外存便能完成。
排序
数
外部排序
据
若参加排序的记录数量很大,整个序列的排序过程不可能在内存中完
结
成。
构
稳定排序
排序
相同关键字的领先关系在排序过程中未发生变化。 不稳定排序
相同关键字的领先关系在排序过程中发生变化。
4358 3485 6552 5145 1354 3625 7272 2420 4707
n-i次
…
第n-1趟 排序结束
25
第25页/共58页
第10章 内部排序
10.3 交换类排序
①冒泡排序(相邻比逆法)
void BubbleSort(RecordType r[ ],int length)
{ n=length;
数
据
结
有序序列a[1..i-1]
构
a[i]
无序序列 a[i..n-1]
有序序列a[1..i]
无序序列 a[i+1..n-1]
7
第7页/共58页
第10章 内部排序 10.2 插入类排序
实现“一趟插入排序”可分三步进行:
1.在a[1..i-1]中查找a[i]的插入位置,
数
a[1..j].key a[i].key < a[j+1..i].key;
low = 1; high = i-1;
while (low<=high)
数
{
据
结
构
m= (low+high)/2;
if (L.r[0].key < L.r[m].klse low = m+1;
18
第18页/共58页
第10章 内部排序 10.2 插入类排序
③希尔排序 (又称缩小增量排序)
数 { R[1],R[1+d],R[1+2d],…,R[1+kd] }
据 { R[2],R[2+d],R[2+2d],…,R[2+kd] }
结
…
构 { R[d],R[2d],R[3d],…,R[kd],R[(k+1)d] }
其中,d 称为增量,它的值在排序过程中从 大到小逐渐缩小,直至最后一趟排序减为1。
数
据
L.r[0] = L.r[i];
结 构
在 L.r[1..i-1]中折半查找插入位置;
for ( j=i-1; j>=low; --j )
}}
L.r[j+1] = L.r[j];
L.r[low] = L.r[0];
17
第17页/共58页
第10章 内部排序
10.2 插入类排序
②折半插入排序
在 L.r[1..i-1]中折半查找插入位置;
} RecordType;
typedef struct
{
RcdType r[MAXSIZE+1];
int
length;
6
} SqList;
第6页/共58页
第10章 内部排序
10.2 插入类排序
将无序子序列中的一个或几个记录“插入”到有 序序列中,从而增加记录的有序子序列的长度。
一趟直接插入排序的基本思想:
①直接插入排序
对于在查找过程中找到的那些关键字不小于r[i].key的记录,并在查找的同时实现 记录向后移动;
数 据
for (j=i-1; r[0].key<r[j].key; --j); r[j+1] = r[j];
结
构
r[0]
r[i]
j 插入j=位i-置1
上述循环结束后可以直接进行“插入” r[j+1] = r[0];
数
据
基本思想:
结
通过交换逆序元素进行排序的方法。
构
①冒泡排序(相邻比逆法)
②快速排序
24
第24页/共58页
第10章 内部排序
10.3 交换类排序
①冒泡排序(相邻比逆法)
思想:在扫描的过程中顺次比较相邻的两个 元素的大小,若逆序就交换位置。
数 第1趟 据 结 构
第2趟
第i 趟
9次
48 6352 3625 7557 571754 173475 3775 9282 294280 4908
3
第3页/共58页
第10章 内部排序 10.1 概述
内部排序的方法 内部排序的过程: 是一个逐步扩大记录的有序序列长度的过程。
数
据
结
构
有序序列区
无序序列区
经过一趟排序
有序序列区
无序序列区
4
第4页/共58页
第10章 内部排序
10.1 概述
基于不同的“扩大” 有序序列长度的方法, 内部排序方法大致可分下列几种类型:
1
第1页/共58页
第10章 内部排序
10.1 概述 排序的定义: 假设含n个记录的序列为{ a0, a1, …, an-1 } 其相应的关键字序列为 { K0, K1, …,Kn-1 }
数
据
这些关键字相互之间可以进行比较,即在
结
它们之间存在着这样一个关系 :
构
Kp0≤Kp1≤…≤Kpn-1
按此固有关系将上式记录序列重新排列为 { ap0, ap1, …,apn-1 }
d3=1
05 1137 1173 42 46 55 9704 9740
21
第21页/共58页
第10章 内部排序
10.2 插入类排序
③希尔排序 (又称缩小增量排序)
void ShellInsert ( SqList &L, int dk ) {
for ( i=dk+1; i<=n; ++i )
if ( L.r[i].key< L.r[i-dk].key) {
第12页/共58页
第10章 内部排序
10.2 插入类排序
①直接插入排序
void InsertionSort ( SqList &L )
{
for ( i=2; i<=L.length; ++i )
if (L.r[i].key < L.r[i-1].key)
{
数
据
结
构
L.r[0] = L.r[i];
} }
即对无序的记录序列进行“一次划分”,
之后分别对分割所得两个子序列“递归”进行快速排序。
28
第28页/共58页
第10章 内部排序
10.3 交换类排序
②快速排序
一次划分(一趟快速排序) r[0]
数
48 3458 1642 35 4787 55 7174 6325 98
据
结
high
构
low low low low high high high high
据
结 构
2.将a[j+1..i]中的所有记录均后移一个位置;
3.将a[i] 插入(复制)到a[j+1]的位置上。
8
第8页/共58页
第10章 内部排序
10.2 插入类排序
不同的具体实现方法导致不同的算法描述
①直接插入排序(基于顺序查找)
数
据
②折半插入排序(基于折半查找)
结
构
③希尔排序(基于逐趟缩小增量)
L.r[0] = L.r[i];
for (j=i-dk; j>0&&(L.r[0].key<L.r[j].key);
数
j-=dk)
据
L.r[j+dk] = L.r[j];
结 构
L.r[j+dk] = L.r[0]; } }
22
第22页/共58页
第10章 内部排序 10.2 插入类排序
③希尔排序 (又称缩小增量排序)
基本思想: 对待排记录序列先作“宏观”调整,再作“微观”调整。
数 据 所谓“宏观”调整,指的是,“跳跃式”的插入排序。 结 构
19
第19页/共58页
第10章 内部排序
10.2 插入类排序
③希尔排序 (又称缩小增量排序)
具体做法为:
将记录序列分成若干子序列,分 别对每个子序列进行插入排序。
例如:将 n 个记录分成 d 个子序列:
29
第29页/共58页
第10章 内部排序
10.3 交换类排序
②快速排序
一趟快速排序算法
int QKpass (RecordType r[ ], int low, int high) {
数
据
从r[i-1]起向前进行顺序查找,监视哨设置在r[0];
结
构
r[0]
r[i]
r[0] = r[i];
j 插入j=位i-置1
for (j=i-1; r[0].key<r[j].key; --j);
循环结束表明r[i]的插入位置为 j +1
10
第10页/共58页
第10章 内部排序
10.2 插入类排序
第10章 内部排序
10.1 概述
排序是计算机内经常进行的一种操作,其目的是将 一组“无序”的记录序列调整为“有序”的记录序列。
数
例如:将下列关键字序列
据
结
52, 49, 80, 36, 14, 58, 61, 23, 97, 75
构
调整为
14, 23, 36, 49, 52, 58, 61, 75, 80, 97
for ( j=i-1; L.r[0].key < L.r[j].key; -- j ) L.r[j+1] = L.r[j];
L.r[j+1] = L.r[0];
13
第13页/共58页
第10章 内部排序 10.2 插入类排序
①直接插入排序
内部排序的时间分析:
实现内部排序的基本操作有两个:
数
据
(1)“比较”序列中两个关键字的大小;
数 据
插入类
结 构
交换类
选择类
归并类
其它方法
5
第5页/共58页
第10章 内部排序
10.1 概述
待排记录的数据类型定义如下:
#define MAXSIZE 1000
typedef int KeyType;
数
typedef struct
据
{
结
KeyType key;
构
OtherType other_data;
数 据
最好 有序
1
n-1
结
最坏 逆序 n-1 n(n-1)/2
构
27
第27页/共58页
第10章 内部排序
10.3 交换类排序
②快速排序
改进冒泡排序中一次交换只能消除一个逆序 的缺点,即实现一次交换消除多个逆序。
数 思想: 据 找一个记录,以它的关键字作为“枢轴”,凡其关键字 结 小于枢轴的记录均移动至该记录之前,凡其关键字 构 大于枢轴的记录均移动至该记录之后。
11
第11页/共58页
第10章 内部排序
10.2 插入类排序
①直接插入排序
令 i = 2,3,…, n, 实现整个序列的排序。
for ( i=2; i<=n; ++i )
if (r[i].key<r[i-1].key)
数
{
据 结
在 r[1..i-1]中查找r[i]的插入位置;
构
插入r[i] ;
}
12
20
第20页/共58页
第10章 内部排序 10.2 插入类排序
③希尔排序 (又称缩小增量排序)
数 据 d1=4 结 构
d2=2
46 55 13 42 94 17 05 70 46 1575 1053 42 94 1557 1035 70 0456 17 1035 42 4964 55 1943 70
数
据
结 构
例如:
插入 位置
i
L.r 14 36 49 52 58 61 80 23 97 75
low high low high
high
m
m
m
16
第16页/共58页
第10章 内部排序
10.2 插入类排序
②折半插入排序
void BiInsertionSort ( SqList &L )
{ for ( i=2; i<=L.length; ++i ) {
i2
2
“移动”的次数:
n (i 1) (n 4)(n 1)
i2
2
15
第15页/共58页
第10章 内部排序
10.2 插入类排序
②折半插入排序
因为 r[1..i-1] 是一个按关键字有序的有序序列,则 可以利用折半查找实现“在r[1..i-1]中查找r[i]的插 入位置”,如此实现的插入排序为折半插入排序。
void ShellSort (SqList &L, int dlta[], int t)
{
for (k=0; k<t; ++t)
ShellInsert(L, dlta[k]);
数
据
}
结
构
23
第23页/共58页
第10章 内部排序
10.3 交换类排序
通过“交换”无序序列中的记录从而得到其中关键字 最小或最大的记录,并将它加入到有序子序列中, 以此方法增加记录的有序子序列的长度。
for(i=1; i<=n-1; i++)
{
数
for(j=1;j<=n-i; ++j)
据
{
结 构
if(r[j].key>r[j+1].key) { x=a[j];r[j]=r[j+1];r[j+1]=x; }
}
}
}
26
第26页/共58页
第10章 内部排序 10.3 交换类排序
①冒泡排序
时间分析:
情况 序列 起泡次数 比较次数
④表插入排序(基于链表存储)
9
第9页/共58页
第10章 内部排序 10.2 插入类排序
①直接插入排序
利用顺序查找实现在r[1..i-1]中查找r[i]的插入位置 r[0]
第1 423567趟
513967545827 143485 643285 34655825 76547258 576572 176472 3757 98
结
构
(2)“移动”记录。
14
第14页/共58页
第10章 内部排序
10.2 插入类排序
①直接插入排序
对
于
直
数
接
据 结
插 入 排
构
序
最好的情况 (关键字在记录序列中顺序有序):
“比较”的次数: “移动”的次数:
n
1 n 1
i2
0
最坏的情况 (关键字在记录序列中逆序有序):
“比较”的次数:
n (i 1) (n 4)(n 1)
的操作称作排序。
2
第2页/共58页
第10章 内部排序
10.1 概述
内部排序
整个排序过程不需要访问外存便能完成。
排序
数
外部排序
据
若参加排序的记录数量很大,整个序列的排序过程不可能在内存中完
结
成。
构
稳定排序
排序
相同关键字的领先关系在排序过程中未发生变化。 不稳定排序
相同关键字的领先关系在排序过程中发生变化。