当前位置:   article > 正文

数据结构笔记--十大经典排序算法(C++)_数据结构-十大经典排序算法

数据结构-十大经典排序算法

目录

1--概述

2--冒泡排序

3--选择排序

4--插入排序

5--希尔排序

6--快速排序

7--归并排序

8--堆排序

9--计数排序

10--基数排序

11--桶排序


1--概述

        十大经典排序算法包括:冒泡排序、选择排序、插入排序、希尔排序、快速排序、归并排序、堆排序、计数排序、基数排序 和 桶排序;

2--冒泡排序

主要思想:视频讲解参考

        每次将最大的元素移动到最后;

        时间复杂度为 O (n^2);

  1. #include <iostream>
  2. #include <vector>
  3. #include <queue>
  4. class Solution{
  5. public:
  6. // 冒泡排序
  7. void bubSort(std::vector<int> &input){
  8. int len = input.size();
  9. while(--len){ // len 一开始指向最后一个元素
  10. for(int i = 0; i < len; i++){
  11. if(input[i] > input[i + 1]){
  12. int tmp = input[i];
  13. input[i] = input[i + 1];
  14. input[i + 1] = tmp;
  15. }
  16. }
  17. }
  18. }
  19. // 优化的冒泡排序
  20. void Better_bubSort(std::vector<int> &input){
  21. int len = input.size();
  22. int flag = 1;
  23. while(--len && flag){ // 当前面的已有序,即上一轮没有发生交换,就不会进入循环体
  24. flag = 0;
  25. for(int i = 0; i < len; i++){
  26. if(input[i] > input[i + 1]){
  27. flag = 1;
  28. int tmp = input[i];
  29. input[i] = input[i + 1];
  30. input[i + 1] = tmp;
  31. }
  32. }
  33. }
  34. }
  35. // 打印函数
  36. void Print(const std::vector<int>& input){
  37. for(int item : input){
  38. std::cout << item << " ";
  39. }
  40. std::cout << std::endl;
  41. }
  42. };
  43. int main(int argc, char *argv[]){
  44. std::vector<int> input = {1, 3, 6, 4, 2, 5};
  45. Solution S1;
  46. std::cout << "Before Sort: " << std::endl;
  47. S1.Print(input);
  48. std::cout << "After Sort: " << std::endl;
  49. S1.bubSort(input);
  50. S1.Print(input);
  51. return 0;
  52. }

3--选择排序

主要思想:视频讲解参考

        选择排序基于冒泡排序的思想,每一轮找到最小值(用 k 指向),将最小值与循环的第一个数(用 i 指向)交换,这样可以确保每一轮将最小值选择排序到前面;

        时间复杂度为 O (n^2);

  1. #include <iostream>
  2. #include <vector>
  3. #include <queue>
  4. class Solution{
  5. public:
  6. // 选择排序
  7. void selectSort(std::vector<int>& input){
  8. int len = input.size();
  9. int k = 0; // 指向本次循环最小值的位置
  10. for(int i = 0; i < len; i++){
  11. k = i;
  12. for(int j = i + 1; j < len; j++){
  13. if(input[j] < input[k]) k = j; // 更新本次循环最小值的位置
  14. }
  15. int tmp = input[i];
  16. input[i] = input[k]; // 最小值的位置移动到前面
  17. input[k] = tmp;
  18. }
  19. }
  20. // 打印函数
  21. void Print(const std::vector<int>& input){
  22. for(int item : input){
  23. std::cout << item << " ";
  24. }
  25. std::cout << std::endl;
  26. }
  27. };
  28. int main(int argc, char *argv[]){
  29. std::vector<int> input = {1, 3, 6, 4, 2, 5};
  30. Solution S1;
  31. std::cout << "Before Sort: " << std::endl;
  32. S1.Print(input);
  33. std::cout << "After Sort: " << std::endl;
  34. S1.selectSort(input);
  35. S1.Print(input);
  36. return 0;
  37. }

