排序算法之归并排序

ゞ 浴缸里的玫瑰 2022-09-25 15:27 269阅读 0赞

先看一下下面这张图

Center

下面分析归并排序:

归并排序把数组划分成几个小数组,然后小数组成划分,直到每个数组都只有一个元素,然后将相邻的两个数组进行合并,再将合并后的数组继续合并,直到合并成一个数组。总体的思想是先拆分再合并。

归并排序的时间复杂度为O(nlogn)。

由于合并的时候需要额外的一个数组来保存,因此空间复杂度为O(n)。

归并排序合并的时候是相邻的数组进行合并,因此是稳定的。

归并排序可用递归实现,先递归将数组拆分,拆到最小时返回,然后将拆分的两个数组进行合并。

C++代码

  1. /*
  2. * 归并排序
  3. * 先将数组拆分成小数组,然后在合并成大数组
  4. * 合并的时候进行排序,使用一个辅助的空间来存储排好序的元素
  5. * O(nlogn)
  6. * O(n)
  7. * 稳定
  8. */
  9. #define RECURSION 0
  10. template <typename T>
  11. void SortHelp<T>::mergeSort(T l[], int length) {
  12. #ifdef RECURSION
  13. //使用递归
  14. merge(l, 0, length - 1);
  15. #else
  16. #endif // RECURSION
  17. }
  18. template<typename T>
  19. void SortHelp<T>::merge(T l[], int start, int end)
  20. {
  21. //数组只剩下一个元素
  22. if (start == end)
  23. {
  24. return;
  25. }
  26. int mid = (start + end) / 2;
  27. merge(l, start, mid);
  28. merge(l, mid + 1, end);
  29. //合并两个数组
  30. T* temp = (T*)malloc(sizeof(T)*(end - start + 1));
  31. int i, j, k;
  32. for (i = start, j = mid + 1, k = 0; i <= mid && j <= end; k++)
  33. {
  34. if (l[i] < l[j])
  35. {
  36. temp[k] = l[i];
  37. i++;
  38. }
  39. else
  40. {
  41. temp[k] = l[j];
  42. j++;
  43. }
  44. }
  45. while (i <= mid)
  46. {
  47. temp[k++] = l[i++];
  48. }
  49. while (j <= end)
  50. {
  51. temp[k++] = l[j++];
  52. }
  53. //复制回原数组
  54. for (i = start, k = 0; i <= end; i++)
  55. {
  56. l[i] = temp[k++];
  57. }
  58. }

也可以不使用递归,不用拆分,直接从最小单位开始合并,合并完一趟后把合并单位翻倍。

C++代码

  1. /*
  2. * 归并排序
  3. * 先将数组拆分成小数组,然后在合并成大数组
  4. * 合并的时候进行排序,使用一个辅助的空间来存储排好序的元素
  5. * O(nlogn)
  6. * O(n)
  7. * 稳定
  8. */
  9. //#define RECURSION 0
  10. template <typename T>
  11. void SortHelp<T>::mergeSort(T l[], int length) {
  12. #ifdef RECURSION
  13. //使用递归
  14. merge(l, 0, length - 1);
  15. #else
  16. //不使用递归
  17. int dt = 1;
  18. T* temp = (T*)malloc(sizeof(T)*length);
  19. int i, j, k;
  20. while (dt < length)
  21. {
  22. for (int s = 0; s < length; s += 2 * dt)
  23. {
  24. //合并数组[s,s+dt-1]和数组[s+dt,s+2dt-1]
  25. for (i = s, j = s + dt, k = 0; i < s + dt && j < s + 2 * dt && j < length; k++)
  26. {
  27. if (l[i] < l[j])
  28. {
  29. temp[k] = l[i++];
  30. }
  31. else
  32. {
  33. temp[k] = l[j++];
  34. }
  35. }
  36. while (i < s + dt)
  37. {
  38. temp[k++] = l[i++];
  39. }
  40. while (j < s + 2 * dt && j < length)
  41. {
  42. temp[k++] = l[j++];
  43. }
  44. //复制回源数组
  45. for (i = s, k = 0; i < s + 2 * dt && i < length; i++, k++)
  46. {
  47. l[i] = temp[k];
  48. }
  49. }
  50. dt *= 2;
  51. }
  52. free(temp);
  53. #endif // RECURSION
  54. }

总结,归并排序的时间复杂度为O(nlogn),空间复杂度为O(n),稳定。

发表评论

表情:
评论列表 (有 0 条评论,269人围观)

还没有评论,来说两句吧...

相关阅读

    相关 排序算法归并排序

    归并排序是一种基于分治思想的排序算法,它的基本思路是将原始序列划分为若干个子序列,对每个子序列进行排序,然后将排好序的子序列合并为一个大序列,最终得到排序结果。具体来说,归并排

    相关 排序算法归并排序

    归并排序 基本思想:归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使用每个子序列有

    相关 排序算法归并排序

    归并排序> 之前曾经实现过堆排序,它用到了完全二叉树,但是堆的设计本身就是比较复杂的,而今天要实现的归并排序同样的也用到了完全二叉树的思想,这种思想比堆排序较为简单.

    相关 排序算法归并排序

    归并排序是利用递归与分治思想将数据序列划分成越来越小的半子序列,在对其进行排序,最后利用递归将排好序的半子序列合并成越来越大的有序序列。 归并排序中,归 即是递归的意思,即递