JavaScript实现简单的双链表

76 阅读2分钟

双向链表

 单向链表: 
    1、只能从头部到尾部或者从尾部到头部
    2、链表的连接是单向的
    3、实现原理就是上一个链表有下一个链表的引用
    4、缺点就是我们可以轻松的前往下一个节点但是回到上一个节点需要从头开始(类似于文本编辑器返回上一个光标)
    
  双向链表:
    1、可以从头遍历到尾部,也可以从尾部变量到头部
    2、一个节点有上一个连接的引用,也有一个下一个连接的引用
    3、缺点有实现起来更复杂,需要处理4个节点; 相比于单向链表,占用内存空间更大
    
  实现:
                                    tail
                                     |
  head -> pre | item | next -> pre | item | next -> null  
    
    
    1、有2个指针,一个指向head头部,一个指向尾部tail
    2、每一个节点3个部分组成 pre(上一个节点的指针) item(保存的元素) next(下一个节点的指针)
    3、双向链表的第一个节点的pre指向null
    4、双向链表的最后的节点的nextnull
/**
* @Description: 双向链表
* @Author: 谭舒琪
* @Date: 2022-12-28 17:11:51
* @LastEditTime: 2022-12-28 17:11:51
* @LastEditors: Please set LastEditors
*/


function DoublyLinkedList() {
    this.head = null
    this.tail = null
    this.length = 0

    function Node(element) {
        this.pre = null
        this.next = null
        this.element = element
    }

    // 添加
    DoublyLinkedList.prototype.append = (element) => {
        const newNode = new Node(element)
        // 是否是头部
        if (this.length === 0) {
            this.head = newNode
            this.tail = newNode
        } else {
            let current = this.head
            while(current.next) {
                current = current.next
            }
            current.next = newNode
            newNode.pre = current
            this.tail = newNode
        }
        this.length += 1
    }

    // 打印
    DoublyLinkedList.prototype.toString = () => {
        let current = this.head
        let str = ''
        while(current) {
            str += current.element + ' '
            current = current.next
        }
        return str
    }

    // 正向遍历
    DoublyLinkedList.prototype.forwardString = () => {
        let current = this.head
        let str = ''
        while(current) {
            str += current.element + ' '
            current = current.next
        }
        return str
    }

    // 反向遍历
    DoublyLinkedList.prototype.backwordString = () => {
        let current = this.tail
        let str = ''
        while(current) {
            str += current.element + ' '
            current = current.pre
        }
        return str
    }

    // 返回元素个数
    DoublyLinkedList.prototype.size = () => {
        return this.length
    }

    // 是否为空
    DoublyLinkedList.prototype.isEmpty = () => {
        if (this.length === 0) {
            return true
        } else {
            return false
        }
    }

    //  特定位置插入
    DoublyLinkedList.prototype.insert = (position, element) => {
        if (position < 0 || position > this.length) {
            return false
        }
        let newNode = new Node(element)
        // 是否是头部插入
        if (position === 0) {
            newNode.pre = null
            newNode.next = this.head
            this.head = newNode
        } 
        // 是否是最后尾部插入
        if (position === this.length) {
            this.append(element)
            return true
        } else {
            let current = this.head
            let pre = null
            let index = 0
            while(index++ < position) {
                pre = current
                current = current.next
            }
            pre.next = newNode
            newNode.pre = pre
            newNode.next = current
            current.pre = newNode
        }
        this.length += 1
        return true
    }

    // 获取对应位置的元素
    DoublyLinkedList.prototype.get = (position) => {
        if (position < 0 || position >= this.length) {
            return false
        }
        let current = this.head
        let index = 0
        while(index++ < position) {
            current = current.next
        }
        return current.element
    }

    // 获取元素对应的索引
    DoublyLinkedList.prototype.indexOf = (element) => {
        let current = this.head
        let index = 0
        while(current) {
            if (current.element === element) {
                return index
            } else {
                current = current.next
                index += 1
            } 
        }
        return -1
    }

    // 修改值
    DoublyLinkedList.prototype.update = (position, element) => {
        if (position < 0 || position >= this.length) {
            return false
        }
        let current = this.head
        let index = 0
        while(index++ < position) {
            current = current.next
        }
        current.element = element
        return true
    }

    // 移除某一个位置的项
    DoublyLinkedList.prototype.removeAt = (position) => {
        if (position < 0 || position >= this.length) {
            return false
        }
        // 是否移除的是首位
        if (position === 0) {
            this.head = this.head.next
            this.head.pre = null
        }
        // 是否移除的是尾部
        else if (position === this.length - 1) {
            this.tail.pre.next = null
            this.tail = this.tail.pre
        } else {
            let current = this.head
            let index = 0
            while(index++ < position) {
                current = current.next
            }
            current.pre.next = current.next
            current.next.pre = current.pre 
        }
        this.length -= 1
    }

    // 移除某一个元素
    DoublyLinkedList.prototype.remove = (element) => {
        let current = this.head
        let index = 0
        while(current) {
            if (current.element === element) {
                this.removeAt(index)
                return true
            } else {
                current = current.next
                index += 1
            }
        }
        return false
    }
}