双向链表

118 阅读1分钟

双向链表

  • 既可以从头遍历到尾, 又可以从尾遍历到头
  • 也就是链表相连的过程是双向的. 那么它的实现原理, 你能猜到吗?
  • 一个节点既有向前连接的引用, 也有一个向后连接的引用

双向链表缺点

  • 每次在插入或删除某个节点时, 需要处理四个节点的引用, 而不是两个. 也就是实现起来要困难一些
  • 并且相当于单向链表, 必然占用内存空间更大一些.
  • 但是这些缺点和我们使用起来的方便程度相比, 是微不足道的

image.png

  • 双向链表代码实现
class Lnode {
    constructor(data) {
        this.head = null
        this.tail = null
        this.data = data
    }
}
class DoubleLinkList {
    constructor() {
        this.head = null
        this.tail = null
        this.length = 0
    }

    // 尾部添加节点
    append(el) {
        let newnode = new Lnode(el)
        if (this.length == 0) {
            this.head = newnode
            this.tail = newnode
        } else {
            newnode.prev = this.tail
            this.tail.next = newnode
            this.tail = newnode;
        }
        this.length++
    }

    //   向指定位置插入元素 
    insert(position, el) {
        // 判断位置是否合法
        if (position < 0 || position > this.length || !Number.isInteger(position)) {
            return false
        }
        let newnode = new Lnode(el)
        if (position == 0) {
            // 头部添加
            if (this.length == 0) {
                this.head = newnode
                this.tail = newnode
            } else {
                newnode.next = this.head
                this.head.prev = newnode
                this.head = newnode;
            }
            this.length++;
        } else if (position == this.length) {
            // 尾部添加
            this.append()
            this.length++;
        } else {
            // 任意位置插入
            let current = this.head;
            var index = 0;
            while (index < position - 1) {
                current = current.next;
                index++;
            }
            // 将新节点链接上去
            newnode.prev = current
            newnode.next = current.next;
            current.next = newnode;
            newnode.next.prev = newnode
            this.length++
        }
    }
    indexOf(el) {
        let current = this.head,
            index = 0;
        while (index < this.length) {
            if (current.data == el) {
                return index
            } else {
                current = current.next;
                index++;
            }
        }

        return -1
    }

    remove(el) {
        let index = this.indexOf(el)
        this.removeAt(index)
    }
    // 正向遍历
    toAfterString() {
        let current = this.head,
            index = 0,
            res = "";
        while (index < this.length) {
            res += "-" + current.data;
            current = current.next;
            index++;
        }
        return res.slice(1)
    }
    // 反向遍历
    toBeforeString() {
        let current = this.tail,
            index = this.length - 1,
            res = "";
        while (index >= 0) {
            res += "-" + current.data;
            current = current.prev;
            index--;
        }
        return res.slice(1)
    }
}