資料結構與演算法 排序 歸併排序

2021-10-09 21:56:34 字數 3322 閱讀 2322

2023年由馮諾依曼首次提出。

執行流程

1 不斷的將當前序列平均分割成兩個子串行

直到不能再分割(序列中只剩1個元素)

2 不斷的將兩個子串行合併成乙個有序序列

直到最終只剩下1個有序序列

歸併排序,主要有分和和兩個步驟。

其中,分感覺好理解些,找出begin,end,求出middle,然後遞迴呼叫,直到元素個數小於或等於1時,不再分割。不難寫出:

public

static

void

dividesort

(int

array,

int begin,

int end)

合併就有些許難度,這其實算是另外一道演算法題:

比如,我們需要將兩個有序陣列[3, 8]、[6, 10]合併成乙個大陣列。

大致流程是:

建立乙個可以容納兩個陣列長度的大陣列array,用以存放排序好的陣列。並設立乙個變數ai,用以存放新元素要存放的位置。預設是0;

設立兩個變數lefti、righti,分別指向兩個陣列當前比較到了**。預設都是0,也就是li = 0; ri = 0;

比較array1[li] 與array2[ri]值的大小

如果array1[li] <= array2[ri],則將array[ai] = array1[li]; li++;

如果li超過array1的邊界,則將array2剩餘的元素依次放在新陣列array後面。

如果array1[li] > array2[ri],則將array[ai] = array2[ri]; ri++;

如果ri超過array2的邊界,則將array1剩餘的元素依次放在新陣列array後面。

有了以上思路,不難寫出**:

public

static

void

main

(string[

] args)

;int

array2 =

;mergesortarray

(array1, array2);}

public

static

void

mergesortarray

(int

array1,

int[

] array2)

else}if

(li == array1.length)}if

(ri == array2.length)

}for

(int i =

0; i < array.length; i++)}

列印結果:12

2346

10

寫完了兩個不相關的陣列,我們再看一下歸併排序的合併

歸併排序的兩個陣列是相連的,並且陣列大小是等分的,因此,在建立新的陣列時候,不需要建立乙個等長的大陣列。

只需要將前面乙個陣列copy出乙份,然後將新copy出來的陣列,與後面的陣列做對比,將比較出來的元素放入到原陣列中即可。這樣,空間複雜度比上面的少一半。

左邊先結束,什麼也不做

右邊先結束,左邊按個移過來

public

static

void

main

(string[

] args)

;dividesort

(array,

0, array.length)

;for

(int i =

0; i < array.length; i++)}

public

static

void

dividesort

(int

array,

int begin,

int end)

public

static

void

mergesort

(int

array,

int begin,

int middle,

int end)

//如果左邊還沒結束

while

(li < le)

else

}else

}//如果左邊先結束,則剩下的啥也不需要做了

}

其中,裡面的while迴圈可優化:

while

(li < le)

else

}

歸併排序花費時間

假設歸併排序花費的時間為t(n)

裡面有兩個均分的歸併排序t(n/2)

以及乙個合併遍歷o(n)

那麼,可以得出:

t(n) = 2*t(n/2) + o(n);…1

並且t(1) = o(1);

那麼1式左右同除以n

t(n)/n = 2*t(n/2)/n + o(1);

t(n)/n = t(n/2)*2/n + o(1);

t(n)/n = t(n/2)/n/2 + o(1);

令s(n) = t(n)/n;,那麼s(1) = t(1) = o(1);

s(n) = s(n/2)+ o(1) = s(n/4)+ o(2) = s(n/8)+ o(3) = s(n/2^k)+ o(k)

n = 2^k,k = logn

s(n) = s(2^k) = s(1) + o(logn) = o(logn)

s(n) = t(n)/n = o(logn)

那麼,t(n) = o(nlogn)

由於歸併排序總是平均分割子串行,所以最好、最壞、平均時間複雜度都是o(nlogn),屬於穩定排序。

歸併排序的空間複雜度為:

在分割的時候,由於是遞迴呼叫,每次遞迴需要占用記憶體空間,遞迴呼叫分割logn次,也就是分割是o(logn)

在合併的時候,由於需要將左邊的陣列copy出乙份,因此,占用空間是o(n/2)

所以,歸併排序的空間複雜度為o(logn + n/2) 約等於 o(n)

資料結構與演算法 歸併排序

include include include string include include include include algorithm using namespace std void merge vector input,int left,int mid,int right,vector...

資料結構與演算法(歸併排序)

歸併排序是採用分治法的乙個典型的應用,歸併排序的思想就是先遞迴分解陣列,在合併陣列。將陣列分解最小之後,然後合併兩個有序陣列,基本思路是比較兩個陣列的前面的數,誰小就先取誰,取了後相應的指標就往後移一位,直至乙個陣列為空,最後把另乙個陣列的剩餘部分複製過來即可。def merge sort alis...

資料結構與演算法 歸併排序

你可以在 的 mer 標籤中看到歸併排序的動畫。歸併排序 時間複雜度 o nlogn 空間複雜度 o n 基本思想 分治思想。8 6 2 3 1 5 7 4 分 8 6 2 3 1 5 7 4 分 8 6 2 3 1 5 7 4 分 8 6 2 3 1 5 7 4 並 8 6 2 3 1 5 7 4...