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

相关文章
相关标签/搜索