• 归并排序(递归、非递归、以及自然归并排序)算法总结


    注:本文所指归并排序指 二路归并排序。

    归并排序是平均情况、最坏情况、最好情况时间复杂度都为O(Nlog2N)的稳定的排序算法。最近梳理了下归并排序的递归、非递归、以及自然归并排序算法。

    归并排序的基础:将两个有序数组合并为一个有序数组,需要O(n)的辅助空间。

    图片来自:https://www.cnblogs.com/chengxiao/p/6194356.html

    // array:待排序数组

    //temparray: 临时数组

    //startindex:起始下标

    //middleindex: 中间值下标

    //endindex:终止下标

    void merge(int sourcearray[], int temparray[], int startindex, int middleindex, int endindex)
    {
    int left = startindex, index = startindex;
    int right = middleindex + 1 ;
    if (left >= right )
    return;

    //对两有序数组进行合并
    while (left != middleindex + 1 && right != endindex + 1)
    {
    if (sourcearray[left ] <= sourcearray[right ])
    {
    temparray[index++] = sourcearray[left++];
    }
    else
    {
    temparray[index++] = sourcearray[right++];
    }
    }

    //左边数组未合并完,直接合入
    while (left!= middleindex+ 1)
    {
    temparray[index++] = sourcearray[left++];
    }

    //右边数组未合并完,直接合入
    while (right != endindex + 1)
    {
    temparray[index++] = sourcearray[right++];
    }

    //将临时数组中排好序的数组赋值给排序数组

    for (int i = 0; i < endindex+ 1; ++i)
    {
    sourcearray[i] = temparray[i];
    }

    }

    归并排序递归算法:

    void mergesort(int sourcearray[],int temparray[], int low ,int high)

    {

    if (low>=high)

    return;

    //一分为二

    int middle = (low+high)/2;

    //左半部分递归

    mergesort(sourcearray, temparray, low,middle);

    //右半部分递归

    mergesort(sourcearray, temparray, middle+1,high);

    //将左半部分和右半部分合并

    merge(sourcearray,temparray,low,middle,high);

    }

    非递归归并排序算法:

    非递归排序与递归排序相反,将一个元素与相邻元素构成有序数组,再与旁边数组构成有序数组,直至整个数组有序。

    void merge_noncursive(int sourcearray[], int temparray[],int endindex)

    {

       //步长,在i+step内数组有序,将sourcearray[i]...sourcearray[step-1]与sourcearray[i+step]...sourcearray[min(endindex,i+2*step-1)]两个有序数组合并起来。

        int step = 1;

        int index;

        while(step <= endindex)

         {  

       index = 0;

      //将相邻数组合并

            while(index <= endindex - 2*step +1)

            {

         merge(sourcearray,temparray,index,index+step -1,index+2*step -1);

               index += 2*step;

            }

            //合并有序的左半部分以及不及一个步长的右半部分

       if (index + step <= endindex)

             {

        merge(sourcearray,temparray,index,index+step-1,endindex);

             }

           step *= 2;

         }

    }

    自然归并排序:

    既然归并排序是将多个有序的数组合并成一个数组,除了完全逆序的数组,总有一部分数组是有序的,我们可以获取有序数组的标记,从而将多个有序数组合并成一个有序数组。

    //这个是理解自然归并排序的关键

    int getindex(int array[], int flag[],int index)

    {

       int next = 0;

     //最开始为下标0

       flag[next] = 0;

       next++;

      for(int i = 0;i<index;i++)

       {

        //找到数组元素不是有序的地方

        if (array[i] > array[i+1])

         {

      flag[next++] = i;

      }

      }    

           //最后一位为最大下标

      flag[next] = index;

         return next;

    }

    void merge_naturally(int sourcearray[],int temparray[],int index)

    {

      int * flag = new int[index];

           int num = getindex(sourcearray,flag,index);

         //大于等于2说明除了0与index外有其他数,数组不完全有序

           while(num >= 2)

          {       

        //对相邻有序数组进行合并

                  for(int i = 0; i<=num;i+=2)

        {

                   merge(sourcearray,temparray,flag[i],flag[i+1],flag[i+2]);

                 }

       //继续获取无序的序号

              num = getindex(sourcearray,flag,index);

          }

    }

  • 相关阅读:
    LeeCode 1497. 检查数组对是否可以被 k 整除
    LeetCode 1503. 所有蚂蚁掉下来前的最后一刻
    双指针算法
    最短送餐路程计算, 美团笔试题2020
    最短路算法dijkstra算法
    寻找最小子字符串, 美团笔试题2020
    最大矩形, 统计全1子矩阵
    拼凑硬币, 腾讯
    7月15日
    7月14日
  • 原文地址:https://www.cnblogs.com/gardener/p/9102985.html
Copyright © 2020-2023  润新知