4--插入排序

主要思想:视频讲解参考

        遍历每一个元素,将其插入到前面已经排好序的序列中,即与前面的数逐一比较,直到找到比其小的数,将元素插入到其后面;

        时间复杂度为 O (n^2);

  1. #include <iostream>
  2. #include <vector>
  3. #include <queue>
  4. class Solution{
  5. public:
  6. // 插入排序
  7. void insertSort(std::vector<int>& input){
  8. int len = input.size();
  9. int key; // key表示本次循环中要插入的值
  10. for(int i = 1; i < len; i++){ // i 从 1 开始,因为input[0]已经是有序的
  11. key = input[i];
  12. int j = i-1; // 从前一个数开始比较
  13. while(j >= 0 && key < input[j]){ // 向前寻找,直到找到第一个比 key 小的数
  14. input[j+1] = input[j]; // 比较过的元素向后移动,因为要空出一个位置
  15. j--; // 继续向前寻找
  16. }
  17. input[j+1] = key; // 将 key 插入到第一个比它小的数的后面
  18. }
  19. }
  20. // 打印函数
  21. void Print(const std::vector<int>& input){
  22. for(int item : input){
  23. std::cout << item << " ";
  24. }
  25. std::cout << std::endl;
  26. }
  27. };
  28. int main(int argc, char *argv[]){
  29. std::vector<int> input = {1, 3, 6, 4, 2, 5};
  30. Solution S1;
  31. std::cout << "Before Sort: " << std::endl;
  32. S1.Print(input);
  33. std::cout << "After Sort: " << std::endl;
  34. S1.insertSort(input);
  35. S1.Print(input);
  36. return 0;
  37. }

5--希尔排序

主要思想:视频讲解参考

        希尔排序是插入排序的进阶版,实质上是使用多次插入排序,只是每次插入比较的步长是step,当 step 为1时,希尔排序就退化为普通的插入排序;

        希尔排序主要应用在数据量很大的排序问题中,本质上是减少交换的次数,因为当 step 退化为 1 时,序列已经大部分是有序的,所以交换的次数很少。

        希尔排序的时间复杂度为:O(n^(1.3--2)),是一种不稳定的排序;

  1. #include <iostream>
  2. #include <vector>
  3. #include <queue>
  4. class Solution{
  5. public:
  6. // 希尔排序
  7. void shellSort(std::vector<int>& input){
  8. int len = input.size();
  9. //初始比较的 step 为 len/2,每一轮退化为 step/2;
  10. for(int step = len / 2; step > 0; step = step / 2){
  11. // 每一轮使用插入排序
  12. for(int i = step; i < len; i++){
  13. int key = input[i]; // 要插入的数
  14. int j = i - step; // 与前一个数进行比较
  15. while(j >= 0 && key < input[j]){
  16. input[j + step] = input[j];
  17. j = j - step; // 不断前移
  18. }
  19. input[j + step] = key;
  20. }
  21. }
  22. }
  23. // 打印函数
  24. void Print(const std::vector<int>& input){
  25. for(int item : input){
  26. std::cout << item << " ";
  27. }
  28. std::cout << std::endl;
  29. }
  30. };
  31. int main(int argc, char *argv[]){
  32. std::vector<int> input = {1, 3, 6, 4, 2, 5};
  33. Solution S1;
  34. std::cout << "Before Sort: " << std::endl;
  35. S1.Print(input);
  36. std::cout << "After Sort: " << std::endl;
  37. S1.shellSort(input);
  38. S1.Print(input);
  39. return 0;
  40. }

6--快速排序

