js 實現數據結構 -- 鏈表(LinkedList)


原文:

  在 Javascript 中學習數據結構與算法。

 

概念: 

  鏈表存儲有序的元素集合,但不同於數組,鏈表中的元素在內存中並不是連續放置的。每個 元素由一個存儲元素本身的節點和一個指向下一個元素的引用(也稱指針或鏈接)組成。下圖展示了鏈表的結構: 

  相對於傳統的數組,鏈表的一個好處在於,添加或移除元素的時候不需要移動其他元素。然而,鏈表需要使用指針,因此實現鏈表時需要額外注意。 數組的另一個細節是可以直接訪問任何位置的任何元素,而要想訪問鏈表中間的一個元素,需要從起點(表頭)開始迭代列表直到找到所需的元素。

 

普通鏈表:

// 鏈表節點
class Node {
    constructor(element) {
        this.element = element;
        this.next = null;
    }
}

// 鏈表
class LinkedList {
    constructor() {
        this.head = null;
        this.length = 0; // length 同數組 length 與下標關系
    }

    // 追加元素
    append(element) {
        let node = new Node(element);
        let current = null;  // 指針?

        if (this.head === null) {
            this.head = node;
        } else {
            current = this.head;
            while (current.next) {
                current = current.next;
            }
            current.next = node;
        }
        this.length++;
    }

    // 任意位置插入元素
    insert (position, element) {
        if (position >= 0 && position <= this.length) {
            let node = new Node(element);
            let current = this.head;
            let previous = null;
            let index = 0;
            if (position === 0) {
                this.head = node;
            } else {
                while (index++ < position) {
                    previous = current;
                    current = current.next;
                }
                node.next = current;
                previous.next = node;
            }
            this.length++;
            return true
        } 
        return false
    }

    // 移除指定位置元素
    removeAt(position) {
        if (position > -1 && position < length) {
            let current = this.head;
            let previous = null;
            let index = 0;
            if (position === 0) {
                this.head = current.next;
            } else {
                while(index++ < position) {
                    previous = current;
                    current = current.next;
                }
                previous.next = current.next;
            }
            this.length--;
            return current.element;
        }
        return null
    }

    // 尋找元素下標
    findIndex(element) {
        let current = this.head;
        let index = -1;
        while (current) {
            if (element === current.element) {
                return index + 1;
            }
            index++;
            current = current.next;
        }

        return -1;
    }

    // 刪除指定文檔
    remove(element) {
        let index = this.findIndex(element);
        return removeAt(index);
    }

    isEmpty() {
        return !this.length;
    }

    size() {
        return this.length;
    }

    // 輸出字符串
    toString() {
        let current = this.head;
        let string = '';
        while (current) {
            string += ` ${current.element}`;
            current = current.next;
        }
        return string;
    }
}

var ll = new LinkedList();
console.log(ll);
ll.append(2);
ll.append(6);
ll.append(24);
ll.append(152);

ll.insert(3, 18);
console.log(ll);
console.log(ll.findIndex(24));

 

雙向鏈表:

class Node {
    constructor(element) {
        this.element = element;
        this.prev = null;
        this.next = null;
    }
}

// 雙向鏈表
class DoubleLinkedList {
    constructor() {
        this.head = null;
        this.tail = null;
        this.length = 0;
    }

    // 任意位置插入元素
    insert(position, element) {
        if (position >= 0 && position <= ehis.length) {
            let node = new Node(element);
            let current = this.head;
            let previous = null;
            this.index = 0;
            // 首位
            if (position === 0) {
                if (!head) {
                    this.head = node;
                    this.tail = node;
                } else {
                    node.next = current;
                    this.head = node;
                    current.prev = node;
                }
            } else if (position === this.length) { // 末尾
                current = this.tail;
                current.next = node;
                node.prev = current;
                this.tail = node;
            } else {  // 中間
                while(index++ < position) {
                    previous = current;
                    current = current.next;
                }
                node.next = current;
                previous.next = node;
                current.prev = node;
                node.prev = previous;
            }
            this.length++;
            return true;
        }
        return false;
    }
    // 移除指定位置元素
    removeAt(position) {
        if (position > -1 && position < this.length) {
            let current = this.head;
            let previous = null;
            let index = 0;

            // 首位
            if (position === 0) {
                this.head = this.head.next
                this.head.prev = null
                if (this.length === 1) {
                    this.tail = null
                }
            } else if (position === this.length - 1) { // 末位
                this.tail = this.tail.prev
                this.tail.next = null
            } else { // 中位
                while (index++ < position) {
                     previous = current
                     current = current.next
                }
                previous.next = current.next
                current.next.prev = previous
            }
            this.length--;
            return current.element;
        } else {
            return null;
        }
    }

    // 其他方法
}

 

循環鏈表:

  具體代碼實現就不寫了,下圖是示意圖


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM