歸並排序(遞歸、非遞歸、以及自然歸並排序)算法總結


注:本文所指歸並排序指 二路歸並排序。

歸並排序是平均情況、最壞情況、最好情況時間復雜度都為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);

      }

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM