数据结构第八章学习小结
一、学习内容小结
排序可分为两大类:
内部排序(Internal Sorting):待排序的记录全部存放在计算机内存中进行的排序过程;
外部排序(External Sorting):待排序的记录数量很大,内存不能存储全部记录,需要对外存进行访问的排序过程。(现阶段还没有详细深入的学习)
(本章学习的排序方法比较多,有点容易混淆,难记忆,花了比较多的时间在把各类方法总结成表格,看着对比比较清晰易懂一些。)
排序方法分类 |
排序方法 (内部排序) |
概述 |
时间复杂度分析 |
空间复杂度分析 |
算法特点 (优缺点) |
交换类
|
冒泡排序 |
重复走访过要排序的元素列,依次比较两个相邻的元素,如果顺序错误就把他们交换过来,直到没有相邻元素需要交换,则排序完成。 |
O(n^2) |
O(1) (两元素交换时,只需要一个记录的辅助空间) |
优点:①稳定排序②可用于链式存储结构 缺点:①不适用于初始记录无序、n较大的情况 |
快速排序 |
通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。 |
O(nlog(2)(n)) |
最好情况: O(log(2)(n)) 最坏情况:O(n) (递归,执行时需要一个栈存放数据,最大递归调用次数与递归树深度一致) |
优点:①适用于初始记录无序、n较大的情况(是所有内部排序中最快的方法) 缺点:①只能用于顺序存储结构②不稳定排序 |
|
插入类
|
直接插入排序 |
(顺序查找)将一条记录插入到已排好序的有序表中得到一个新的、记录数量增加1的有序表。 |
平均:O(n^2) |
O(1) (只需要一个记录的辅助空间r[0]) |
优点:①稳定排序②算法简便③可用于链式存储结构④适用于初始记录基本有序(正序) 缺点:①当初始记录基本无序、n较大时复杂度高,不适用 |
折半插入排序 |
对直接插入排序算法的改进,排序原理同直接插入算法。(在插入到已排序的数据时采用来折半查找(二分查找)) |
O(n^2) (与直接插入排序相比,减少了比较次数,移动次数不变) |
O(1) (只需要一个记录的辅助空间r[0]) |
优点:①稳定排序②适用于初始记录无序、n较大的情况 缺点:①只能用于顺序存储结构 |
|
希尔排序 (缩小增 量排序) |
(分组插入) 把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,算法便终止。 |
O(nlog(2)(n))~O(n^2) (不确定) |
O(1) (只需要一个记录的辅助空间r[0]) |
(要使增量序列中的值没有除1之外的公因子,并且在最后增量值必须等于1) 优点:①适用于初始记录无序、n较大的情况 缺点:①只能用于顺序存储结构②不稳定排序 |
|
选择类
|
简单选择排序 |
先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。 |
O(n^2) |
O(1) (两元素交换时,只需要一个记录的辅助空间) |
①稳定排序(但可能产生“不稳定现象”)②可用于链式存储结构③移动记录次数少,当每一记录占用空间较多时,该法比直接插入排序快
|
树形选择排序 |
首先对n个记录的关键字进行两两比较,然后在n/2个较小者之间再进行两两比较,如此重复,直至选出最小的记录为止。 |
O(nlog(2)(n)) |
|
缺点:①辅助存储空间较多②和“最大值”进行多余比较等缺点 |
|
堆排序 |
是一种树形选择排序,将待排序的记录r[1,n]看作一棵完全二叉树的顺序存储结构,利用其中双亲结点和孩子结点之间的内在关系,在当前的无序序列中选择最大(小)记录。 |
O(nlog(2)(n)) |
O(1) (两元素交换时,只需要一个记录的辅助空间) |
优点:①适用于初始记录无序、n较大的情况,记录较少时不适用 缺点:①只能用于顺序存储结构②不稳定排序 |
|
归并类 |
2-路归并排序 |
递归算法:反复将当前区间[left, right]分为两半,对两个子区间[left, mid]与[mid +1, right]分别递归进行归并排序,然后将两个已经有序的合并为有序序列。 |
O(nlog(2)(n)) 需要进行log(2)(n)(向上取整)躺归并排序,每一趟O(n)
|
O(n) (需要和待排序记录个数相等的辅助存储空间) |
优点:①稳定排序②可用于链式存储结构,且不需要附加存储空间,但递归实现时仍要开辟相应的递归工作栈 |
至于更详细的描述推荐参考这个网站的资料:https://www.cnblogs.com/hokky/p/8529042.html
(里面对每一种方法都进行了非常详细的描述,还有算法思路的动图jpg演示,非常清晰,简洁易懂)
二、代码实战
一开始做PTA上的作业题的时候还没有想到原来方法挺简单的,以为是要考察课本上的几个算法,然后用几个排序方法试了挺久的。后来在网上查阅了一下才发现原来可以这么简单的完成=。=,还了解并学习到了桶排序这个排序方法的简单思路。
因为每个员工的工龄在[0,50]这个区间上,所以可以开个小数组作为桶。

1 #include <iostream> 2 using namespace std; 3 4 int main() 5 { 6 int n,x; 7 cin >> n; 8 int count[51] = { 0 }; 9 for (int i = 0; i < n; i++) 10 { 11 cin >> x; 12 count[x]++; 13 } 14 for (int i = 0; i < 51; i++) 15 if (count[i]) 16 cout << i << ":" << count[i] << endl; 17 return 0; 18 }
还有实践1PTA排名汇总的算法思路,总体看起来不是很困难,用了<algorithm>头文件中的sort函数就比较简便,基本就是将考生在考场内及总体分别排名一次(记得考虑同分的情况),再将总体的数据输出。(在代码中也作了比较清晰的注释,应该会比较易懂)

1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 struct student 7 { 8 string id; //考号 9 int score; //分数 10 int position; //考点 11 int rank; // 所在考点排名 12 int total_rank; //总排名 13 }stu[30010]; 14 15 int compare(student a, student b) 16 { 17 if(a.score==b.score) 18 { 19 return a.id<b.id; 20 } 21 return a.score>b.score; 22 } 23 24 int main() 25 { 26 int N, K; 27 int num=0; 28 cin >> N; 29 30 for(int i=0;i<N;i++) 31 { 32 cin >> K; 33 for(int j=num;j<num+K;j++) 34 { 35 cin >> stu[j].id >> stu[j].score; 36 stu[j].position = i+1; 37 } 38 sort(stu+num,stu+num+K,compare); //同一考场排序 39 40 int rank = 1; 41 stu[num].rank = rank; //组中第一人排名为1 42 43 for(int t=num+1;t<K+num;t++) //确定组中排名 44 { 45 rank++; 46 if(stu[t].score==stu[t-1].score) //同分并列 47 { 48 stu[t].rank = stu[t-1].rank; 49 } 50 else 51 { 52 stu[t].rank = rank; //排名+1 53 } 54 } 55 num = num+K; //更新stu长度 56 } 57 58 sort(stu,stu+num,compare);//全部考生排序 59 60 int rank=1; 61 stu[0].total_rank = rank; 62 for(int i=1;i<num;i++) 63 { 64 rank++; 65 if(stu[i].score ==stu[i-1].score) 66 { 67 stu[i].total_rank = stu[i-1].total_rank; 68 } 69 else 70 { 71 stu[i].total_rank = rank; 72 } 73 } 74 75 cout << num << endl; 76 77 for(int i=0;i<num;i++) 78 { 79 cout << stu[i].id << " " << stu[i].total_rank << " " << stu[i].position << " " << stu[i].rank << endl; 80 } 81 82 return 0; 83 }
三、学习心得
本学期的内容已经到此结束了,我觉得让我感触很深的反而是每一次的写博客,每进行一章节的博客总结,都可以从头把内容温习一遍,这个感觉十分好,同时也可以相互学习。本章的各种排序方法是算法思路不算特别困难,但是打起代码来还是有点吃力,还有比较多的知识点要记牢、区分,希望自己在接下来的复习阶段多看看代码,掌握思路的同时也要强化临时打代码的能力。