数据结构第八章学习小结

一、学习内容小结

 

 排序可分为两大类:

 内部排序(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 }
View Code

 

还有实践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 }
View Code

 

三、学习心得

本学期的内容已经到此结束了,我觉得让我感触很深的反而是每一次的写博客,每进行一章节的博客总结,都可以从头把内容温习一遍,这个感觉十分好,同时也可以相互学习。本章的各种排序方法是算法思路不算特别困难,但是打起代码来还是有点吃力,还有比较多的知识点要记牢、区分,希望自己在接下来的复习阶段多看看代码,掌握思路的同时也要强化临时打代码的能力。

posted @ 2020-07-12 14:28  冯颖欣  阅读(209)  评论(0编辑  收藏  举报