JS實現單向鏈表、雙向鏈表、循環鏈表

https://cloud.tencent.com/developer/article/1114246

 

鏈表存儲有序的元素的集合,但是和數組不同的是,鏈表中的元素在內存中的存儲並不是連續的。每一個鏈表元素都包含了一個存儲元素本身的節點一個指向下一個元素的引用。看起來就像這樣:

  相對於傳統的數組,鏈表的一個好處就是增刪的時候無需移動其它元素,只要更改指針的指向就可以了。但是缺點就是如果想要訪問鏈表中的元素,需要從頭開始循環迭代到你想要的元素。

function LinkedList() {

    // Node輔助類,表示要加入列表的項,element是即將添加到列表的值,next是指向列表中下一個節點項的指針
    let Node = function (element) {
        this.element = element
        this.next = null
    }

    let length = 0
    let head = null

    // 向鏈表尾部追加元素
    this.append = function (element) {
        let node = new Node(element)
        let current
        if (head === null) { // 列表中第一個節點
            head = node
        } else {
            current = head
            while (current.next) {
                current = current.next // 找到最後一項,是null
            }
            current.next = node // 給最後一項賦值
        }
        length++ // 更新列表的長度
    }

    // 從鏈表中移除指定位置元素
    this.removeAt = function (position) {
        if (position > -1 && position < length) { // 值沒有越界
            let current = head
            let previous, index = 0
            if (position === 0) { //  移除第一項
                head = current.next
            } else {
                while (index++ < position) {
                    previous = current
                    current = current.next
                }
                previous.next = current.next // 將previous與current的下一項連接起來,跳過current,從而移除
            }
            length-- // 更新列表的長度
            return current.element
        } else {
            return null
        }
    }

    // 在鏈表任意位置插入一個元素
    this.insert = function (position, element) {
        if (position >= 0 && position <= length) { // 檢查越界值
            let node = new Node(element),
                current = head,
                previous,
                index = 0
            if (position === 0) { // 在第一個位置添加
                node.next = current
                head = node
            } else {
                while (index++ < position) {
                    previous = current
                    current = current.next
                }
                node.next = current // 在previous與current的下一項之間插入node
                previous.next = node
            }
            length++
            return true
        } else {
            return false
        }
    }

    // 把鏈表內的值轉換成一個字符串
    this.toString = function () {
        let current = head,
            string = ''
        while (current) {
            string += current.element + ' '
            current = current.next
        }
        return string
    }

    // 在鏈表中查找元素並返回索引值
    this.indexOf = function (element) {
        let current = head,
            index = 0
        while (current) {
            if (element === current.element) {
                return index
            }
            index++
            current = current.next
        }
        return -1
    }

    // 從鏈表中移除指定元素
    this.remove = function (element) {
        let index = this.indexOf(element)
        return this.removeAt(index)
    }

    this.isEmpty = function () {
        return length === 0
    }

    this.size = function () {
        return length
    }

    this.getHead = function () {
        return head
    }
}
let list = new LinkedList()
list.append(1)
list.append(2)
console.log(list.toString()) // 1 2
list.insert(0, 'hello')
list.insert(1, 'world')
console.log(list.toString()) // hello world 1 2
list.remove(1)
list.remove(2)
console.log(list.toString()) // hello world 
單鏈表有一個變種 - 循環鏈表,最後一個元素指向下一個元素的指針,不是引用null,而是指向第一個元素,只需要修改下最後的next指向爲head即可。
 
雙向鏈表與單鏈表的區別在於,在單鏈表中,一個節點只有鏈向下一個節點的鏈接,而在雙向鏈表中,鏈接是雙向的:一個鏈向下一個元素,另一個鏈向前一個元素。
  雙向鏈表提供了兩種迭代列表的方法:從頭到尾,或則反過來。在單鏈表中,如果我們在迭代列表中錯過了要找的元素,就需要回到列表的起點,重新開始迭代,這是雙向列表的優點。
  雙向鏈表與單向鏈表的實現類似,需要同時控制next、prev兩個指針,同時需要增加尾引用tail。
function DoubleLinkedList() {

        // Node輔助類,表示要加入列表的項,element是即將添加到列表的值,next是指向列表中下一個節點項的指針
        let Node = function (element) {
            this.element = element
            this.prev = null // 新增一個向前的指針
            this.next = null 
        }

        let length = 0
        let head = null
        let tail = null // 新增一個尾引用

        // 向鏈表尾部追加元素
        this.append = function (element) {
            let node = new Node(element)

            let current
            if (head === null) { // 列表中第一個節點
                head = node // head與tail是同一個元素
                tail = node
            } else {
                current = head
                while (current.next) {
                    current = current.next // 找到最後一項,是null
                }
                current.next = node // 給最後一項賦值
                node.prev = current
                tail = node // 修改尾引用
            }
            length++ // 更新列表的長度
        }

        // 從鏈表中移除指定位置元素
        this.removeAt = function (position) {
            if (position > -1 && position < length) { // 值沒有越界
                let current = head
                let previous,
                    index = 0
                if (position === 0) { //  移除第一項
                    head = current.next
                    if (length === 1) { // 只有一項
                        tail = null
                    } else {
                        head.prev = null
                    }
                } else if (position === length - 1) { // 移除最後一項
                    current = tail
                    tail = current.prev
                    tail.next = null
                }
                else {
                    while (index++ < position) {
                        previous = current
                        current = current.next
                    }
                    previous.next = current.next // 將previous與current的下一項連接起來,跳過current,從而移除
                    current.next.prev = previous
                }
                length-- // 更新列表的長度
                return current.element
            } else {
                return null
            }
        }

        // 在鏈表任意位置插入一個元素
        this.insert = function (position, element) {
            if (position >= 0 && position <= length) { // 檢查越界值
                let node = new Node(element),
                    current = head,
                    previous,
                    index = 0
                if (position === 0) { // 在第一個位置添加
                    if (!head) {
                        head = node
                        tail = node
                    }else {
                        node.next = current
                        current.prev = node
                        head = node
                    }
                    node.next = current
                    head = node
                } else if (position === length) {
                    current = tail
                    current.next = node
                    node.prev = current
                    tail = node
                } else {
                    while (index++ < position) {
                        previous = current
                        current = current.next
                    }
                    node.next = current // 在previous與current的下一項之間插入node
                    previous.next = node

                    current.prev = node
                    node.prev = previous
                }
                length++
                return true
            } else {
                return false
            }
        }

        // 把鏈表內的值轉換成一個字符串
        this.toString = function () {
            let current = head,
                string = ''
            while (current) {
                string += current.element + ' '
                current = current.next
            }
            return string
        }

        // 在鏈表中查找元素並返回索引值
        this.indexOf = function (element) {
            let current = head,
                index = 0
            while (current) {
                if (element === current.element) {
                    return index
                }
                index++
                current = current.next
            }
            return -1
        }

        // 從鏈表中移除指定元素
        this.remove = function (element) {
            let index = this.indexOf(element)
            return this.removeAt(index)
        }

        this.isEmpty = function () {
            return length === 0
        }

        this.size = function () {
            return length
        }

        this.getHead = function () {
            return head
        }
    }
    let list = new DoubleLinkedList()
    list.append(1)
    list.append(2)
    console.log(list.toString()) // 1 2
    list.insert(0, 'hello')
    list.insert(1, 'world')
    console.log(list.toString()) // hello world 1 2
    list.remove(1)
    list.remove(2)
    console.log(list.toString()) // hello world


 

轉載於:https://www.cnblogs.com/leftJS/p/11074346.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章