数据结构学习篇-单/双向链表

51 阅读1分钟

单向链表

方法
  • 向后追加
  • 转换成字符串
  • 下标插入
  • 下标删除
  • 根据位置获取元素
  • 根据元素删除
实现
function LinkList() {
    this.val = null;
    this.next = null;
    this.length = 0;
    // 定义了一个num 每次下标插入时使用并递增
    let num = 1;
    LinkList.prototype.createNode = function (item) {
        return {
            val: item,
            next: null,
        };
    };
    // 后追加
    LinkList.prototype.append = function (item) {
        if (this.val) {
            let curr = this
            while (curr.next) {
                curr = curr.next;
            }
            curr.next = this.createNode(item);
        } else {
            this.val = item;
        }
        this.length++;
    };
    // tostring
    LinkList.prototype.toString = function (interval = ',') {
        const result = [];
        this.length > 0 && result.push(this.val);
        let curr = this.next;
        while (curr) {
            result.push(curr.val);
            curr = curr.next;
        }
        return result.join(interval);
    };
    // 下标插入 insertAt
    LinkList.prototype.insertAt = function (position, item = num) {
        if (position > this.length || position < -this.length) return false;
        if (position < 0) {
            position = this.length + position;
        }
        const ele = this.createNode(item);
        if (position === 0) {
            this.next = {
                val: this.val,
                next: this.next,
            };
            this.val = item;
        } else if (position === 1) {
            ele.next = this.next;
            this.next = ele;
        } else {
            let curr = this.next;
            for (let i = 2; i < position; i++) {
                curr = curr.next;
            }
            ele.next = curr.next;
            curr.next = ele;
        }
        this.length++;
        num++;
        return this.toString();
    };
    // 下标删除 removeAt
    LinkList.prototype.removeAt = function (position) {
        if (position >= this.length || position < -this.length) return false;
        if (position < 0) {
            position = this.length + position;
        }
        let curr = this;
        let prev = null;
        let i = 0;
        let result = '';
        while (i++ < position) {
            prev = curr;
            curr = curr.next;
        }
        result = curr.val;
        if (prev) {
            prev.next = curr.next;
        } else {
            if (curr.next) {
                this.val = curr.next.val;
                this.next = curr.next.next;
            } else {
                // 删除到最后一个了
                this.val = null;
                this.next = null;
            }
        }
        this.length--;
        return result;
    };
    // 通过位置获取元素 indexOf
    LinkList.prototype.indexOf = function (position) {
        if (position >= linkList.length || position <= -linkList.length) return false;
        if (position < 0) {
            position = linkList.length + position;
        }
        let curr = this;
        for(let i = 0; i < position; i++) {
            curr = curr.next;
        }
        return curr.val;
    };
    // 根据元素删除 remove
    LinkList.prototype.remove = function (item) {
        let prev = null;
        let curr = this;
        for (let i = 0; i < this.length; i++) {
            if (curr.val === item) {
                if (prev) {
                    prev.next = curr.next;
                } else {
                    if (curr.next) {
                        // 第一个
                        this.val = curr.next.val;
                        this.next = curr.next.next;
                    } else {
                        // 没了
                        this.val = null;
                        this.next = null;
                    }
                }
            } else {
                prev = curr;
                curr = curr.next;
            }         
        }
    };
};

功能测试
let linkList = new LinkList();
linkList.append("a");
linkList.append("b");
linkList.append("c");
linkList.insertAt(0);
linkList.insertAt(1);
linkList.insertAt(2);
linkList.insertAt(3);
linkList.insertAt(4);
linkList.insertAt(212); // false
linkList.insertAt(-3);
linkList.insertAt(-322);  // false
linkList.toString();   // '1,2,3,4,5,6,a,b,c'
linkList.removeAt(0); // 1
linkList.removeAt(1); // 2
linkList.toString();  // '2,4,5,6,a,b,c'
linkList.removeAt(2); // 1
linkList.toString();  // '2,4,6,a,b,c'
linkList.removeAt(5); // 5
linkList.toString();  // '2,4,6,a,b'
linkList.removeAt(0); // 2
linkList.removeAt(0); // 6
linkList.removeAt(0); // 1
linkList.removeAt(0); // b
linkList.removeAt(0); // false
linkList.toString();  // ''

双向链表

方法
  • 后追加
  • 正向遍历
  • 反向遍历
  • 根据位置添加
  • 根据位置删除
  • 获取元素位置
  • 根据元素删除
实现
function DoublyLinkList() {
    this.head = null;
    this.tail = null;
    this.length = 0;
    function createNode(item, prev, next) {
        return {
            val: item,
            prev,
            next,
        };
    }
    // 后追加
    DoublyLinkList.prototype.append = function(item) {
        if (this.length === 0) {
            this.head = this.tail = createNode(item, null, null);
        } else {
            let curr = this.head;
            while (curr.next) {
                curr = curr.next;
            }
            curr.next  = this.tail = createNode(item, curr, null);
        }
        this.length++;
    }
    // 正向遍历
    DoublyLinkList.prototype.forwardString = function() {
        if (!this.head) return '';
        let curr = this.head;
        let items = [];
        while (curr) {
            items.push(curr.val);
            curr = curr.next;
        }
        return items.join(',');
    }
    // 反向遍历
    DoublyLinkList.prototype.reverseString = function() {
        if (!this.tail) return '';
        let curr = this.tail;
        let items = [];
        while (curr) {
            items.push(curr.val);
            curr = curr.prev;
        }
        return items.join(',');
    }
    // 任意位置添加 insert
    DoublyLinkList.prototype.insert = function(item, position) {
        if ((!position && position !== 0) || position > this.length || -position - 1 > this.length) return false;
        if (position < 0) {
            position = this.length + position + 1;
        }
        let curr = this.head;
        let prev = null;
        // 如果链表为空
        if (!curr) {
            this.head = this.tail = createNode(item, null, null);
        } else {
            if (position === 0) {
                this.head = curr.prev = createNode(item, null, curr);
            } else {
                for (let i = 0; i < position; i++) {
                    prev = curr;
                    curr = curr.next;
                }
                prev.next = createNode(item, prev, curr);
                if (curr) {
                    curr.prev = prev.next
                } else {
                    // 添加到最后一个
                    this.tail = prev.next
                }
            }
        }
        this.length++;
    }
    this.forwardString();
    // 根据位置删除 removeAt
    DoublyLinkList.prototype.removeAt = function(position) {
        // 未传入位置
        if (!position && position !== 0) return false;
        // 传入位置不符合链表长度
        if (position >= this.length) return undefined;
        // 如果是负数
        if (position < 0) {
            position = this.length + position;
        }
        this.length--;
        let curr = this.head;
        let prev = null;
        for (let i = 0; i < position; i++) {
            prev = curr;          
            curr = curr.next;
        }
        if (curr.next) {
            if (prev) {
                // 中间的
                curr.next.prev = prev;
                prev.next = curr.next
            } else {
                // 第一个
                this.head = curr.next;
                this.head.prev = null;
            }
        } else {
            this.tail = prev;
            if (prev) {
                // 最后一个
                prev.next = null;
            } else {
                // 没了
                this.head = null;
            }
        }

        return curr.val;
    }
    // 获取元素位置 indexOf
    DoublyLinkList.prototype.indexOf = function(item) {
        if (!this.head) return -1;
        let curr = this.head;
        for (let i = 0; i < this.length; i++) {
            if (curr.val === item) {
                return i;
            }
            curr = curr.next;
        };
        return -1;
    }
    // 根据元素删除 remove
    DoublyLinkList.prototype.remove = function(item) {
        let i = this.indexOf(item);
        return i === -1 ? false : this.removeAt(i);
    }
}
功能测试
let doublyLinkList = new DoublyLinkList();
doublyLinkList.append(1);
doublyLinkList.append(2);
doublyLinkList.append(3);
doublyLinkList.forwardString(); // '1,2,3'
doublyLinkList.reverseString(); // '3,2,1'
doublyLinkList.insert(4, 0);
doublyLinkList.forwardString(); // '4,1,2,3'
doublyLinkList.reverseString(); // '3,2,1,4'
doublyLinkList.insert(5, 1);
doublyLinkList.forwardString(); // '4,5,1,2,3'
doublyLinkList.reverseString(); // '3,2,1,5,4'
doublyLinkList.insert(6, 5);
doublyLinkList.forwardString(); // '4,5,1,2,3,6'
doublyLinkList.reverseString(); // '6,3,2,1,5,4'
doublyLinkList.removeAt(0); // 4
doublyLinkList.forwardString(); // '5,1,2,3,6'
doublyLinkList.reverseString(); // '6,3,2,1,5'
doublyLinkList.removeAt(1); // 1
doublyLinkList.forwardString(); // '5,2,3,6'
doublyLinkList.reverseString(); // '6,3,2,5'
doublyLinkList.removeAt(3); // 6
doublyLinkList.forwardString(); // '5,2,3'
doublyLinkList.reverseString(); // '3,2,5'
doublyLinkList.removeAt(2); // 3
doublyLinkList.removeAt(1); // 2
doublyLinkList.removeAt(0); // 5
doublyLinkList.removeAt(0); // undefined
doublyLinkList.append(1);
doublyLinkList.append(2);
doublyLinkList.append(3);
doublyLinkList.forwardString(); // '1,2,3'
doublyLinkList.reverseString(); // '3,2,1'
doublyLinkList.indexOf(1);  // 0
doublyLinkList.indexOf(2);  // 1
doublyLinkList.indexOf(3);  // 2
doublyLinkList.indexOf(4);  // -1
doublyLinkList.remove(2);   // 1
doublyLinkList.remove(1);   // 0
doublyLinkList.remove(0);   // -1
doublyLinkList.remove(3);   // 0

参考

  • 小马哥 – JS数据结构与算法