主要思路:

        每次选定一个基准轴元素 (pivot),从两边开始扫描,比 pivot 小的元素放在轴的左边,比 pivot 大的元素放在轴的右边;

        经过一次遍历之后,pivot 左边的元素都比 pivot 小,pivot 右边的元素都比 pivot 大,这样对于最终的结果来说,pivot 所在的位置是排好序的,只需递归排序 pivot 左边的元素和右边的元素即可;

        快速排序的时间复杂度为:O(nlogn) ~ O(n^2)

  1. #include <iostream>
  2. #include <vector>
  3. #include <queue>
  4. class Solution{
  5. public:
  6. // 快速排序
  7. void quickSort(std::vector<int>& input, int left, int right){
  8. if(left >= right) return; // 递归结束条件
  9. int len = input.size();
  10. int pivot = input[left]; // 记录基准轴元素
  11. int i = left, j = right;
  12. while(i < j){
  13. while(i < j && input[j] >= pivot) j--; // 从右往左扫描直到找到第一个比 pivot 小的元素停下
  14. input[i] = input[j]; // 将小的数放到 pivot 的左边
  15. while(i < j && input[i] <= pivot) i++; // 从左往右扫描直到找到第一个比 pivot 大的元素停下
  16. input[j] = input[i]; // 将大的数放到 pivot 的右边
  17. }
  18. // 一趟遍历之后,将基准元素 pivot 放在 i 的位置(i == j)
  19. input[i] = pivot;
  20. // 递归排序pivot左边的元素和右边的元素
  21. quickSort(input, left, i - 1);
  22. quickSort(input, i+1, right);
  23. }
  24. // 打印函数
  25. void Print(const std::vector<int>& input){
  26. for(int item : input){
  27. std::cout << item << " ";
  28. }
  29. std::cout << std::endl;
  30. }
  31. };
  32. int main(int argc, char *argv[]){
  33. std::vector<int> input = {1, 3, 6, 4, 2, 5};
  34. Solution S1;
  35. std::cout << "Before Sort: " << std::endl;
  36. S1.Print(input);
  37. std::cout << "After Sort: " << std::endl;
  38. S1.quickSort(input, 0, input.size()-1);
  39. S1.Print(input);
  40. return 0;
  41. }

7--归并排序

        普通归并排序将两个有序的序列归并为一个有序的新序列视频讲解

  1. #include <iostream>
  2. #include <vector>
  3. class Solution{
  4. public:
  5. std::vector<int> mergeSort(std::vector<int> input1, std::vector<int> input2){
  6. std::vector<int> Res;
  7. int i = 0, j = 0;
  8. while(i < input1.size() && j < input2.size()){
  9. if(input1[i] < input2[j]){
  10. Res.push_back(input1[i]);
  11. i++;
  12. }
  13. else{
  14. Res.push_back(input2[j]);
  15. j++;
  16. }
  17. }
  18. while(i < input1.size()){
  19. Res.push_back(input1[i]);
  20. i++;
  21. }
  22. while(j < input2.size()){
  23. Res.push_back(input2[j]);
  24. j++;
  25. }
  26. return Res;
  27. }
  28. // 打印函数
  29. void Print(const std::vector<int>& input){
  30. for(int item : input){
  31. std::cout << item << " ";
  32. }
  33. std::cout << std::endl;
  34. }
  35. };
  36. int main(int argc, char *argv[]){
  37. std::vector<int> input1 = {1, 3, 4, 6};
  38. std::vector<int> input2 = {2, 5, 7, 8};
  39. Solution S1;
  40. std::cout << "Before Sort: " << std::endl;
  41. S1.Print(input1);
  42. S1.Print(input2);
  43. std::cout << "After Sort: " << std::endl;
  44. std::vector<int> output = S1.mergeSort(input1, input2);
  45. S1.Print(output);
  46. return 0;
  47. }

        进阶归并排序将一个无序的序列归并排序为一个有序的系列;通过递归将无序的序列二分,从底层开始将二分的序列归并排序为有序序列;

  1. #include <iostream>
  2. #include <vector>
  3. class Solution{
  4. public:
  5. // 归并排序
  6. std::vector<int> mergeSort(std::vector<int> input){
  7. std::vector<int> Res = split(input, 0, input.size() - 1);
  8. return Res;
  9. }
  10. // 二分序列
  11. std::vector<int> split(std::vector<int> input, int left, int right){
  12. if(left == right){ // 只剩下一个元素,返回由该元素构成的有序序列
  13. std::vector<int> Res = {input[left]};
  14. return Res;
  15. }
  16. int mid = left + (right - left) / 2;
  17. std::vector<int> input1 = split(input, left, mid);
  18. std::vector<int> input2 = split(input, mid+1, right);
  19. std::vector<int> Res = merge(input1, input2); // 二分至底层,进行归并排序再回溯
  20. return Res;
  21. }
  22. // 将两个有序的序列归并排序
  23. std::vector<int> merge(std::vector<int> input1, std::vector<int> input2){
  24. std::vector<int> Res;
  25. int i = 0, j = 0;
  26. while(i < input1.size() && j < input2.size()){
  27. if(input1[i] < input2[j]){
  28. Res.push_back(input1[i]);
  29. i++;
  30. }
  31. else{
  32. Res.push_back(input2[j]);
  33. j++;
  34. }
  35. }
  36. while(i < input1.size()){
  37. Res.push_back(input1[i]);
  38. i++;
  39. }
  40. while(j < input2.size()){
  41. Res.push_back(input2[j]);
  42. j++;
  43. }
  44. return Res;
  45. }
  46. // 打印函数
  47. void Print(const std::vector<int>& input){
  48. for(int item : input){
  49. std::cout << item << " ";
  50. }
  51. std::cout << std::endl;
  52. }
  53. };
  54. int main(int argc, char *argv[]){
  55. std::vector<int> input = {1, 4, 6, 3, 5, 2, 8, 7, 10, 9, 11, 12};
  56. Solution S1;
  57. std::cout << "Before Sort: " << std::endl;
  58. S1.Print(input);
  59. std::cout << "After Sort: " << std::endl;
  60. std::vector<int> output = S1.mergeSort(input);
  61. S1.Print(output);
  62. return 0;
  63. }

8--堆排序

关于堆的知识:从堆的定义到优先队列、堆排序(强烈推荐)

堆排序基本知识:视频讲解参考

        ① 堆排序中的堆分为大根堆小根堆,小根堆中孩子结点的值必须大于父亲结点的值(即堆顶是最小值),大根堆中孩子结点的值必须小于父亲结点的值(即堆顶是最大值);

        ② 大根堆和小根堆本质上是一个完全二叉树,满足以下性质:结点连续存储,假设结点从0开始编号,则左孩子的位置为 2*parent + 1,右孩子的位置为 2*parent + 2;

        ③ (外堆且基于小顶堆)堆排序本质上分为入堆出堆两步:

        入堆时新加入结点,结点需要自底向上与父亲结点进行比较,重构大根堆和小根堆,确保满足上面的性质;

        出堆时返回堆顶元素,并将最后一个元素放在堆顶位置,自顶向下与较小的孩子结点进行比较,重构大根堆和小根堆,确保满足上面的性质;

  1. #include <iostream>
  2. #include <vector>
  3. #include <queue>
  4. class Solution{
  5. public:
  6. void heapSort(std::vector<int>& input){
  7. int size = input.size();
  8. // 入堆
  9. for(int data : input){
  10. pushHeap(data);
  11. }
  12. // 出堆
  13. for(int i = 0; i < size; i++){
  14. input[i] = popheap();
  15. }
  16. }
  17. // 入堆
  18. void pushHeap(int data){
  19. if(len == 0){
  20. heap.push_back(data); // 入堆
  21. len++;
  22. return;
  23. }
  24. heap.push_back(data); // 入堆
  25. len++; // 元素个数 +1
  26. // 重新排序堆
  27. int cur = len - 1; // 当前堆中最后一个元素的位置
  28. int parent = (cur-1) / 2; // 父亲节点的位置
  29. while(parent != cur){ // 直到根节点
  30. if(heap[cur] < heap[parent]){
  31. swap(cur, parent); // 交换两个位置的值
  32. cur = parent;
  33. parent = (cur-1) / 2; // 从下往上比较,不断交换
  34. }
  35. else break;
  36. }
  37. }
  38. // 出堆
  39. int popheap(){
  40. int res = heap[0]; // 堆顶元素
  41. int cur = len - 1; // 最后一个元素的位置
  42. heap[0] = heap[cur]; // 最后一个元素的位置放到堆顶中
  43. len--; // 堆中元素 -1
  44. // 重新排序堆
  45. int start = 0;
  46. while(start <= len){ // 从根节点开始排序
  47. int l_child = 2*start+1;
  48. int r_child = 2*start+2;
  49. if(l_child > len || r_child > len) break; // 防止溢出
  50. int small = heap[l_child] < heap[r_child] ? l_child : r_child; // 较小的孩子
  51. if (heap[small] < heap[start]){ // 从上到下与较小的孩子交换位置
  52. swap(small, start);
  53. start = small;
  54. }
  55. else break;
  56. }
  57. return res;
  58. }
  59. void swap(int index1, int index2){
  60. int temp = heap[index1];
  61. heap[index1] = heap[index2];
  62. heap[index2] = temp;
  63. }
  64. // 打印函数
  65. void Print(const std::vector<int>& input){
  66. for(int item : input){
  67. std::cout << item << " ";
  68. }
  69. std::cout << std::endl;
  70. }
  71. private:
  72. std::vector<int> heap; // 小顶堆
  73. int len = 0; // 堆中元素的个数
  74. };
  75. int main(int argc, char *argv[]){
  76. std::vector<int> input = {1, 3, 6, 4, 2, 5, 8, 7, 10, 9};
  77. Solution S1;
  78. std::cout << "Before Sort: " << std::endl;
  79. S1.Print(input);
  80. std::cout << "After Sort: " << std::endl;
  81. S1.heapSort(input);
  82. S1.Print(input);
  83. return 0;
  84. }

