数据结构第八章
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
70
第3步 第2步 第1步
X=13 05
i
13 05
i=j j
17
42
46
94
55
70
第3步 第2步 第1步
X=94 05
13
17
42
46
70
i
55
i
94 70
i=j j
第3步 第2步 第1步
X=70 05
05
13
13
17
17
42
42
46
46
55
i
70 55
i=j j
94
94
结束
55
70
2. 快速排序算法 快速排序是一个递归的过程,只要能够实现一趟快速 排序的算法,就可以利用递归的方法对一趟快速排序后的 左右分区域分别进行快速排序。下面是一趟快速排序的算 法分析:
具体步骤可以描述如下: ① 假设待排序的记录为n个,先取整数d<n,例如,取d=
n/2 ,将所有距离为d的记录构成一组,从而将整个
待排序记录序列分割成为d个子序列,对每个分组分 别进行直接插入排序; ② 然后再缩小间隔d,即d= d/2 ,以此间隔d重新分组, 再对每个分组分别进行直接插入排序;
③ 在对这两个无序子区分别进行上述处理,以此类 推,直至所有无序区的记录个数均不大于1为止。
怎样才能确定控制记录的合适位置呢? ① 初始化:取第一个记录作为控制记录,设置两个 指针i,j分别用来指示将要与控制记录进行比较的 左侧记录位置,即i=1;和右侧记录位置,即j=n; ② 取无序区的首记录r[i]作为控制记录,先把r[i]临时 存放在附设变量x中,然后用控制记录与右侧j位置 的记录进行比较,如果右侧记录的关键字值大, 则继续与j的前一个记录进行比较,即j- -后的记录 比较,若右侧的记录小(逆序),则将j位置的记 录左移到i位置;
4
5
6
7
8
46 46 46 46 05 05 05
55 55 17 17 17 17 13
13 13 05 05 13 13 17
42 42 42 42 42 42 42
94 94 94 94 46 46 46
17 17 55 55 55 55 55
05 05 13 13 94 94 70
70 70 70 70 70 70 94
置在外设上,整个排序过程需要在内外存之间多次交换数
据才能得到排序的结果。本章主要讨论常用的内部排序算 法,并将其推广到外部排序。
8.1 插入排序
插入排序的主要思路是不断地将待排序的数值插入到
有序段中,使有序段逐渐扩大,直至所有数值都进入有序
段中为止。
8.1.1 直接插入排序
直接插入排序的基本思想 直接插入排序是一种比较简单的排序方法。它的基本
1
2
3
4
5
6
7
i=7 i=6 i=5 i=4 i=3 i=2 i=1
1 2 3 8
2 8 3
3 5 8 2
8 5
6 8 9
8 9 1
9 6
下面给出记录类型的定义和直接插入算法的C函数: struct node {int key; int data; }; typedef struct node NODE; void insert(NODE r[],int n) {int i,j; for(i=2;i<=n;i++) {r[0]=r[i]; /*将r[i]暂存到r[0]中*/ j=i-1; while(r[i].key<r[j].key) r[j+1]=r[j- -]; r[j+1]=r[0]; } }
希尔排序是一种不稳定的排序方法。
8.2 交换排序
交换排序是指在排序过程中,主要是通过待 排序记录序列中元素间关键字的比较,与存储位 置的交换来达到排序目的一类排序方法。
8.2.1 冒泡排序
1. 冒泡排序的基本思想
冒泡排序是交换排序中一种简单的排序方法。 它的基本思想是对所有相邻记录的关键字值进行 比效,如果是逆顺(r[j]>r[j+1]),则将其交换, 最终达到有序化。其处理过程为:
录为止。
1
初始时 第9步 第8步 第7步 第6步 第5步 第4步 第2步 第3步 第1步
2
3
4
5
6
7
8
X=46 46 x 17
i
05 55
i
13
i
42
i
46 94
i=j i
94 05
j
55 17
j
70
j
第5步 第4步 第3步 第2步 第1步
X=17 13
i
05
i
17 13
i=j j
42ຫໍສະໝຸດ Baidu
j
46
94
55
分析上述算法,其主要操作为比较和移动记录,为了正 确插入第i个记录,最多比较i-1次,最少比较1次,平均比较
i/2次。因此将n个记录进行直接插入排序所需要的平均比较
次数为:
而为了插入第i个记录,最多移动i+1次(包括r[0]=r[i]), 最少不移动记录,即平均移动次数为(i+1)/2。插入n个记录所 需的平均移动次数近似为n2/2。 当待排序的数据元素基本有序时,直接插入排序过程中
8.2.2 快速排序
1. 快速排序的基本思想
快速排序又称为分区交换排序。其基本思想是:
① 首先将待排序记录序列中的所有记录作为当前待 排序区域,从中任选取一个记录(比如,第一个 记录),并以该记录的关键字值作为控制关键字 (相应的记录称为控制记录),设法把控制记录放到 无序区的合适的位置上;
② 同时对其他记录作适当的调整,使得在控制记录 右边的所有记录的关键字值都大于控制关键字, 而在它左边的所有记录的关键字值都不大于关键 字值。这样把一个无序区分成两个无序子区;
(1)将整个待排序的记录序列划分成有序区和无 序区,初始状态有序区为空,无序区包括所有待排序 的记录。 (2)对无序区从前向后依次将相邻记录的关键字 进行比较,若逆序将其交换,从而使得关键字值小的
记录向上“飘浮”(上移),关键字值大的记录好像
石块向下“沉落”(下移)。 每经过一趟冒泡排序,都使无序区中关键字值最 小的记录进入有序区,对于由n个记录组成的记录序列, 最多经过n-1趟冒泡排序,就可以将这n个记录重新按 关键字顺序排列。
1 2 3
44 11 22 44 55 33 44 55 22
2. 冒泡排序算法 对由n个记录组成的记录序列,最多经 过(n-1)趟冒泡排序,就可以使记录序列 成为有序序列。若想获得有序区的第j个记
4 5
6 7 8
44 55 22 33
55 33 99 66 99 11 77 99 66 99 77
在希尔排序中,由于开始将n个待排序的记录分成了d组,
所以每组中的记录数目将会减少。在数据量较少时,利用直
接插入排序的效率较高。随着反复分组排序,d值逐渐变小, 每个分组中的待排序记录数目将会增多,但此时记录的排列 顺序将更接近有序,所以利用直接插入排序不会降低排序的 时间效率。 希尔排序适用于待排序的记录数目较大时,在此情况下, 希尔排序方法一般要比直接插入排序方法快。 希尔排序的平均比较次数和平均移动次数都为n1.3左右。
思想是依次将记录序列中的每一个记录插入到有序段中,
使有序段的长度不断地扩大。
其具体的排序过程可以描述如下: 1. 首先将待排序记录序列中的第一个记录作为一个有序段, 将记录序列中的第二个记录插入到上述有序段中形成由 两个记录组成的有序段; 2. 再将记录序列中的第三个记录插入到这个有序段中,形 成由三个记录组成的有序段,…依此类推; 每一趟都是将一个记录插入到前面的有序段中,假设当 前欲处理第i个记录,则应该将这个记录插入到由前i-1个记 录组成的有序段中,从而形成一个由i个记录组成的按关键 字值排列的有序序列,直到所有记录都插入到有序段中。 一共需要经过n-1趟就可以将初始序列的n个记录重新排列 成按关键字值大小排列的有序序列。
第8章 排序
本章中主要介绍下列内容: 插入排序
交换排序
选择排序 归并排序 基数排序
退出
8.1 基本概念
8.2 插入排序
8.3 交换排序
8.4 选择排序
8.5 归并排序 8.6 基数排序
排序 设{R1,R2, …,Rn}是一组记录,其对应的 关键字为K1,K2, …,Kn。把一组记录按照其关键字值 递增(或递减)的顺序重新排列起来,使当i<j时,满 足Ki≤Kj(或Ki≥Kj)(1≤i<j≤n)。
录,需要从后向前对无序区中的相邻记录一
对一对地进行关键字的比较,一直到第j个 记录为止。第一趟进行n-1次比较,此时有 序区只有一个记录;第二趟进行n-2次比较, 此时有序区有两个记录,以此类推。
下面给出冒泡排序算法:
void bubblesort (NODE r[],int n)
{int i,j, x,exchange; for(i=1;i< =n-1;i++) {exchange=0; for(j=n;j>i;j- -)
if(r[j].key<r[j-1].key)
{ x=r[j]; r[j]=r[j-1]; r[j-1]=x; exchange=1; } if(exchange==0) break; } }
冒泡排序比较简单,当初始序列基本有序时, 冒泡排序有较高的效率,反之效率较低。冒泡排序 是一种稳定的排序方法。其最多比较次数:
(2) 在某一d值下对各组进行排序 do
{bool=false;
某一组内排序; }while(bool=true);
(3) 以不同间隔d进行排序
d=n; while(d>1) {d=d/2; 在某一d值下对各组进行排序; } 设记录类型与前所述相同,其完整程序如下:
void shell(NODE r[],int n) {int i,j,d; enum{false,true}bool;NODE x; d=n; while(d>1) {d=d/2; do {bool=false; for (i=1; i<=n-d; i++) {j=i+d; if(r[i].key>r[j].key) {x=r[i]; r[i]=r[j];r[j]=x; bool=true; } } }while(bool=true); printf(“d=%3d\n”,d); for(i=1;i<=n;i++) printf(“%3d”,r[i].key); printf(“\n”); } }
③ 接着使i右移一个位置,即i++,再用控制记录与i位置 的记录进行比较,如果i位置的记录关键字值小,则继 续与i的后一个记录,即i++后的记录进行比较,若i位 置的的记录关键字大(逆序),则将i位置的记录右移 到j位置; ④ 这样控制记录与右侧的j位置的记录的比较与左侧i位 置的记录的比较交替重复进行,直到指针i与j指向同 一位置,即为控制记录最终(合适的)位置。这样就完 成一趟快速排序; ⑤ 一趟快速排序完成之后,再分别对左右两个无序区进 行快速排序,以此类推,直到每个分区都只有一个记
排序算法的稳定性 如果在待排序的记录序列中
有多个数据元素的关键字值相同,经过排序后,这 些数据元素的相对次序保持不变,则称这种排序算 法是稳定的,否则称之为不稳定的。
内部排序与外部排序 根据在排序过程中待排序的所
有记录是否全部被放置在内存中,可将排序方法分为内部
排序和外部排序两大类。内部排序是指在排序的整个过程 中,待排序的所有记录全部被放置在内存中;外部排序是 指由于待排序的记录个数太多,不能同时放置在内存,而 需要将一部分数据元素放置在内存,另一部分数据元素放
d=4 d=4 d=2 d=2 d=1 d=1
希尔排序示例
2. 希尔排序算法
(1) 分别让每个记录参与相应分组内的排序 从第一个记录开始,按某个d值为间距进行组内比 较。若有逆序则进行交换位置: bool=false; for (i=1; i<=n-d; i++) {j=i+d; if(r[i].key>r[j].key) {x=r[i]; r[i]=r[j]; r[j]=x; bool=true; } }
③ 直到最后取间隔d=1,即将所有记录放在一组进行一
次直接插入排序,最终将所有记录重新排列成按关键 字有序的序列。
对间隔值的取法,有多种方法,希尔提出的取
法是: d1= n/2 , di+1= di/2 。其中n为待排序
记录数,i=1,2, …, log2n 。
1
初始状态
2
3
的比较次数和移动次数大大减少,从而效率会有所提高。
插入排序是一种稳定的排序方法。
8.1.2 希尔排序
1. 希尔排序的基本思想
希尔排序方法又称为缩小增量排序,其基本思想 是将待排序的记录划分成几组,从而减少参与直接插 入排序的数据量,当经过几次分组排序后,记录的排 列已经基本有序,这个时候再对所有的记录实施直接 插入排序。