注:本文所指歸併排序指 二路歸併排序。html
歸併排序是平均狀況、最壞狀況、最好狀況時間複雜度都爲O(Nlog2N)的穩定的排序算法。最近梳理了下歸併排序的遞歸、非遞歸、以及天然歸併排序算法。算法
歸併排序的基礎:將兩個有序數組合併爲一個有序數組,須要O(n)的輔助空間。數組
圖片來自:https://www.cnblogs.com/chengxiao/p/6194356.htmlhtm
// array:待排序數組blog
//temparray: 臨時數組排序
//startindex:起始下標遞歸
//middleindex: 中間值下標圖片
//endindex:終止下標get
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);
}
}