????????歸并排序是第一個可以被實際使用的排序算法。你在本書中學到的前三個排序算法性能不好,但歸并排序性能不錯,其復雜度為O(nlogn)。
? ??????歸并排序是一種分治算法。其思想是將原始數(shù)組切分成較小的數(shù)組,直到每個小數(shù)組只有一個位置,接著將小數(shù)組歸并成較大的數(shù)組,直到最后只有一個排序完畢的大數(shù)組。
? ??????由于是分治法,歸并排序也是遞歸的:
this.mergeSort = function(){
????array = mergeSortRec(array);
};
? ??????像之前的章節(jié)一樣,每當要實現(xiàn)一個遞歸函數(shù),我們都會實現(xiàn)一個實際被執(zhí)行的輔助函數(shù)。對歸并排序我們也會這么做。我們將聲明mergeSort方法以供隨后使用,而mergeSort方法將會調用mergeSortRec,該函數(shù)是一個遞歸函數(shù):
var mergeSortRec = function(array){
? ????var length = array.length;
? ????if(length === 1) {? ? ? //{1}
? ? ????????return array;? ? ? //{2}
? ????}
? ????var mid = Math.floor(length / 2),
? ? ????left = array.slice(0, mid),
? ? ????right = array.slice(mid, length); //{5}
????return merge(mergeSortRec(left), mergeSortRec(right)); //{6}
};
? ??????歸并排序將一個大數(shù)組轉化為多個小數(shù)組直到只有一個項。由于算法是遞歸的,我們需要一個停止條件,在這里此條件是判斷數(shù)組的長度是否為1(行{1})。如果是,則直接返回這個長度為1的數(shù)組(行{2}),因為它已排序了。
? ??????如果數(shù)組長度比1大,那么我們得將其分成小數(shù)組。為此,首先得找到數(shù)組的中間位(行{3}),找到后我們將數(shù)組分成兩個小數(shù)組,分別叫作left(行{4})和right(行{5})。left數(shù)組由索引0至中間索引的元素組成,而right數(shù)組由中間索引至原始數(shù)組最后一個位置的元素組成。
? ??????下面的步驟是調用merge函數(shù)(行{6}),它負責合并和排序小數(shù)組來產生大數(shù)組,直到回到原始數(shù)組并已排序完成。為了不斷將原始數(shù)組分成小數(shù)組,我們得再次對left數(shù)組和right數(shù)組遞歸調用mergeSortRec,并同時作為參數(shù)傳遞給merge函數(shù)。
var merge = function(left, right){
? ? ? var result = [], // {7}
????????il = 0,
????????ir = 0;
????while(il < left.length && ir < right.length) { // {8}
? ????????if(left[il] < right[ir]) {
? ? ???????????result.push(left[il++]);? // {9}
? ???????} else{
? ? ????????result.push(right[ir++]); // {10}
? ????????}
????}
? while (il < left.length){.??// {11}
? ? ????result.push(left[il++]);
????}
? while (ir < right.length){.??// {12}
? ? ????result.push(right[ir++]);
????}
? return result; // {13}
};
? ??????merge函數(shù)接受兩個數(shù)組作為參數(shù),并將它們歸并至一個大數(shù)組。排序發(fā)生在歸并過程中。首先,需要聲明歸并過程要創(chuàng)建的新數(shù)組以及用來迭代兩個數(shù)組(left和right數(shù)組)所需的兩個變量(行{7})。迭代兩個數(shù)組的過程中(行{8}),我們比較來自left數(shù)組的項是否比來自right數(shù)組的項小。如果是,將該項從lef數(shù)組添加至歸并結果數(shù)組,并遞增迭代數(shù)組的控制變量(行{9});否則,從right數(shù)組添加項并遞增相應的迭代數(shù)組的控制變量({10})。
? ??????接下來,將left數(shù)組或者right數(shù)組所有剩余的項添加到歸并數(shù)組中(行{11}和行{12})。最后,將歸并數(shù)組作為結果返回(行{13})。
????????如果執(zhí)行mergeSort函數(shù),下圖是具體的執(zhí)行過程:
????????可以看到,算法首先將原始數(shù)組分割直至只有一個元素的子數(shù)組,然后開始歸并。歸并過程也會完成排序,直至原始數(shù)組完全合并并完成排序。