首頁  >  文章  >  web前端  >  JavaScript趣題:鍊錶的歸併排序

JavaScript趣題:鍊錶的歸併排序

黄舟
黄舟原創
2017-01-22 15:04:131845瀏覽

歸併排序想必大家都知道,它的基本思想,是一個先分割,再合併的過程。

那麼,如何對一條單鍊錶進行歸併排序呢?

首先,我們需要一個分割鍊錶的方法,如下面的偽代碼所展示的那樣:

var source = 1 -> 3 -> 7 -> 8 -> 11 -> 12 -> 14 -> null  
var front = new Node()  
var back = new Node()  
frontBackSplit(source, front, back)  
front === 1 -> 3 -> 7 -> 8 -> null  
back === 11 -> 12 -> 14 -> null

它接收一個鍊錶的尾指針作為參數,將該鍊錶一分為二,也就是前半部分和後半部分。

那麼,這個中間的分界值該如何決定?

可以使用快慢指針,快指針和慢指針同時從尾部出發,遍歷單鍊錶,快指針每次都走2步,慢指針每次走1步,那麼快指針肯定會先達到終點,而慢指針此時只走了一半的路程,也就是說,慢指針正好處於這個分界的位置。

那剩下的就好辦了,在分界處截斷,該設定為null的設定好,第一階段我們就完成了。

function Node(data) {  
    this.data = data === undefined ? null : data;  
    this.next = null;  
}  
  
function frontBackSplit(source, front, back) {  
    var total = 0;  
    var fast = source;  
    var slow = source;  
    var partial = null;  
    while(fast && fast.next){  
        fast = fast.next.next;  
        slow = slow.next;  
        total++;  
    }  
    partial = slow;  
    while(slow){  
        slow = slow.next;  
        total++;  
    }  
    if(total % 2 === 1){  
        back.data = partial.next.data;  
        back.next = partial.next.next;  
        partial.next = null;  
    }  
    else{  
        back.data = partial.data;  
        back.next = partial.next;  
        for(var e=source;e.next!=partial;e=e.next);  
        e.next = null;        
    }  
    front.data = source.data;  
    front.next = source.next;  
}

然後,鍊錶打散了,甚至成了一個個不可分割的單元節點,我們就要想辦法將它們合併,組裝成新的有序的鍊錶,於是,就需要下面的merge方法:

var first = 2 -> 4 -> 6 -> 7 -> null  
var second = 1 -> 3 -> 5 -> 6 -> 8 -> null  
sortedMerge(first, second) === 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 6 -> 7 -> 8 -> null

要寫好一個這樣的方法,考慮的case其實是有蠻多的,這在俺的程式碼裡就有所體現了:

function sortedMerge(l1, l2) {  
    var newList = null;  
    var temp = null;  
    while(l1 && l2){  
        if(l1.data > l2.data){  
            if(!newList){  
                newList = l2;  
                temp = l2;  
            }  
            else{  
                temp.next = l2;  
                temp = l2;  
            }  
            l2 = l2.next;  
        }  
        else{  
            if(!newList){  
                newList = l1;  
                temp = l1;  
            }  
            else{  
                temp.next = l1;  
                temp = l1;  
            }  
            l1 = l1.next;  
        }  
    }  
    if(l1){  
        if(!newList){  
            newList = l1;  
        }  
        else{  
            temp.next = l1;  
        }  
    }  
    if(l2){  
        if(!newList){  
            newList = l2;  
        }  
        else{  
            temp.next = l2;  
        }  
    }  
    return newList;  
}

好了,分割方法和合併方法都寫好了,就好比案板和菜刀都準備好,只需要切肉了。主方法這是一個遞歸的過程。

function mergeSort(list) {  
    if(list && list.next){  
        var front = new Node();  
        var back = new Node();  
        frontBackSplit(list, front, back);  
        return sortedMerge(mergeSort(front),mergeSort(back));  
    }  
    return list;  
}

以上就是JavaScript趣題:鍊錶的歸併排序的內容,更多相關內容請關注PHP中文網(www.php.cn)!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn