• 快速排序和归并排序的非递归形式


            快速排序和归并排序都需要用递归的形式展开,那么有没有什么方法不需要递归就能实现归并和快速排序,有的!

     1.快速排序

            我们可以借助栈来模拟递归。

            递归的主要思想就是大事化小,小事化了。我们借助栈的 目的是将需要排序的“头” 和 “尾”找到,进而排序,然后找到合适的keyi并放入合适的位置,再将keyi两边的“头” 和 “尾”入栈,找到合适的keyi......如此重复下去.......

            keyi需要入栈吗?keyi不需要入栈,因为keyi已经在合适的位置了

    前后指针法,结合上一篇博客来看, 

    1. int PatrSort3(int* a, int begin, int end)
    2. {
    3. int prev = begin, cur = begin+1;
    4. int keyi = begin;
    5. int midi = GetMidIndex(a , begin ,end);
    6. Swap(&a[keyi],&a[midi]);
    7. while (cur <= end)
    8. {
    9. //cur位置小于keyi发生交换
    10. if (a[cur] < a[keyi] && ++prev != cur)
    11. {
    12. //++prev;
    13. Swap(&a[prev], &a[cur]);
    14. }
    15. cur++;
    16. }
    17. Swap(&a[keyi],&a[prev]);
    18. keyi = prev;
    19. return keyi;
    20. }
    1. void QuickSortNonR(int* a, int begin, int end)
    2. {
    3. ST st;
    4. STInit(&st);
    5. STPush(&st,end);
    6. STPush(&st, begin);
    7. while (!STEmpty(&st))
    8. {
    9. int left = STTop(&st);
    10. STPop(&st);
    11. int right = STTop(&st);
    12. STPop(&st);
    13. int keyi = PatrSort3(a,left,right);
    14. if (keyi + 1 < right)
    15. {
    16. STPush(&st,right);
    17. STPush(&st,keyi+1);
    18. }
    19. if (left < keyi - 1)
    20. {
    21. STPush(&st, keyi - 1);
    22. STPush(&st, left);
    23. }
    24. }
    25. STDestroy(&st);
    26. }

    2.归并排序

            归并排序的基本思想在上一篇已经讲过,快速排序是先对整个数组中选出适中的的keyi放到合适的位置,然后切分子块,层层递归,进行排序,快速排序类似于前序遍历。归并排序是先找到最小的子块,然后层层排序,层层归并,归并排序类似于后序遍历。

            归并排序还存在越界的问题:每个子区间应该怎么样确定,能给出明确的边界吗?

            边界是怎么确定的:

     

            gap每次增加是上一次的2倍,当gap = 4 时, 数组有10个元素,我们控制循环是按照一下的方式来控制的。

            当 i = 0 的时候 begin1 end1 ,begin2 end2 。[0 ,3]  [4 ,7]  。

            进入下一轮循环: i = 8 , begin1 end1 ,begin2 end2 。[8,11]  [12 ,15] 。

     

            此时问题来了,数组只有十个元素,下标为 10-15  已经越界访问了 ,这是我们要处理越界访问问题。

            

    1. void MergeSortNonR(int* a, int n)
    2. {
    3. int* tmp = (int*)malloc(sizeof(int) * n);
    4. if (tmp == NULL)
    5. {
    6. perror("malloc fail");
    7. }
    8. int gap = 1;
    9. while (gap < n)
    10. {
    11. printf("gap:%d->", gap);
    12. for (int i = 0; i < n; i += 2*gap)
    13. {
    14. //[i,i+gap-1] [i+gap ,i + 2*gap-1] 控制边界
    15. int begin1 = i;
    16. int end1 = i + gap - 1;
    17. int begin2 = i + gap;
    18. int end2 = i + 2 * gap - 1;
    19. //越界,修正边界
    20. if (end1 >= n)
    21. {
    22. end1 = n - 1;
    23. // [begin2, end2]修正为不存在区间
    24. begin2 = n;
    25. end2 = n - 1;
    26. }
    27. else if (begin2 >=n)
    28. {
    29. // [begin2, end2]修正为不存在区间
    30. begin2 = n;
    31. end2 = n - 1;
    32. }
    33. else if (end2 >= n)
    34. {
    35. end2 = n - 1;
    36. }
    37. printf("[%d,%d] [%d, %d]--", begin1, end1, begin2, end2);
    38. int m = end2 - begin1+1;
    39. int j = begin1;
    40. while (begin1 <= end1 && begin2 <= end2)
    41. {
    42. if (a[begin1] < a[begin2])
    43. {
    44. tmp[j++] = a[begin1++];
    45. }
    46. else
    47. {
    48. tmp[j++] = a[begin2++];
    49. }
    50. }
    51. while (begin1 <= end1)
    52. {
    53. tmp[j++] = a[begin1++];
    54. }
    55. while (begin2 <= end2)
    56. {
    57. tmp[j++] = a[begin2++];
    58. }
    59. memcpy(a+i, tmp+i, sizeof(int) * m);
    60. }
    61. // memcpy(a, tmp, sizeof(int) * m);
    62. printf("\n");
    63. gap *= 2;
    64. }
    65. free(tmp);
    66. }
    1. void TestMergeSort()
    2. {
    3. int a[] = { 9, 1, 2, 5, 7, 4, 8, 6, 3, 5 };
    4. //MergeSort(a, sizeof(a) / sizeof(int) );
    5. MergeSortNonR(a, sizeof(a) / sizeof(int));
    6. PrintArray(a, sizeof(a) / sizeof(int));
    7. }

    归并排序的特性总结:
            1. 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
            2. 时间复杂度:O(N*logN)
            3. 空间复杂度:O(N)
            4. 稳定性:稳定

  • 相关阅读:
    Unity使用新输入系统InputSystem制作飞机大战Demo
    R语言时间序列数据算术运算:使用log函数将时间序列数据的数值对数化、使用diff函数计算对数化后的时间序列数据的逐次差分(计算价格的对数差分)
    (免费分享)java基于SSM的进销存管理系统设计与实现
    C#【必备技能篇】生成公共属性代码{get;set;}的快捷方法
    详解OpenCV的窗口滑动条创建控制函数createTrackbar()
    *** stack smashing detected ***: terminated
    旅游 DIY
    打造类ChatGPT服务,本地部署大语言模型(LLM),如何远程访问?
    猫罐头哪个牌子好?盘点十大猫罐头品牌排行榜!
    Latex 写论文排版方法(vscode)
  • 原文地址:https://blog.csdn.net/kqs__/article/details/132883169