目录
4.1.2各种排序算法什么时候有最好情况、最坏情况(尤其是快排) ⭐⭐⭐⭐
4.1.9快排的partition函数与归并的Merge函数⭐⭐⭐
4.2.2 vector内存是怎么增长的vector的底层实现⭐⭐⭐⭐
4.2.4为什么stl里面有sort函数list里面还要再定义一个sort⭐⭐⭐
4.1 排序算法
-
4.1.1各种排序算法的时间空间复杂度、稳定性⭐⭐⭐⭐⭐
-
4.1.2各种排序算法什么时候有最好情况、最坏情况(尤其是快排) ⭐⭐⭐⭐
-
4.1.3冒泡排序⭐⭐⭐⭐
1. // 冒泡排序 相邻2个元素 相互比较,直到最后 然后重新开始。
2. void BubbleSort(int a[], int len) {
3. int tmp;
4. int exchange = 1;
5. for (int i = 0; (i < len - 1) && (exchange > 0); i++) {
6. exchange = 0;
7. for (int j = 0; j < len - 1 - i; j++) {
8. if (a[j] > a[j + 1]) {
9. tmp = a[j];
10. a[j] = a[j + 1];
11. a[j + 1] = tmp;
12. exchange = 1;
13. }
14. }
15. }
16. }
17.
-
4.1.4选择排序⭐⭐⭐⭐
1. //选择排序
2. //稳定性最好的排序之一,时间复杂度为O(n2) 规模越小越好,不占用额外空间
3. //在未排序中找最小的,放到起始位置,然后再找最小放到第二位置
4. void SelectSort(int a[], int len) {
5. for (int i = 0; i < len; i++) {
6. int minindex = i;
7. for (int j = i + 1; j < len; j++) {
8. if (a[minindex] > a[j]) {
9. minindex = j;
10. }
11. }
12. swap(a[i],a[minindex]);
13. }
14. }
15.
-
4.1.5插入排序⭐⭐⭐⭐
1. //插入排序
2. //拿出一个数和前面的数进行比较,遇到不比它大的数字,插入其中
3. void InsertSort(int a[],int len) {
4. int tmp;
5. for (int i = 0; i < len; i++) {
6. tmp = a[i];
7. int k = i; // 记录插入的位置
8. for (int j = i-1; (j >= 0) && (a[j] > tmp); j--) {
9. a[j + 1] = a[j];
10. k = j;
11. }
12. a[k] = tmp;
13. }
14. }
15.
-
4.1.6希尔排序⭐⭐⭐⭐
1. //希尔排序
2. //解决 最大值在第一位 需要移动n-1个位置
3. void ShellSort(int a[], int n) {
4. int gap = n;
5. int tmp;
6. while (gap > 1) {
7. gap = gap / 3 + 1;
8. for (int i = gap; i < n; i += gap) {
9. int k = i;
10. tmp = a[i];
11. for (int j = i -gap; (j >= 0) && (a[j] > tmp); j -= gap) {
12. a[j + 1] = a[j];
13. k = j;
14. }
15. a[k] = tmp;
16. }
17. }
18. }
19.
-
4.1.7归并排序⭐⭐⭐⭐
1. //归并排序
2. //即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表。
3. //把长度为n的输入序列分成两个长度为n/2的子序列;对这两个子序列分别采用归并排序;将两个排序好的子序列合并成一个最终的排序序列。
4.
5. //首先假设2个数组是有序的,按照有序序列进行合并,组成有序序列
6. void merge(int a[],int low ,int mid,int high, int tmp[]) {
7. int i = low; //左子数组开始的位置
8. int j = mid + 1; //右子数组开始的位置
9. int t = 0; //临时空间指针
10. //首先 判断要合并的数组的起始位置的大小,然后将数组复制到tmp数组存储。
11. // 比较2个数组的每个元素 然后按照大小顺序进行排序。
12. while (i <= mid && j <= high) {
13. if (a[i] < a[j]) {
14. tmp[t++] = a[i++];
15. }
16. else
17. tmp[t++] = a[j++];
18. }
19. //参考https://www.bilibili.com/video/BV1Pt4y197VZ?from=search&seid=6438701192248743313
20. //如果右半区就一个元素,上述放好位置后,左半区的元素直接放就好
21. //将左边剩余元素填充进temp中
22. while (i <= mid) {
23. tmp[t++] = a[i++];
24. }
25. //将右边子数组剩余部分填充到temp中
26. while (j <= high) {
27. tmp[t++] = a[j++];
28. }
29. //将融合后的数据拷贝到原来的数据对应的子空间中
30. t = 0;
31. while (low <= high) {
32. a[low++] = tmp[t++];
33. }
34. }
35. void Msort(int a[], int low, int high, int tmp[]) {
36. if (low < high) {
37. int mid = (low + high) / 2;
38. //递归划分左半区
39. Msort(a,low,mid,tmp);
40. //递归划分右半区
41. Msort(a,mid + 1,high,tmp);
42. //合并左右半区
43. merge(a,low,mid,high,tmp);
44. }
45. }
46.
-
4.1.8快速排序⭐⭐⭐⭐⭐
1. //快速排序
2. //选出一个数作为基准,使得数组左边的小于基准,右边的大于基准
3. //递归划分
4.
5. //划分函数
6. int partion(int a[], int low, int high) {
7. //选择第一个元素作为标准
8. int index = a[low];
9. //推动左右指针向中间移动,
10. while (low < high) {
11. //如果右边的数比标准大,不用移动,否则交换到左边
12. while ((low < high) && a[high] >= index) {
13. high--;
14. }
15. while ((low < high) && a[low] <= index) {
16. low++;
17. }
18. swap(a[low],a[high]);
19. }
20.
21. }
22.
23. void Qsort(int a[], int low,int high) {
24. if (low < high) {
25. int index = partion(a,low,high);
26. //递归划分
27. Qsort(a,low,index - 1);
28. Qsort(a,index,high);
29. }
30. }
31.
排序算法 | 平均时间复杂度 | 最好情况 | 最坏情况 | 空间复杂度 | 排序方式 | 稳定性 |
冒泡排序 | O(n²) | O(n) | O(n²) | O(1) | In--place | 稳定 |
选择排序 | O(n²) | O(n²) | O(n²) | O(1) | In--place | 不稳定 |
插入排序 | O(n²) | O(n²) | O(n²) | O(1) | In--place | 稳定 |
希尔排序 | O(nlog n) | O(nlog² n) | O(nlog² n) | O(1) | In--place | 不稳定 |
归并排序 | O(nlog n) | O(nlog n) | O(nlog n) | O(n) | Out--place | 稳定 |
堆排序 | O(nlog n) | O(nlog n) | O(nlog n) | O(1) | In--place | 不稳定 |
快速排序 | O(nlog n) | O(nlog n) | O(n²) | O(log n) | In--place | 不稳定 |
名称 | 数据对象 | 稳定性 | 时间复杂度 | 额外空间复杂度 | 描述 | |
平均 | 最坏 | |||||
冒泡排序 | 数组 | √ | O(n²) | O(1) | 从无序区通过交换找出最大元素放到有序区 | |
选择排序 | 数组 | × | O(n²) | O(1) | 在无序区里找一个最小的元素跟在有序区的后面,对数组比较多换的少 | |
链表 | √ | |||||
插入排序 | 数组、链表 | √ | O(n²) | O(1) | 把无序区的第一个元素插入到有序区的合适的位置,对数组比较的少,换的多 | |
堆排序 | 数组 | × | O(nlogn) | O(1) | 从堆顶把根卸出来放在有序区之前,再恢复堆 | |
归并排序 | 数组 | √ | O(nlog²n) | O(1) | 把数据分为两段,从两端中逐个选择最小的元素移入新数据段的末尾,可从上到下或从下到上运行 | |
链表 | O(nlogn) | O(n)+O(logn) 如果不是从下到上 | ||||
O(1) | ||||||
快速排序 | 数组 | × | O(nlogn) | O(n²) | O(logn) | 在区间中随机选取一个元素作为基准,将小于基准的元素放在基准之前,大于基准的元素放在基准之后,再分别对小数区和大数区进行排序 |
希尔排序 | 数组 | × | O(nlog²n) | O(n²) | O(1) | 每一轮按照事先决定的间隔进行插入排序,间隔会依次缩小,最后一次一定要是1。 |
-
4.1.9快排的partition函数与归并的Merge函数⭐⭐⭐
-
4.2 STL库相关
-
4.2.1 vector list异同⭐⭐⭐⭐⭐
-
4.2.2 vector内存是怎么增长的vector的底层实现⭐⭐⭐⭐
-
4.2.3 vector和deque的比较⭐⭐⭐⭐
-
4.2.4为什么stl里面有sort函数list里面还要再定义一个sort⭐⭐⭐
-
4.2.5 STL底层数据结构实现⭐⭐⭐⭐
-
4.2.6利用迭代器删除元素会发生什么?⭐⭐⭐⭐
-
4.2.7 map是如何实现的,查找效率是多少⭐⭐⭐⭐⭐
-
4.2.8几种模板插入的时间复杂度 ⭐⭐⭐⭐⭐