js合併有序鏈表

關於鏈表

區別於數組,數組的全部的元素在內存中都是連續存儲的,而鏈表則是分散在內存中的,經過指針鏈接起來的一種數據結構。接下來,咱們嘗試使用js合併兩個有序鏈表。node

一些準備

首先咱們須要聲明一些咱們須要用到的函數。數組

鏈表中的節點

每個節點一般最少有兩個屬性,一個表示該節點的值,能夠用key來表示,另一個就是指向下一個節點的指針,能夠用next表示。
先聲明一個Node類:數據結構

function Node (key) {
    this.key = key;
    this.next = null;
}

鏈表類

接着,聲明一個鏈表類LinkedList:app

function LinkedList () {
    //表示鏈表的長度
    this.length = 0;
    //表示鏈表的頭結點(第一個節點)
    this.head = null;
}

鏈表的插入節點方法

而後,再聲明一個基本的鏈表方法append,用來向鏈表尾部插入一個新節點:函數

LinkedList.prototype.append = function (key){
    var node = new Node(key);
    //若是鏈表尚未節點
    if (!this.head) {
        this.head = node;
    } else {
        //經過循環找到最後一個節點,而後讓最後一個節點指向新節點
        var current = this.head;
        while(current.next){
            current = current.next;
        }
        current.next = node;
    }
    // 修改鏈表的長度
    this.length++;
}

構造兩個有序鏈表

咱們的目的是合併有序鏈表,因此這裏,咱們先用兩個有序數組,去構建兩個有序鏈表:測試

var arr1 = [2, 4, 6, 8];
var arr2 = [1, 3, 5, 7];
var list1 = new LinkedList();
var list2 = new LinkedList();

arr1.forEach(function(key){
    list1.append(key);
});
arr2.forEach(function(key){
    list2.append(key);
});

合併有序鏈表

最簡單的方案

就是把兩個鏈表中全部key都拿出來放進一個數組裏,庵後,再對數組排序,根據數組,從新構建一個鏈表。this

function mergeLinkedList (list1, list2) {
    // 存放兩個鏈表key的數組
    var array = [];
    // 最終須要返回的新鏈表
    var list = new LinkedList();
    // 第一個鏈表的頭節點
    var listHead1 = list1.head;
    // 第二個鏈表的頭節點
    var listHead2 = list2.head;

    // 把第一個鏈表的全部key存進數組
    while (listHead1) {
        array.push(listHead1.key);
        listHead1 = listHead1.next;
    }
    // 把第二個鏈表的全部key存進數組
    while (listHead2) {
        array.push(listHead2.key);
        listHead2 = listHead2.next;
    }
    // 對數組排序
    array = array.sort(function(a, b){
        return a - b;
    })
    // 使用數組從新構建一個鏈表
    array.forEach(function(key){
        list.append(key);
    });

    return list;
}

按順序把兩個鏈表的key插入到新鏈表

function mergeLinkedList (list1, list2) {
    var list = new LinkedList();
    // 第一個鏈表的頭節點
    var current1 = list1.head;
    // 第二個鏈表的頭節點
    var current2 = list2.head;

    // 用循環把兩個鏈表的key按順序插入到新鏈表
    while (current1 && current2) {
        if (current1.key < current2.key) {
            list.append(current1.key);
            current1 = current1.next;
        } else {
            list.append(current2.key);
            current2 = current2.next;
        }
    }

    // 找到新鏈表的最後一個節點
    var current = list.head;
    while(current.next){
        current = current.next;
    }

    // 循環完成之後,把第二個鏈表剩餘部分插入到新鏈表
    if (current2) {
        while (current2) {
            list.append(current2.key);
            current2 = current2.next;
        }
    }
    // 循環完成之後,把第一個鏈表剩餘部分插入到新鏈表
    if (current1) {
        while (current1) {
            list.append(current1.key);
            current1 = current1.next;
        }
    }

    return list;
}

合併到第一個鏈表

function mergeLinkedList (list1, list2) {
    var listHead1 = list1.head;
    var listHead2 = list2.head;
    var previous = listHead1;

    // 若是第二個鏈表的首節點key小於第一個鏈表的首節點key
    // 則構造一個新節點,並把新節點插入到第一個鏈表頭部
    if (listHead1.key > listHead2.key) {
        var node = new Node(listHead2.key);
        node.next = listHead1;
        list1.head = listHead1 = previous = node;
        listHead2 = listHead2.next;
    }
    // 循環比較兩個鏈表的key,把第二個鏈表中的key插入到第一個鏈表合適的位置
    while (listHead1 && listHead2) {
        if (listHead2.key < listHead1.key) {
            var node = new Node(listHead2.key);
            node.next = previous.next;
            previous.next = node;
            previous = node;
            listHead2 = listHead2.next;
        } else {
            previous = listHead1;
            listHead1 = listHead1.next; 
        }
    }
    // 若是第二個鏈表比較長,則把剩餘部分插入到第一個鏈表
    while (listHead2) {
        var node = new Node(listHead2.key);
        if (listHead1) {
            listHead1.next = node;
            listHead1 = node;                    
        } else if (previous) {
            previous.next = node;
            previous = node;    
        }

        listHead2 = listHead2.next;
    }

    // 修正第一個鏈表的長度
    list1.length = list1.length + list2.length;
    return list1;
}

結果驗證

仍是構造兩個有序鏈表spa

var arr1 = [2, 4, 6, 8];
var arr2 = [1, 3, 5, 7];
var list1 = new LinkedList();
var list2 = new LinkedList();
arr1.forEach(function(key){
    list1.append(key);
});
arr2.forEach(function(key){
    list2.append(key);
});
var list = mergeLinkedList(list1, list2);

自控制檯查看結果:
圖片描述prototype

換一組測試數據(arr1和arr2調換一下):指針

var arr2 = [2, 4, 6, 8];
var arr1 = [1, 3, 5, 7];
var list1 = new LinkedList();
var list2 = new LinkedList();
arr1.forEach(function(key){
    list1.append(key);
});
arr2.forEach(function(key){
    list2.append(key);
});
var list = mergeLinkedList(list1, list2);

看結果:
圖片描述

來一個複雜點的測試數據:

var arr1 = [99, 100, 104, 106];
var arr2 = [1, 3, 5, 7, 102, 103, 107];
var list1 = new LinkedList();
var list2 = new LinkedList();
arr1.forEach(function(key){
    list1.append(key);
});
arr2.forEach(function(key){
    list2.append(key);
});
var list = mergeLinkedList(list1, list2);

結果以下:
圖片描述

以上代碼中,都省去了參數合法性校驗的過程,真實環境裏是須要的。

相關文章
相關標籤/搜索