9--计数排序

        在计数排序中,用一个数组的下标表示原数组的真值,数组下标对应的值表示真值出现的次数;遍历记录的数组,当下标对应的值不为0时,输入其下标(值多大就输出多少次);

        在 C++ 中可以通过哈希表的形式来实现计数排序,key 表示原数组的真值,value 表示真值出现的次数;

        经典利用数组实现计数排序可以参考视频讲解

  1. #include <iostream>
  2. #include <vector>
  3. #include <map>
  4. class Solution{
  5. public:
  6. std::vector<int> countSort(std::vector<int> input){
  7. for(int item : input){ // 遍历每一个数
  8. M.insert(std::pair<int, int>(item, M.count(item)+1));
  9. }
  10. for(auto item : M){ // map自动根据key排好序了,因此直接遍历即可
  11. int num = item.second; // 出现的次数
  12. while(num != 0){
  13. Res.push_back(item.first);
  14. num--;
  15. }
  16. }
  17. return Res;
  18. }
  19. // 打印函数
  20. void Print(const std::vector<int>& input){
  21. for(int item : input){
  22. std::cout << item << " ";
  23. }
  24. std::cout << std::endl;
  25. }
  26. private:
  27. std::map<int, int> M; // <真值,出现的次数>
  28. std::vector<int> Res;
  29. };
  30. int main(int argc, char *argv[]){
  31. std::vector<int> input = {1, 3, 6, 4, 2, 5, 8, 7, 10, 9};
  32. Solution S1;
  33. std::cout << "Before Sort: " << std::endl;
  34. S1.Print(input);
  35. std::cout << "After Sort: " << std::endl;
  36. std::vector<int> output = S1.countSort(input);
  37. S1.Print(output);
  38. return 0;
  39. }

10--基数排序

        在基数排序中,对每一个数依次按照个位、十位、百位 ... 来排序,对最高位排序后即为有序结果,返回即可;

11--桶排序

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/966107
推荐阅读
相关标签
  

闽ICP备14008679号