JavaScript數據結構之-雙向鏈表

鏈表相對傳統數組優勢是:添加刪除元素不會移動其它元素。鏈表相對傳統數組缺點是:訪問鏈表中間的元素,須要從頭迭代,直到找到所需元素。上一篇文章討論了鏈表,本章敘述雙向鏈表。雙向鏈表是雙向的,一個鏈向上一個元素,一個鏈向上一個元素。 雙向鏈表提供兩種迭代方式:從頭至尾和從尾到頭,咱們能夠訪問特定一個節點的上一個元素或者下一個元素。node

簡單鏈表和雙向鏈表很是相似,上一章 juejin.im/post/5ccb1b… 已經介紹了基本的操做方法和寫法,此次介紹雙向鏈表和簡單鏈表不同的一些算法。算法

在任意位置插入新元素

function DoublyLinkedList() {
    let Node = function(element) {
        this.element = element;
        this.next = null;
        this.prev = null;
    };
    let length = 0,
        head = null,
        tail = null;
    // 在任意位置插入新元素
    this.insert = function(position) {
        if (position >= 0 && position <= length) {
            let node = new Node(element),
                current = head,
                previous = null,
                index = 0;
            if (0 === position) {
                if (!head) {
                    head = node;
                    tail = node;
                } else {
                    node.next = current;
                    current.prev = node;
                    head = node;
                }
            } else if (length === position) {
                current = tail;
                current.next = node;
                node.prev = current;
                tail = node;
            } else {
                while (index++ < position) {
                    previous = current;
                    current = current.next;
                }
                previous.next = node;
                node.prev = previous;
                current.prev = node;
                node.next = current;
            }
            length++;
            return true;
        } else {
            return false;
        }
    };
}
複製代碼

插入大體分爲三種場景:一、 在列表第一個位置插入元素,若是列表爲空,head和tail都指向這個新節點。若是列表不爲空,current將是對這個列表對一個元素的引用,node.next指向current,current.prev指向node。二、在列表最後插入一個元素,這是一種比較特殊的場景,由於最後還控制着tail指針,current指向最後一個指針的引用,而後創建裏一個連接,current.next指向node,而後node.prev指向current,最後更新tail,指向node。三、在列表任意位置插入元素,首先遍歷到指定位置,這裏就須要在指定位置先後位新元素創建兩兩連接。這樣纔不會丟掉節點之間的關係。數組

從任意位置移除元素

function DoublyLinkedList() {
    let Node = function(element) {
        this.element = element;
        this.next = null;
        this.prev = null;
    };
    let length = 0,
        head = null,
        tail = null;
    // 從任意位置移除元素
    this.removeAt = function(position) {
        if (position > -1 && position < length) {
            let current = head,
                previous = null,
                index = 0;
            if (0 === position) {
                head = current.next;
                if (1 === length) {
                    tail = null;
                } else {
                    head.prev = null;
                }
            } else if (length - 1 === position) {
                current = tail;
                tail = current.prev;
                tail.next = null;
            } else {
                while (index++ < position) {
                    previous = current;
                    current = current.next;
                }
                previous.next = current.next;
                current.next.prev = previous;
            }
            length--;
            return current.element;
        } else {
            return null;
        }
    };
}
複製代碼

刪除也大體分爲三種場景:一、 在列表第一個位置刪除元素。二、刪除列表最後一個元素,這是一種比較特殊的場景,由於最後還控制着tail指針。三、在列表任意位置刪除元素。bash

雙向鏈表的刪除和插入操做最基本的思想一致,在操做元素時保證元素間先後連接不能斷開。post

下一章:循環鏈表ui