5_2 交换与选择排序
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
7
5.3.1
冒泡排序
•
下降法示例 a 0 8 1 3 2 4 3 9 4 7
自上而下地扫描的下降法
最大元素下降到底部
0 1 2 3
4
a 8 3 4 9 7
0 1 2 3
4
a 3 8 4 9 7
0 1 2 3
4
a 3 4 8 9 7
0 1 2 3
4
a 3 4 8 9 7
0 1 2 3
4
a 3 4 8 7 9
不交换, 再比较 8 和 3
3 8 4 7 9
交换 8 和 3
3 8 4 7 9
上升结果
比较 9 和 7
6
5.3.1
冒泡排序
2. 简单的冒泡排序算法(上升法)
void bubble_sort(int a[ ],int n) { int i,j,x; 1. for(j=0;j<n-1; j++) // j是本遍扫描终点下标 2. for(i=n-2;i>=j; i-- ) 3. if(a[i]>a[i+1]) //逆序 4. { x=a[i]; a[i]=a[i+1]; a[i+1]=x; } }
5.3.2 快速排序(quick sort )
1.基本原理 也称划分交换排序,因速度非常快而得名
反复进行有序划分 在数组a中任选一个元素x作为划分元素,通过比较 将小于x的元素换到数组的左端(左段) 将大于或等于x的元素换到数组右端(右段) x本身位于两段之间 如果左、右段元素个数多于1,则递归的将左、右段各自划分, 直到每段元素个数都不超过1,从而达到排序目的
27
5.4.3 堆排序( heap sort )
2. 示例
0 1
由J.Willioms于1964年设计
2 3 4 5 6 7 8 9 10
a
96 67 83 54 65 45 23 12 29 32 存储堆的数组
1 96 2 67
83
3
23
堆的逻辑结构
7
4
8
28
54 29
5 65
9
32
45
6
12
10
5.3.2 快速排序(quick sort )
6. 结论 1)划分元素的选取是关键 2 )输入数据次序越乱,划分元素值的随机性越好, 排序速度越快 (不是自然排序) 3)无法保证子问题的大小完全平衡 最坏情况下,总是O(n2)的
24
5.4 选择排序(selection sort)
1. 原理 从n个元素中选出一个最大元素,调到序列末端 再从剩下的n-1个元素中选出最大元素„„, 反复如此,可完成排序 for(k=n-1;k>0;k - -) { i=0; for(j=1;j<=k;j++) if(a[j]>a[i]) i=j; //选最大元 交换a[k]与a[i]; }
数据结构与算法
第五章 排序
——交换排序和选择排序
信息工程系 赖小平
内容提要
4+2 学时
主要内容:
交换排序:冒泡排序、快速排序 选择排序:直接选择法、堆排序
教学目标:
熟悉两种排序方法的原理 掌握快速排序算法和堆排序算法
1
重 难 点
快速排序算法 堆排序算法
2
5 . 3
交 换 排 序
Exchange Sort i<j a[i]>a[j] 大数排在小数前面,称a[i]和a[j]构成 “逆序” 在排序过程中,通过比较元素的大小发现逆序元素就交 换它们的位置,这种方法成为交换排序。 交换可以消除逆序,当所有的逆序都消除后,排序完成。
8与3比较,8下降
8与9比较,8不下降 9与7比较,9下降
最大元9下降到最底部
8与4比较,8再下降
8
5.3.1
下降法
冒泡排序
自上而下地扫描的下降法 最大元素下降到底部
用语句描述第一遍扫描: for(i=0;i<=n-2; i++) if(a[i]>a[i+1])交换a[i]与a[i+1]
下一遍扫描: for(i=0;i<=n-3; i++) if(a[i]>a[i+1])交换a[i]与a[i+1] 1. for(j=0;j<n-1; j++) 2. for(i=n-2;i>=j; i--) 2. for(i=0;i<=n-2-j; i++ )
25
5.4 选择排序(selection sort)
2. 效率分析
T(n)=O(n2)
存在大量冗余比较 1)元素x与y比较一次之后,可能还会比较 2)已有比较结果:x>y而且y>z,但可能还会将x与z进行比较 直接选择法不能记住每次比较的结果并在以后的步骤中使用它。
有必要探讨消除冗余比较的方法:树选排序、堆排序
22
5.3.2 快速排序(quick sort )
5. 性能分析 空间复杂性 用到递归,需附加栈空间,不属原地排序 理想情况/平均情况: S (n)= O(logn) 最坏情况:SW(n)=O(n) 时间复杂性 理想情况/平均情况:T (n)= O(nlogn) 最坏情况:TW(n)=O(n2)
23
14
5.3.2 快速排序(quick sort )
2.划分操作示例 划分段:等待划分的一段数据 选x=54进行划分 54 31 76 23 35 87 19 63 81 28 一次划分结果 28 31 19 23 35 54 87 63 81 76 左段
15
划分元素x
右段
取划分段左端(首元素)作为划分元素
5.4.3 堆排序( heap sort )
3.排序阶段的操作方法 步骤1)令j=n; j是堆的最大下标,即堆的当前尾指针 步骤2)将a[1]与a[j]交换,将最大元换到当前尾 步骤3)j=j-1;使堆的范围缩小 步骤4)重新堆化(是关键步骤) 即调整a[1]至a[j],使之成为一个新堆 步骤5)若j>1,则转步骤2;否则排序结束
3
5.3
排序的基本概念
冒泡排序原理是“相邻元素比较、交换” 因元素交换步伐太小影响排序速度 快速排序原理反复进行划分,元素交换步伐大, 排序速度快 冒泡排序是基础,快速排序是重点
4
5.3.1 冒泡排序(bubble sort)
1.基本原理 反复扫描数组a,比较相邻元素a[i]与a[i+1] 若逆序(a[i]>a[i+1])就交换
19
63
81
28
空单元
28
28 28 28
31
31 31 31
76
76 76 19
23
23 23 23
35
35 35 35
87
87 87 87
19
19 19 19
63
63 63 63
81
81 81 81
76
76 76 76 空单元
x=54
28
28 28 28 28
31
31 31 31 31
19
19 19 19 19
k 划分元素就位位置
下一步,将分别递归的对左段(下标从s到k-1) 和右段(下标从到k+1到t)进行划分
5.3.2 快速排序(quick sort )
3. 递归的快速排序算法 ( 1 )划分函数 partition 完成对一个划分段的划 分,返回划分元素最终 位置
void partition(int a[ ],int s,int t,int &k) { int i,j,x; 1. x=a[s]; //取划分元素 2. i=s; j=t; //扫描指针初值 3. do //循环地进行划分 4. { while((a[j]>=x)&&(i<j)) j- - ; 5. if(i<j) a[i++]=a[j]; 6. while ((a[i]<x)&&(i<j)) i++; 7. if(i<j) a[j- -]=a[i]; } 8. while(i<j); //直到i等于j 9. a[i]=x; //划分元素就位 10. k=i; }
1. for(j=n-2; j>=0; j--) 2. for(i=0; i<=j; i++)
9
5.3.1
3. 初步改进
冒泡排序
考虑因素:如果某遍扫描没发生元素交换,排序即已完成,以后无需再扫描 改进措施:设置一个标记,记录内循环中是否发生元素交换
0 1 2 3 4
a 8 3 4 9 7
0 1 2 3 4265.4.3 堆排序( heap sort )
1. 堆的定义 由J.Willioms于1964年设计
堆是每个非叶结点值都大于或等于其儿子值 (父大于子)的完全二叉树
用数组a[n+1]存储长度为n的堆(a[0]不用) a[i]≥a[2*i] a[i]≥a[2*i+1] 根结点a[1]存储的是最大值(大根堆)
a 3 4 8 7 9
0 1 2 3 4
a 3 4 7 8 9
0 1 2 3 4
a 3 4 7 8 9
10
第一遍扫描 有交换
第二遍扫描 有交换
第三遍扫描 没有交换
5.3.1
冒泡排序
4. 带交换否标记的汽泡排序算法(下降法)
void bubble_sort_2(int a[ ],int n) { int i,j,x,flag=1; 1. j=n-2; 2. while(flag) { 3. flag=0; 4. for(i=0;i<=j;i++) 5. if(a[i]>a[i+1]) { 5. x=a[i]; a[i]=a[i+1]; a[i+1]=x; flag=1;} 6. j--; } }
按照从两端向中间扫描的方法进行划分
活动指针
取x=54
空单元
54
54
31
31
76
76
23
23
35
35
87
87
19
19
63
63
81
81
28
28
28
非活动指针 28
31
31
76
76
23
23
35
35
87
87
19
19
63
63
81
81
28
28
空单元 空单元
x=54 空单元 空单元 空单元
28
31
76
23
35
87
96 32
67
83
54
65
45
23
12
29
32 96
•
•
自上而下地扫描的下降法 最大元素下降到底部 自下而上地扫描的上升法 最小元素上升到数组顶部
5
5.3.1
冒泡排序
上升法排序的第一遍扫描示例
0 1 2 3 4 8 3 4 9 7 8 3 4 7 9
交换 9 和 7, 再比较 4 和 7
8 3 4 7 9
不交换, 再比较 3 和 4
8 3 4 7 9
23
23 23 23 23
35
35 35 35 35
87
87 87 87 54
19
19 19 87 87
63
63 63 63 63
81
81 81 81
76
76 76 76
空单元
空单元 空单元 空单元
划分元素就位 81 76
划分段左下标 s x=54 28 31 19 23 35 54 87 63
划分段右下标 t 81 76
20
5.3.2 快速排序(quick sort )
3. 递归的快速排序算法 ( 2 )递归函数 qksort 完 成划分段的一对下标 “配对”,调用partition 对其划分
void qksort(int a[ ],int i,int j) { int k; 11. if(i<j) { 12. partition(a,i,j,k); //划分 13. qksort(a,i,k-1); //递归 14. qksort(a,k+1,j); //递归 } }
(3)主调语句: qksort(a,0,n-1); //对数组a[n]排序
21
5.3.2 快速排序(quick sort )
4. 划分元素的选择方法 1)首元素 2)选择“中值元素” 首元素a[s]、尾元素a[t]和中间位置的元素a[(s+t)/2] 三者中“中间大小”的那个元素 3)随机元素 选择a[i],i 是划分段下标值s到t之间的一个随机数 当划分元素不是首元素,先与首元素交换,再划分
11
5.3.1
5. 性能分析
冒泡排序
空间复杂性:不需附加空间,属原地排序 S (n)=O(1) 时间复杂性:T (n)=O(n2)
12
5.3.1
冒泡排序
6. 进一步改进:带交换否标记的汽泡排序算法(下降法)
void bubble_sort_3(int a[ ],int n) { flag不仅用来记录 int i,j,x,flag; 内循环是否发生交 1. flag=n-2; 换,而且记录交换 2. while(flag) { 的元素的下标,即 3. j=flag; 本轮循环最后一次 4. flag=0; 的交换点,以减少 5. for(i=0;i<=j;i++) 下一遍扫描的范围, 6. if(a[i]>a[i+1]) { 从而提高排序速度 7. x=a[i]; a[i]=a[i+1]; a[i+1]=x; flag=i;} } } 13
29
示例(n=10)
1 2 4 8
12 54 29 67
96 32
83
步1 j=n=10
3
23
步2 a[1]与a[10]交换
7
5 9
32 96
65
45
6
步3 j=j-1(j=9) 步4 重新堆化a[1]至a[j] 重新堆化方法,后述
10
j
0 1 2 3 4 5 6 7
绿色结点脱离了堆
8 9 10
a
5.3.1
冒泡排序
•
下降法示例 a 0 8 1 3 2 4 3 9 4 7
自上而下地扫描的下降法
最大元素下降到底部
0 1 2 3
4
a 8 3 4 9 7
0 1 2 3
4
a 3 8 4 9 7
0 1 2 3
4
a 3 4 8 9 7
0 1 2 3
4
a 3 4 8 9 7
0 1 2 3
4
a 3 4 8 7 9
不交换, 再比较 8 和 3
3 8 4 7 9
交换 8 和 3
3 8 4 7 9
上升结果
比较 9 和 7
6
5.3.1
冒泡排序
2. 简单的冒泡排序算法(上升法)
void bubble_sort(int a[ ],int n) { int i,j,x; 1. for(j=0;j<n-1; j++) // j是本遍扫描终点下标 2. for(i=n-2;i>=j; i-- ) 3. if(a[i]>a[i+1]) //逆序 4. { x=a[i]; a[i]=a[i+1]; a[i+1]=x; } }
5.3.2 快速排序(quick sort )
1.基本原理 也称划分交换排序,因速度非常快而得名
反复进行有序划分 在数组a中任选一个元素x作为划分元素,通过比较 将小于x的元素换到数组的左端(左段) 将大于或等于x的元素换到数组右端(右段) x本身位于两段之间 如果左、右段元素个数多于1,则递归的将左、右段各自划分, 直到每段元素个数都不超过1,从而达到排序目的
27
5.4.3 堆排序( heap sort )
2. 示例
0 1
由J.Willioms于1964年设计
2 3 4 5 6 7 8 9 10
a
96 67 83 54 65 45 23 12 29 32 存储堆的数组
1 96 2 67
83
3
23
堆的逻辑结构
7
4
8
28
54 29
5 65
9
32
45
6
12
10
5.3.2 快速排序(quick sort )
6. 结论 1)划分元素的选取是关键 2 )输入数据次序越乱,划分元素值的随机性越好, 排序速度越快 (不是自然排序) 3)无法保证子问题的大小完全平衡 最坏情况下,总是O(n2)的
24
5.4 选择排序(selection sort)
1. 原理 从n个元素中选出一个最大元素,调到序列末端 再从剩下的n-1个元素中选出最大元素„„, 反复如此,可完成排序 for(k=n-1;k>0;k - -) { i=0; for(j=1;j<=k;j++) if(a[j]>a[i]) i=j; //选最大元 交换a[k]与a[i]; }
数据结构与算法
第五章 排序
——交换排序和选择排序
信息工程系 赖小平
内容提要
4+2 学时
主要内容:
交换排序:冒泡排序、快速排序 选择排序:直接选择法、堆排序
教学目标:
熟悉两种排序方法的原理 掌握快速排序算法和堆排序算法
1
重 难 点
快速排序算法 堆排序算法
2
5 . 3
交 换 排 序
Exchange Sort i<j a[i]>a[j] 大数排在小数前面,称a[i]和a[j]构成 “逆序” 在排序过程中,通过比较元素的大小发现逆序元素就交 换它们的位置,这种方法成为交换排序。 交换可以消除逆序,当所有的逆序都消除后,排序完成。
8与3比较,8下降
8与9比较,8不下降 9与7比较,9下降
最大元9下降到最底部
8与4比较,8再下降
8
5.3.1
下降法
冒泡排序
自上而下地扫描的下降法 最大元素下降到底部
用语句描述第一遍扫描: for(i=0;i<=n-2; i++) if(a[i]>a[i+1])交换a[i]与a[i+1]
下一遍扫描: for(i=0;i<=n-3; i++) if(a[i]>a[i+1])交换a[i]与a[i+1] 1. for(j=0;j<n-1; j++) 2. for(i=n-2;i>=j; i--) 2. for(i=0;i<=n-2-j; i++ )
25
5.4 选择排序(selection sort)
2. 效率分析
T(n)=O(n2)
存在大量冗余比较 1)元素x与y比较一次之后,可能还会比较 2)已有比较结果:x>y而且y>z,但可能还会将x与z进行比较 直接选择法不能记住每次比较的结果并在以后的步骤中使用它。
有必要探讨消除冗余比较的方法:树选排序、堆排序
22
5.3.2 快速排序(quick sort )
5. 性能分析 空间复杂性 用到递归,需附加栈空间,不属原地排序 理想情况/平均情况: S (n)= O(logn) 最坏情况:SW(n)=O(n) 时间复杂性 理想情况/平均情况:T (n)= O(nlogn) 最坏情况:TW(n)=O(n2)
23
14
5.3.2 快速排序(quick sort )
2.划分操作示例 划分段:等待划分的一段数据 选x=54进行划分 54 31 76 23 35 87 19 63 81 28 一次划分结果 28 31 19 23 35 54 87 63 81 76 左段
15
划分元素x
右段
取划分段左端(首元素)作为划分元素
5.4.3 堆排序( heap sort )
3.排序阶段的操作方法 步骤1)令j=n; j是堆的最大下标,即堆的当前尾指针 步骤2)将a[1]与a[j]交换,将最大元换到当前尾 步骤3)j=j-1;使堆的范围缩小 步骤4)重新堆化(是关键步骤) 即调整a[1]至a[j],使之成为一个新堆 步骤5)若j>1,则转步骤2;否则排序结束
3
5.3
排序的基本概念
冒泡排序原理是“相邻元素比较、交换” 因元素交换步伐太小影响排序速度 快速排序原理反复进行划分,元素交换步伐大, 排序速度快 冒泡排序是基础,快速排序是重点
4
5.3.1 冒泡排序(bubble sort)
1.基本原理 反复扫描数组a,比较相邻元素a[i]与a[i+1] 若逆序(a[i]>a[i+1])就交换
19
63
81
28
空单元
28
28 28 28
31
31 31 31
76
76 76 19
23
23 23 23
35
35 35 35
87
87 87 87
19
19 19 19
63
63 63 63
81
81 81 81
76
76 76 76 空单元
x=54
28
28 28 28 28
31
31 31 31 31
19
19 19 19 19
k 划分元素就位位置
下一步,将分别递归的对左段(下标从s到k-1) 和右段(下标从到k+1到t)进行划分
5.3.2 快速排序(quick sort )
3. 递归的快速排序算法 ( 1 )划分函数 partition 完成对一个划分段的划 分,返回划分元素最终 位置
void partition(int a[ ],int s,int t,int &k) { int i,j,x; 1. x=a[s]; //取划分元素 2. i=s; j=t; //扫描指针初值 3. do //循环地进行划分 4. { while((a[j]>=x)&&(i<j)) j- - ; 5. if(i<j) a[i++]=a[j]; 6. while ((a[i]<x)&&(i<j)) i++; 7. if(i<j) a[j- -]=a[i]; } 8. while(i<j); //直到i等于j 9. a[i]=x; //划分元素就位 10. k=i; }
1. for(j=n-2; j>=0; j--) 2. for(i=0; i<=j; i++)
9
5.3.1
3. 初步改进
冒泡排序
考虑因素:如果某遍扫描没发生元素交换,排序即已完成,以后无需再扫描 改进措施:设置一个标记,记录内循环中是否发生元素交换
0 1 2 3 4
a 8 3 4 9 7
0 1 2 3 4265.4.3 堆排序( heap sort )
1. 堆的定义 由J.Willioms于1964年设计
堆是每个非叶结点值都大于或等于其儿子值 (父大于子)的完全二叉树
用数组a[n+1]存储长度为n的堆(a[0]不用) a[i]≥a[2*i] a[i]≥a[2*i+1] 根结点a[1]存储的是最大值(大根堆)
a 3 4 8 7 9
0 1 2 3 4
a 3 4 7 8 9
0 1 2 3 4
a 3 4 7 8 9
10
第一遍扫描 有交换
第二遍扫描 有交换
第三遍扫描 没有交换
5.3.1
冒泡排序
4. 带交换否标记的汽泡排序算法(下降法)
void bubble_sort_2(int a[ ],int n) { int i,j,x,flag=1; 1. j=n-2; 2. while(flag) { 3. flag=0; 4. for(i=0;i<=j;i++) 5. if(a[i]>a[i+1]) { 5. x=a[i]; a[i]=a[i+1]; a[i+1]=x; flag=1;} 6. j--; } }
按照从两端向中间扫描的方法进行划分
活动指针
取x=54
空单元
54
54
31
31
76
76
23
23
35
35
87
87
19
19
63
63
81
81
28
28
28
非活动指针 28
31
31
76
76
23
23
35
35
87
87
19
19
63
63
81
81
28
28
空单元 空单元
x=54 空单元 空单元 空单元
28
31
76
23
35
87
96 32
67
83
54
65
45
23
12
29
32 96
•
•
自上而下地扫描的下降法 最大元素下降到底部 自下而上地扫描的上升法 最小元素上升到数组顶部
5
5.3.1
冒泡排序
上升法排序的第一遍扫描示例
0 1 2 3 4 8 3 4 9 7 8 3 4 7 9
交换 9 和 7, 再比较 4 和 7
8 3 4 7 9
不交换, 再比较 3 和 4
8 3 4 7 9
23
23 23 23 23
35
35 35 35 35
87
87 87 87 54
19
19 19 87 87
63
63 63 63 63
81
81 81 81
76
76 76 76
空单元
空单元 空单元 空单元
划分元素就位 81 76
划分段左下标 s x=54 28 31 19 23 35 54 87 63
划分段右下标 t 81 76
20
5.3.2 快速排序(quick sort )
3. 递归的快速排序算法 ( 2 )递归函数 qksort 完 成划分段的一对下标 “配对”,调用partition 对其划分
void qksort(int a[ ],int i,int j) { int k; 11. if(i<j) { 12. partition(a,i,j,k); //划分 13. qksort(a,i,k-1); //递归 14. qksort(a,k+1,j); //递归 } }
(3)主调语句: qksort(a,0,n-1); //对数组a[n]排序
21
5.3.2 快速排序(quick sort )
4. 划分元素的选择方法 1)首元素 2)选择“中值元素” 首元素a[s]、尾元素a[t]和中间位置的元素a[(s+t)/2] 三者中“中间大小”的那个元素 3)随机元素 选择a[i],i 是划分段下标值s到t之间的一个随机数 当划分元素不是首元素,先与首元素交换,再划分
11
5.3.1
5. 性能分析
冒泡排序
空间复杂性:不需附加空间,属原地排序 S (n)=O(1) 时间复杂性:T (n)=O(n2)
12
5.3.1
冒泡排序
6. 进一步改进:带交换否标记的汽泡排序算法(下降法)
void bubble_sort_3(int a[ ],int n) { flag不仅用来记录 int i,j,x,flag; 内循环是否发生交 1. flag=n-2; 换,而且记录交换 2. while(flag) { 的元素的下标,即 3. j=flag; 本轮循环最后一次 4. flag=0; 的交换点,以减少 5. for(i=0;i<=j;i++) 下一遍扫描的范围, 6. if(a[i]>a[i+1]) { 从而提高排序速度 7. x=a[i]; a[i]=a[i+1]; a[i+1]=x; flag=i;} } } 13
29
示例(n=10)
1 2 4 8
12 54 29 67
96 32
83
步1 j=n=10
3
23
步2 a[1]与a[10]交换
7
5 9
32 96
65
45
6
步3 j=j-1(j=9) 步4 重新堆化a[1]至a[j] 重新堆化方法,后述
10
j
0 1 2 3 4 5 6 7
绿色结点脱离了堆
8 9 10
a