• 【数据结构】归并排序、基数排序算法的学习知识点总结


     目录

    1、归并排序

            1.1 算法思想

            1.2 代码实现

            1.3 例题分析

    2、基数排序

            2.1 算法思想

            2.2 代码实现

            2.3 例题分析


    1、归并排序

    1.1 算法思想

            归并排序是一种采用分治思想的经典排序算法,通过将待排序数组分成若干个子序列,将每个子序列排序,最终合并成一个有序序列。其基本思路可以归纳为以下三个步骤:

    1. 分治:将待排序数组递归地分成两个子序列,直到每个子序列中只有一个元素;
    2. 合并:将两个有序子序列合并成一个有序序列,直到合并成一个完整的有序序列;
    3. 递归:重复以上两个步骤,直到排序完成。

            具体实现过程中,可以采取自上而下或自下而上的方式进行归并排序。其中,自下而上的归并排序首先将整个数组划分成若干个大小为1的子数组,然后将相邻两个子数组合并成一个有序数组,逐渐扩大有序数组的长度,直到整个数组有序。

            归并排序算法的时间复杂度为 O(nlogn),具有稳定性,适用于对大规模数据进行排序。

    1.2 代码实现

    归并排序(Merge Sort)是一种分治思想的排序算法,它的核心思想是将待排序的序列分成若干子序列,分别排序,然后合并。

    C语言实现归并排序的代码如下:

    1. #include
    2. #include
    3. void merge(int arr[], int l, int m, int r) {
    4. int i, j, k;
    5. int n1 = m - l + 1;
    6. int n2 = r - m;
    7. // 创建左右子数组
    8. int L[n1], R[n2];
    9. // 将数据复制到左右子数组中
    10. for (i = 0; i < n1; i++) {
    11. L[i] = arr[l + i];
    12. }
    13. for (j = 0; j < n2; j++) {
    14. R[j] = arr[m + 1 + j];
    15. }
    16. // 将左右子数组合并到 arr 中
    17. i = 0;
    18. j = 0;
    19. k = l;
    20. while (i < n1 && j < n2) {
    21. if (L[i] <= R[j]) {
    22. arr[k] = L[i];
    23. i++;
    24. } else {
    25. arr[k] = R[j];
    26. j++;
    27. }
    28. k++;
    29. }
    30. // 处理剩余元素
    31. while (i < n1) {
    32. arr[k] = L[i];
    33. i++;
    34. k++;
    35. }
    36. while (j < n2) {
    37. arr[k] = R[j];
    38. j++;
    39. k++;
    40. }
    41. }
    42. void mergeSort(int arr[], int l, int r) {
    43. if (l < r) {
    44. int m = l + (r - l) / 2;
    45. // 分别对左右子数组进行排序
    46. mergeSort(arr, l, m);
    47. mergeSort(arr, m + 1, r);
    48. // 将左右子数组合并
    49. merge(arr, l, m, r);
    50. }
    51. }
    52. int main() {
    53. int arr[] = {5, 1, 4, 2, 8, 0, 2};
    54. int n = sizeof(arr) / sizeof(arr[0]);
    55. printf("Original array: \n");
    56. for (int i = 0; i < n; i++) {
    57. printf("%d ", arr[i]);
    58. }
    59. // 执行归并排序
    60. mergeSort(arr, 0, n - 1);
    61. printf("\nSorted array: \n");
    62. for (int i = 0; i < n; i++) {
    63. printf("%d ", arr[i]);
    64. }
    65. return 0;
    66. }

            在这段代码中,merge() 函数用于合并左右子数组,mergeSort() 函数用于对左右子数组进行排序并合并。在 main() 函数中,我们创建了一个待排序的整数数组,然后调用 mergeSort() 函数对其进行排序,并输出排序后的结果。

    1.3 例题分析

    假设我们有一个无序数组[10, 5, 2, 7, 6, 4, 3, 8, 9, 1],要使用归并排序对其进行排序。下面是具体步骤:

    1. 首先将数组不断分成两半,直到每个子数组只有一个元素为止。

    [10, 5, 2, 7, 6, 4, 3, 8, 9, 1] -> [10, 5, 2, 7, 6] [4, 3, 8, 9, 1] -> [10, 5] [2, 7, 6] [4, 3] [8, 9, 1] -> [10] [5] [2] [7] [6] [4] [3] [8] [9] [1]
    

    2. 接着,将相邻的两个子数组合并,并按顺序排序。

    1. [10] [5] -> [5, 10]
    2. [2] [7] [6] -> [2, 6, 7]
    3. [4] [3] -> [3, 4]
    4. [8] [9] [1] -> [1, 8, 9]

    3. 重复步骤2,直到最终将所有子数组合并成为一个有序数组。

    [5, 10] [2, 6, 7] [3, 4] [1, 8, 9] -> [2, 3, 4, 5, 6, 7, 8, 9, 10]
    

    4. 最终得到的有序数组为[2, 3, 4, 5, 6, 7, 8, 9, 10]。可以看出,归并排序的时间复杂度为O(nlogn),且不会破坏原有数组的顺序。

    2、基数排序

    2.1 算法思想

    基数排序是一种非比较排序算法,根据关键字的每一位来排序,最终得到有序序列。其基本思想是将待排序的元素按照其每一位的值,将其分配到对应的桶中,然后按照桶的顺序依次取出元素,即可得到有序序列。

    具体实现步骤如下:

    1. 将所有待排序数按照个位数的值依次放入相应的桶中。

    2. 按照桶的顺序依次取出每个桶中的元素,将其按照一位数的大小依次放回原数组中。

    3. 对于十位数、百位数等同理,直到最高位数。

    4. 最终得到有序序列。

                    需要注意的是,基数排序算法的空间复杂度较高,需要额外的空间来存储桶和中间结果。在实际应用中,需要权衡算法的时间复杂度和空间复杂度,选择合适的算法。

    2.2 代码实现

    以下是一个基数排序的实现,它将一组数字按位数从低到高排序,每次排序都利用计数排序算法进行。

    1. #include
    2. #include
    3. using namespace std;
    4. // 计数排序算法,用于将整数数组按某一位进行排序
    5. void countingSort(vector<int>& arr, int exp)
    6. {
    7. vector<int> output(arr.size());
    8. vector<int> count(10, 0);
    9. // 统计每个数字出现的次数
    10. for (int i = 0; i < arr.size(); i++)
    11. count[(arr[i] / exp) % 10]++;
    12. // 累加计数数组,求出每个数字在排序后的数组中的位置
    13. for (int i = 1; i < 10; i++)
    14. count[i] += count[i - 1];
    15. // 根据计数数组中的位置,将数字放置到排序后的数组中
    16. for (int i = arr.size() - 1; i >= 0; i--)
    17. {
    18. output[count[(arr[i] / exp) % 10] - 1] = arr[i];
    19. count[(arr[i] / exp) % 10]--;
    20. }
    21. // 将排序后的数组复制到原始数组中
    22. for (int i = 0; i < arr.size(); i++)
    23. arr[i] = output[i];
    24. }
    25. // 基数排序算法
    26. void radixSort(vector<int>& arr)
    27. {
    28. int max = *max_element(arr.begin(), arr.end());
    29. // 从低位到高位依次进行排序
    30. for (int exp = 1; max / exp > 0; exp *= 10)
    31. countingSort(arr, exp);
    32. }
    33. int main()
    34. {
    35. vector<int> arr = { 170, 45, 75, 90, 802, 24, 2, 66 };
    36. radixSort(arr);
    37. for (int i = 0; i < arr.size(); i++)
    38. cout << arr[i] << " ";
    39. return 0;
    40. }

    2.3 例题分析

            基数排序是一种非比较排序算法,其基本思想是将待排序的数据按照位数划分为不同的数字位,然后依次对每一位进行排序。

            例如,对于一个无序数组[753, 584, 626, 901, 321],经过一轮排序后,按照个位数字的大小,可以得到以下排列:[901, 321, 753, 584, 626],此时数组已经按照个位数字排好序了。

            接下来,我们再按照十位数字的大小对这个序列进行排序,排完之后得到的序列为:[321, 584, 626, 901, 753]。

            最后,再按照百位数字的大小进行排序就可以得到最终的有序数组:[321, 584, 626, 753, 901]。

            基数排序的时间复杂度是O(d*(n+k)),其中d为位数,n为元素个数,k为数字范围。因此,当数字范围较小且位数不多时,基数排序的效率较高,但如果数字范围很大或者位数较多时,基数排序的效率就会下降。

  • 相关阅读:
    Neo4j图形数据库查询,Cypher语言详解
    Onvif soap库使用辅助类
    人人开源搭建后台管理系统 & 逆向工程生成CRUD代码
    Git使用详解
    浅谈yolov5中的anchor
    python垃圾自动清理机制
    jmeter使用bzm线程组压测(Custom Thread Groups插件)
    redis分布式锁
    MATLAB中左边的大括号最后一行为什么会留很大的空白——解决
    数据结构c语言版第二版(严蔚敏)第四章笔记
  • 原文地址:https://blog.csdn.net/qq_52442214/article/details/133392140