第21讲 排序之交换排序和选择排序

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。


7.3.1 冒泡排序

冒泡排序的具体实现
排序中各元素不断接近自己的位置,如果一趟下来没有交换, 则序列已经有序,可设一个标志flag判断,提前结束
void BubbleSort(list R,int n) {//上升法冒泡排序 int i,j,flag; for(i=1;i<=n−1;i++) { //做n−1趟扫描 flag=0; //置未交换标志 for(j=n;j>=i+1;j−−) //从下向上扫描 if(R[j].key<R[j−1].key) { //交换记录 flag=1; R[0]=R[j];R[j]=R[j−1];R[j−1]=R[0]; //交换,R[0]作辅助量 } if(!flag) break; //本趟未交换过,排序结束 } }
上节回顾
(2)直接插入排序 空间复杂度:O(1) 稳定性:稳定 适合场景:序列基本有序或元素个数较少 (3)希尔排序(缩小增量排序,分组插入排序) 思想:按增量将元素分组后分别进行直接插入排序; 反复如此,直到增量为1 时间复杂度:O(nlog2n)~O(n2),稍优于直接插入排序 空间复杂度:O(1) 稳定性:不稳定
7.3.1 冒泡排序
(2)空间复杂度分析:只需要一个辅助空间用于交换 数据,因此S(n)=1=O(1) (3)稳定性
在数据绝对小于时才发生交换,因此对两个数值相同的 元素不会发生交换,因此算法是稳定的
7.3.2 快速排序
基本思想: (1)划分:选定一个数做为轴值,把序列分成比轴值 小(左边)和比轴值大(右边)两个子序列
7.3.2 快速排序
int Partition(list R,int p,int q) { 如何实现划分?交替扫描 //对无序区R[p]到R[q]划分,返回划分后基准的位置 int i,j; i=p; j=q; R[0]=R[i]; //R[0]作辅助量,存基准(无序区第一个记录) while(i<j) { while(R[j].key>=R[0].key && i<j) j−−; //从右向左扫描 if(i<j) {R[i]=R[j];i++;} //交换R[i]和R[j] while(R[i].key<=R[0].key && i<j) i++; //从左向右扫描 if(i<j) {R[j]=R[i];j−−;} //交换R[i]和R[j] } R[i]=R[0]; //将基准移到最后位置 return i; }

R[0]=R[i]; 其中i为无序区第一个元素 R[0]
23 23
i
13
35
6
19
50
28
j
7.3.2 快速排序
对一个序列R[p,q]进行划分Partition (1)设下标i从头指向尾,下标j从尾指向头 (2)选择第1个数作为轴值 (3)从j开始向前行动,寻找比轴值小的值 R[0] while(R[j].key>=R[0].key && i<j) j−−;
13
i
35
6
**
j
50
28
7.3.2 快速排序
对一个序列R[p,q]进行划分Partition (4)找到比轴值小的数,则与轴值交换 (5)换i行动,依次向后搜索一个比轴值大的数 while(R[i].key<=R[0].key && i<j) i++;

R[0]
23 19
13
35
i
6
**
j
50

23 23
i
13
35
6
19
j
50
28
7.3.2 快速排序
对一个序列R[p,q]进行划分Partition (4)找到比轴值小的数,则与轴值交换 if(i<j) {R[i]=R[j];i++;}

R[0]
23 19
i
13
35
6
**
j
50
28
7.3.2 快速排序
对一个序列R[p,q]进行划分Partition (4)找到比轴值小的数,则与轴值交换 if(i<j) {R[i]=R[j];i++;}

7.3.1 冒泡排序
基本思想: 将序列划分成有序区(左边)和无序区(右边) 初始时,有序区为空,无序区为序列全部
r1 r2 …ri-1 ri ri+1 … rn
有序区 无序区
7.3.1 冒泡排序
基本思想: 将序列划分成有序区(左边)和无序区(右边) 初始时,有序区为空,无序区为序列全部 每一次“冒泡”相邻元素依次两两比较,将较小/大者 交换到前面,成为有序区的第一个元素
r1 ≤ r2 ≤ … ≤ ri-1 ri ri+1 … rn-1 rn
有序区 无序区
7.3.1 冒泡排序
基本思想: 将序列划分成有序区(左边)和无序区(右边) 初始时,有序区为空,无序区为序列全部 每一次“冒泡”相邻元素依次两两比较,将较小/大者 交换到前面,成为有序区的第一个元素
r1 ≤ r2 ≤ … ≤ ri-1 ≤ ri ri+1 … rn-1 rn
第2次循环:
a[0] a[1] a[2] a[3] a[4] a[5]
4 45 36 4 45 36 4 45 36 4 45 13 4 13 45
4次比较
13 25
43
13 25
43
13 25
43
36 25
43
36 25
43
7.3.1 冒泡排序
第3次循环:
a[0] a[1] a[2] a[3] a[4] a[5]
36 45
43
7.3.1 冒泡排序
第5次循环:
a[0] a[1] a[2] a[3] a[4] a[5]
4 13 25 4 13 25
1次比较
完成排序!!
36 45
43
36 43
45
7.3.1 冒泡排序

两层循环(n = 6)

外层n-1次:i = 1 to n-1 内层(用于比较相邻的两个数): 第1次循环:比较n-1次;例子中5次 第2次循环:比较n-2次;例子中4次 第i次循环:比较n-i次; 用j表示每次比较,j = 1 to n-i
有序区 无序区
7.3.1 冒泡排序
第1次循环:
a[0] a[1] a[2] a[3] a[4] a[5]
45 36 4 45 36 4 45 36 4 45 36 4 45 4 36
5次比较
4 45 36
13 25
43
13 25
43
13 25
43
13 25
43
13 25
43
13 25
43
7.3.1 冒泡排序
上升法和下沉法 上升法,每次扫描从序列尾部向头部扫,每次比较相 邻的元素,将较小(升序)/较大(降序)的元素交换到前 面,如此,有序的“气泡”就会从尾部往上“冒”

下沉法,每次扫描从序列头部向尾部扫,每次比较相 邻的元素,将较大(升序)/较小(降序)的元素交换到后 面,如此,有序的“气泡”就会从头部向下“沉” 本章主要讨论上升法
28
7.3.2 快速排序
对一个序列R[p,q]进行划分Partition (6)找到后,与轴值交换 if(i<j) {R[j]=R[i];j−−;}

R[0]
23 19
13
**
i
6
35
j
50
28
7.3.2 快速排序
对一个序列R[p,q]进行划分Partition (6)找到后,与轴值交换 if(i<j) {R[j]=R[i];j−−;}

23 23
i
13
35
6
19
50
28
j
7.3.2 快速排序
对一个序列R[p,q]进行划分Partition (1)设下标i从头指向尾,下标j从尾指向头 (2)选择第1个数作为轴值 (3)从j开始向前行动,寻找比轴值小的值 R[0] while(R[j].key>=R[0].key && i<j) j−−;

R[0]
23 19
13
i
35
6
**
j
50
28
7.3.2 快速排序
对一个序列R[p,q]进行划分Partition (4)找到比轴值小的数,则与轴值交换 (5)换i行动,依次向后搜索一个比轴值大的数 while(R[i].key<=R[0].key && i<j) i++;

R[0]
23 19
课堂练习
1、用直接插入排序对下面4个序列进行递增排序,元素 比较次数最少的是( )。 A. 94,32,40,90,80,46,21,69 B. 32,40,21,46,69,94,90,80 C. 21,32,46,40,80,69,90,94 D. 90,69,80,46,21,32,94,40 答案:C。A选项总共比较24次;B选项总共比较17次; C选项总共比较9次;D选项总共25次
第21讲 排序 ——交换排序和选择排序
7.3 交换排序
基本思想: 每次比较两个待排序的记录,如果关键字的次序与排 序要求相反时就交换两者的位置,直到没有反序的记录 为止。 特点: 键值较大的记录向排序表的一端移动,键值较小的记 录向另一端移动。 经典算法: (1)冒泡排序 (2)快速排序
7.3.1 冒泡排序

R[0]
23 19
13
**
i
6
j
35
50
28
7.3.2 快速排序
对一个序列R[p,q]进行划分Partition (6)找到后,与轴值交换 (7)转回由j向前行动,轮流更换,直到i和j重合 while(i<j)

R[0]
23 19
13
6
**
i j
35
50
28
7.3.2 快速排序
对一个序列R[p,q]进行划分Partition (6)找到后,与轴值交换 (7)转回由j向前行动,轮流更换,直到i和j重合 (8)将轴值移到合适位置:R[i]=R[0];
7.3.2 快速排序

对一个序列R[p,q]进行划分Partition
23
13
35
6
19
50
28
7.3.2 快速排序
对一个序列R[p,q]进行划分Partition (1)设下标i从头指向尾,下标j从尾指向头 i=p; j=q;

23
i
13
Biblioteka Baidu
35
6
19
50
28
j
7.3.2 快速排序
对一个序列R[p,q]进行划分Partition (1)设下标i从头指向尾,下标j从尾指向头 (2)选择第1个数作为轴值
4 13 45 4 13 45 4 13 45 4 13 25
3次比较
36 25
43
36 25
43
25 36
43
45 36
43
7.3.1 冒泡排序
第4次循环:
a[0] a[1] a[2] a[3] a[4] a[5]
4 13 25 4 13 25 4 13 25
2次比较
45 36
43
45 36
43
课堂练习
2、数据序列(8,12,10,15,9,7,20,16,4)需 要排序为升序序列。经过一趟增量为5的希尔排序后的 结果是( ) A.(7,20,16,4, 8,12,10,15,9) B.(7, 12, 10, 4, 9, 8, 20, 16, 15) C.(10,15,8,12,20,16,4, 9,7) D.(4, 7, 8, 9, 10, 12, 15, 16, 20) 答案:B
上节回顾
(1)基本概念: 稳定性:检测相同的元素在排序是否保持先后顺序 内排序和外排序 有序区增长法和有序度增长法 (2)直接插入排序 思想:每次将无序区的第一个元素插入到有序区合适 的位置 时间复杂度:与数据分布有关

最好(基本有序):O(n) 最坏(逆序):O(n2) 平均:O(n2)
7.3.1 冒泡排序
(1)时间复杂度分析: 最好情况:序列正序,通过flag标志,序列只需要两两 比较一趟即结束,共需要比较n-1次,即 T(n)=n-1=O(n) 最坏情况:序列反序,每一趟不止要完成所有有序区 元素的两两比较,而且每比较一次要交换一次,因此, 对第i趟冒泡而言,最坏情况下要比较i-1次和交换i-1次, 即共需要操作的语句数为: T(n)=∑2(i-1)=O(n2) 平均情况:O(n2)

23 23
i
13
35
6
19
50
j
28
7.3.2 快速排序
对一个序列R[p,q]进行划分Partition (1)设下标i从头指向尾,下标j从尾指向头 (2)选择第1个数作为轴值 (3)从j开始向前行动,寻找比轴值小的值 R[0] while(R[j].key>=R[0].key && i<j) j−−;

[ r1 … … ri-1 ] ri [ ri+1 … … rn ]
均≤ri
轴值
均≥ri
(2)求解子问题:分别对两个子序列进行轴值划分, 直到划分区域里只有一个元素 关键问题:如何选择轴值?如何实现划分?
7.3.2 快速排序
轴值选择不同,划分的效率不同,排序的速度也不同。 如何选择轴值? (1)常用、最简单的做法:选当前序列第一个 (2)随机选取 (3)选择序列的中位数(最好)
相关文档
最新文档