• 常见的8种排序(含代码):插入排序、冒泡排序、希尔排序、快速排序、简单选择排序、归并排序、堆排序、基数排序


    时间复杂度O(n^2)

    1、插入排序 (Insertion Sort)

            从第一个元素开始,该元素可以认为已经被排序;取出下一个元素,在已经排序的元素序列中从后向前扫描;如果该元素(已排序)大于新元素,将该元素移到下一位置;重复步骤,直到找到已排序的元素小于或者等于新元素的位置;将新元素插入到该位置后。

    1. void insertionSort(int arr[], int n) {
    2. for (int i = 1; i < n; ++i) {
    3. int key = arr[i];
    4. int j = i - 1;
    5. while (j >= 0 && arr[j] > key) {
    6. arr[j + 1] = arr[j];
    7. --j;
    8. }
    9. arr[j + 1] = key;
    10. }
    11. }

    2、冒泡排序 (Bubble Sort)

            重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。

    1. void bubbleSort(int arr[], int n) {
    2. for (int i = 0; i < n - 1; ++i) {
    3. for (int j = 0; j < n - i - 1; ++j) {
    4. if (arr[j] > arr[j + 1]) {
    5. std::swap(arr[j], arr[j + 1]);
    6. }
    7. }
    8. }
    9. }

    3、简单选择排序 (Selection Sort)

            每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

    1. void selectionSort(int arr[], int n) {
    2. for (int i = 0; i < n - 1; i++) {
    3. int min_idx = i;
    4. for (int j = i + 1; j < n; j++) {
    5. if (arr[j] < arr[min_idx]) {
    6. min_idx = j;
    7. }
    8. }
    9. std::swap(arr[min_idx], arr[i]);
    10. }
    11. }

    时间复杂度O(nlog2n)

    4、希尔排序(Shell Sort)

            是插入排序的一种又称“缩小增量排序”,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法的基本思想是:先将整个待排序的记录序列分割成为若干子序列(由相隔某个“增量”的记录组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。
    (这里只给出增量的简化选择,实际应用中增量序列的选择会更复杂)

    1. void shellSort(int arr[], int n) {
    2. int gap = n / 2;
    3. while (gap > 0) {
    4. for (int i = gap; i < n; ++i) {
    5. int temp = arr[i];
    6. int j = i;
    7. while (j >= gap && arr[j - gap] > temp) {
    8. arr[j] = arr[j - gap];
    9. j -= gap;
    10. }
    11. arr[j] = temp;
    12. }
    13. gap /= 2;
    14. }
    15. }

    5、快速排序(Quick Sort)

            通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

    1. int partition(int arr[], int low, int high) {
    2. int pivot = arr[high];
    3. int i = (low - 1);
    4. for (int j = low; j <= high - 1; j++) {
    5. if (arr[j] < pivot) {
    6. i++;
    7. std::swap(arr[i], arr[j]);
    8. }
    9. }
    10. std::swap(arr[i + 1], arr[high]);
    11. return (i + 1);
    12. }
    13. void quickSort(int arr[], int low, int high) {
    14. if (low < high) {
    15. int pi = partition(arr, low, high);
    16. quickSort(arr, low, pi - 1);
    17. quickSort(arr, pi + 1, high);
    18. }
    19. }

    6、堆排序(Heap Sort)

            堆排序是利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或者大于)它的父节点。堆排序主要要解决两个问题:

            1)如何根据给定的序列建初始堆

             2)如何在交换掉根结点后,将剩下的结点调整为新的堆(筛选)

    1. void set(int p,int m){//小顶堆
    2. int i,j;
    3. i=p;j=i*2;
    4. while(j<=m){
    5. if(j<=m-1&&k[j]>k[j+1])//改为<
    6. j++;
    7. if(k[j]>=k[i])//改为<=,则为大顶堆
    8. break;
    9. else{
    10. swap(k[i],k[j]);
    11. i=j;
    12. j=i*2;
    13. }
    14. }
    15. }
    16. void heapSort(){
    17. int i,j;
    18. for(i=n/2;i>0;i--)//建堆
    19. set(i,n);
    20. for(i=n;i>1;i--)//排序
    21. {
    22. swap(k[i],k[1]);
    23. set(1,i-1);
    24. }
    25. }

    7、归并排序 (Merge Sort)

            归并排序采用分治法的思想,将数组分成两半,分别对它们进行排序,然后将结果合并起来。

            1)编写一个辅助函数来合并两个已排序的子数组。

            2)编写主归并排序函数,该函数将递归地分解数组,直到子数组只包含一个元素(已排序),然后合并这些子数组,直到整个数组排序完成。

    1. void merge(int arr[], int left[], int leftSize, int right[], int rightSize) {
    2. int i = 0, j = 0, k = 0;
    3. while (i < leftSize && j < rightSize) {
    4. if (left[i] <= right[j]) {
    5. arr[k++] = left[i++];
    6. } else {
    7. arr[k++] = right[j++];
    8. }
    9. }
    10. while (i < leftSize) {
    11. arr[k++] = left[i++];
    12. }
    13. while (j < rightSize) {
    14. arr[k++] = right[j++];
    15. }
    16. }
    17. void mergeSort(int arr[], int left, int right) {
    18. if (left < right) {
    19. int mid = left + (right - left) / 2;
    20. int leftSize = mid - left + 1;
    21. int rightSize = right - mid;
    22. int leftArr[leftSize], rightArr[rightSize];
    23. // 拷贝数据到临时数组
    24. for (int i = 0; i < leftSize; i++) {
    25. leftArr[i] = arr[left + i];
    26. }
    27. for (int j = 0; j < rightSize; j++) {
    28. rightArr[j] = arr[mid + 1 + j];
    29. }
    30. // 递归地对子数组进行排序
    31. mergeSort(leftArr, 0, leftSize - 1);
    32. mergeSort(rightArr, 0, rightSize - 1);
    33. // 合并两个已排序的子数组
    34. merge(arr, leftArr, leftSize, rightArr, rightSize);
    35. }
    36. }

    时间复杂度O(d(n+rd))

    8、基数排序(Radix Sort)

            基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。为了适用于负数和非整数,这里给出一个简化的版本,仅适用于非负整数,并且假设所有整数的位数相同(或可以通过填充前导零来使它们具有相同的位数)。

    1. #include <vector>
    2. #include <algorithm>
    3. void countingSort(std::vector<int>& arr, int exp) {
    4. std::vector<int> output(arr.size());
    5. std::vector<int> count(10, 0);
    6. // 存储每个桶中的元素数量
    7. for (int i = 0; i < arr.size(); i++)
    8. count[(arr[i] / exp) % 10]++;
    9. // 更改count[i],使其包含每个数字小于或等于i的数量
    10. for (int i = 1; i < 10; i++)
    11. count[i] += count[i - 1];
    12. // 构建输出数组
    13. for (int i = arr.size() - 1; i >= 0; i--) {
    14. output[count[(arr[i] / exp) % 10] - 1] = arr[i];
    15. count[(arr[i] / exp) % 10]--;
    16. }
    17. // 复制回原数组
    18. for (int i = 0; i < arr.size(); i++)
    19. arr[i] = output[i];
    20. }
    21. void radixsort(std::vector<int>& arr) {
    22. int maxVal = *std::max_element(arr.begin(), arr.end());
    23. // 找到最大数的位数
    24. int exp = 1;
    25. while (maxVal / exp > 0) {
    26. countingSort(arr, exp);
    27. exp *= 10;
    28. }
    29. }

    或者

    1. #include <iostream>
    2. #include <cmath>
    3. #include <algorithm> // 使用std::max来找到数组中的最大值
    4. // 获取数组中的最大值
    5. int getMax(int arr[], int n) {
    6. int mx = arr[0];
    7. for (int i = 1; i < n; i++) {
    8. if (arr[i] > mx) {
    9. mx = arr[i];
    10. }
    11. }
    12. return mx;
    13. }
    14. // 基数排序函数
    15. void radixsort(int arr[], int n) {
    16. // 找到数组中的最大值
    17. int maxVal = getMax(arr, n);
    18. // 基数排序使用计数排序作为子程序
    19. // 这里为了简单起见,我们假设所有的整数都是非负的
    20. // 如果有负数,需要做适当的转换
    21. // 对每一位执行计数排序
    22. for (int exp = 1; maxVal / exp > 0; exp *= 10) {
    23. int output[n]; // 输出数组
    24. int count[10] = {0}; // 计数器数组
    25. // 存储每个元素的频次
    26. for (int i = 0; i < n; i++) {
    27. int index = (arr[i] / exp) % 10;
    28. count[index]++;
    29. }
    30. // 更改count[i]的值,这样它现在包含位置i处之前的所有元素
    31. for (int i = 1; i < 10; i++) {
    32. count[i] += count[i - 1];
    33. }
    34. // 生成输出数组
    35. for (int i = n - 1; i >= 0; i--) {
    36. int index = (arr[i] / exp) % 10;
    37. output[count[index] - 1] = arr[i];
    38. count[index]--;
    39. }
    40. // 将排序后的元素复制回原数组
    41. for (int i = 0; i < n; i++) {
    42. arr[i] = output[i];
    43. }
    44. }
    45. }
    46. int main() {
    47. int arr[] = {170, 45, 75, 90, 802, 24, 2, 66};
    48. int n = sizeof(arr) / sizeof(arr[0]);
    49. radixsort(arr, n);
    50. std::cout << "Sorted array: \n";
    51. for (int i = 0; i < n; i++) {
    52. std::cout << arr[i] << " ";
    53. }
    54. std::cout << std::endl;
    55. return 0;
    56. }

    28edbba515494195b2405823ebde7468.png

  • 相关阅读:
    Makefile中的变量
    FreeRTOS创建任务-简要
    jenkins介绍
    C#常用的快捷键
    时序数据库
    ros rviz显示orb-slam2保存的轨迹
    【云原生K8S】Kubernetes资源管理
    【流式传输】使用Spring Boot实现ChatGpt流式传输
    LeetCode1013
    神经网络解决哪些问题,神经网络结果不稳定
  • 原文地址:https://blog.csdn.net/aw2371/article/details/139884567