JS数据结构3:链表

单链表链表结构的实现

在这里插入图片描述

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

class LinkedList {
    constructor() {
        this.length = 0;
        this.head = null;
    }

    equalsFn(a, b) {
        return a === b;
    }
}

功能

  1. push(element):向链表尾部添加一个新元素。
  2. insert(element, position):向链表的特定位置插入一个新元素。
  3. getElementAt(index):返回链表中特定位置的元素。如果链表中不存在这样的元素,则返回undefined。
  4. remove(element):从链表中移除一个元素。
  5. indexOf(element):返回元素在链表中的索引。如果链表中没有该元素则返回-1。
  6. removeAt(position):从链表的特定位置移除一个元素。
  7. isEmpty():如果链表中不包含任何元素,返回true,如果链表长度大于0 则返回false。
  8. size():返回链表包含的元素个数,与数组的length 属性类似。
  9. toString():返回表示整个链表的字符串。由于列表项使用了Node 类,就需要重写继承自JavaScript 对象默认的toString 方法,让其只输出元素的值。

push

    push(val) {
        let newNode = new Node(val);
        let curr;
        if (!this.head) {   // 刚开始链表为空,就把这个设置为head
            this.head = newNode;
        } else {
            curr = this.head;
            while (curr.next) {    // 一直找到链表末尾
                curr = curr.next;
            }
            curr.next = newNode;
        }
        this.length++;
    }

removeAt

在这里插入图片描述

    removeAt(index) {
        if (index < this.length && index >= 0) {
            let curr = this.head;
            if (index === 0) {
                this.head = curr.next;
            } else {
                // 找到index前一个后停止,下一个就是要删除的结点
                for (let i = 1; i < index; i++) {
                    curr = curr.next;
                }
                let beRemove = curr.next;
                // 改变要被删除结点的上一个结点的指向
                curr.next = beRemove.next;
                this.length--;
                return beRemove;
            }
        }
    }

getElementAt

    getElementAt(index) {
        if (index < this.length && index >= 0) {
            let curr = this.head;
            if (index === 0) return curr;
            else {
                for (let i = 1; i <= index; i++) {
                    curr = curr.next;
                }
                return curr;
            }
        }
    }

重写removeAt

    removeAt(index) {
        let curr = this.getElementAt(index - 1);
        curr.next = curr.next.next;

insert

在这里插入图片描述

    insert(index, value) {
        let newNode = new Node(value);
        if (index < this.length && index >= 0) {
            let curr = this.head;
            if (index === 0) {  // index 为0,改变头结点指向就行了
                this.head = newNode;
                this.head.next = curr;
            } else {
                // 找到插入位置的前一个,
                for (let i = 1; i < index; i++) {
                    curr = curr.next;
                }
                let nextNode = curr.next;
                curr.next = newNode;
                newNode.next = nextNode;
            }
            this.length++;
        }
    }

indexOf

    indexOf(value) {
        let curr = this.head;   // 存入head
        if (this.equalsFn(curr.value, value)) {
            return 0;
        }
        for (let i = 1; i < this.length; i++) {
            curr = curr.next;
            if (this.equalsFn(curr.value, value)) {
                return i;
            }
        }

        return -1;
    }

removeValue

    removeValue(value) {
        let curr = this.head;
        let prev = null;
        if (this.equalsFn(curr.value, value)) {
            this.head = curr.next;
            this.length--;
        }
        for (let i = 1; i < this.length; i++) {
            prev = curr;
            curr = curr.next;
            if (this.equalsFn(curr.value, value)) {
                prev.next = curr.next;
                this.length--;
            }
        }
        return undefined;
    }

toString

    toString() {
        let objString = "";
        let curr = this.head;
        if (!curr) {
            return objString;
        } else {
            objString = `${curr.value}`;
            for (let i = 1; i < this.length; i++) {
                curr = curr.next;
                objString = `${objString}, ${curr.value}`;
            }
            return objString;
        }
    }

完整代码

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

class LinkedList {
    constructor() {
        this.length = 0;
        this.head = null;
    }

    equalsFn(a, b) {
        return a === b;
    }

    push(val) {
        let newNode = new Node(val);
        let curr;
        if (!this.head) {   // 刚开始链表为空,就把这个设置为head
            this.head = newNode;
        } else {
            curr = this.head;
            while (curr.next) {    // 一直找到链表末尾
                curr = curr.next;
            }
            curr.next = newNode;
        }
        this.length++;
    }

    removeAt(index) {

        let curr = this.getElementAt(index - 1);
        curr.next = curr.next.next;
    }

    getElementAt(index) {
        if (index < this.length && index >= 0) {
            let curr = this.head;
            if (index === 0) return curr;
            else {
                for (let i = 1; i <= index; i++) {
                    curr = curr.next;
                }
                return curr;
            }
        }
    }

    insert(index, value) {
        let newNode = new Node(value);
        if (index < this.length && index >= 0) {
            let curr = this.head;
            if (index === 0) {  // index 为0,改变头结点指向就行了
                this.head = newNode;
                this.head.next = curr;
            } else {
                // 找到插入位置的前一个,
                for (let i = 1; i < index; i++) {
                    curr = curr.next;
                }
                let nextNode = curr.next;
                curr.next = newNode;
                newNode.next = nextNode;
            }
            this.length++;
        } else {
            throw "索引值错误";
        }
    }

    indexOf(value) {
        let curr = this.head;   // 存入head
        if (this.equalsFn(curr.value, value)) {
            return 0;
        }
        for (let i = 1; i < this.length; i++) {
            curr = curr.next;
            if (this.equalsFn(curr.value, value)) {
                return i;
            }
        }

        return -1;
    }

    removeValue(value) {
        let curr = this.head;
        let prev = null;
        if (this.equalsFn(curr.value, value)) {
            this.head = curr.next;
            this.length--;
        }
        for (let i = 1; i < this.length; i++) {
            prev = curr;
            curr = curr.next;
            if (this.equalsFn(curr.value, value)) {
                prev.next = curr.next;
                this.length--;
            }
        }
        return undefined;
    }

    toString() {
        let objString = "";
        let curr = this.head;
        if (!curr) {
            return objString;
        } else {
            objString = `${curr.value}`;
            for (let i = 1; i < this.length; i++) {
                curr = curr.next;
                objString = `${objString}, ${curr.value}`;
            }
            return objString;
        }
    }

    getHead() {
        return this.head;
    }

    isEmpty() {
        return this.length === 0 ? true : false;
    }

    size() {
        return this.length;
    }
}

let linkedList = new LinkedList();
linkedList.push("a");
linkedList.push("b");
linkedList.push("c");
// linkedList.removeAt(1);
linkedList.insert(1, "aa");
console.log(linkedList.getElementAt(2));
console.log(linkedList.indexOf("a"));
console.log(linkedList.removeValue("c"));
console.log(linkedList.size());
console.log(linkedList.isEmpty());
console.log(linkedList);
console.log(linkedList.toString());

双向链表的实现

在这里插入图片描述

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

class DBLinkedList {
    constructor() {
        this.length = 0;
        this.head = null;
    }

    equalsFn(a, b) {
        return a === b;
    }
}

双向链表需要讨论的情况

  1. 当结点为头结点时
  2. 当结点为最后一个结点时
  3. 当结点有且只有一个结点时

重构链表方法

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

class DBLinkedList {
    constructor() {
        this.length = 0;
        this.head = null;
    }

    equalsFn(a, b) {
        return a === b;
    }

    push(val) {
        let newNode = new Node(val);
        let prev = this.head;
        let curr;
        if (!this.head) {   // 刚开始链表为空,就把这个设置为head
            this.head = newNode;
        } else {
            curr = this.head;
            while (curr.next) {    // 一直找到链表末尾
                curr = curr.next;
                prev = curr;
            }
            curr.next = newNode;
            newNode.prev = prev;
        }
        this.length++;
    }

    removeAt(index) {
        if (index < this.length && index >= 0) {
            let curr = this.head;
            if (index === 0) {
                this.head = curr.next;
                if (this.length !== 1) {
                    this.head.prev = null;
                }
                this.length--;
            } else {
                // 找到index前一个后停止,下一个就是要删除的结点
                for (let i = 1; i < index; i++) {
                    curr = curr.next;
                }
                let beRemove = curr.next;
                // 改变要被删除结点的上一个结点的指向
                curr.next = beRemove.next;
                if (index !== this.length - 1) {
                    beRemove.next.prev = curr;
                }
                this.length--;
                return beRemove;
            }
        }
    }

    getElementAt(index) {
        if (index < this.length && index >= 0) {
            let curr = this.head;
            if (index === 0) return curr;
            else {
                for (let i = 1; i <= index; i++) {
                    curr = curr.next;
                }
                return curr;
            }
        }
    }

    insert(index, value) {
        let newNode = new Node(value);
        if (index < this.length && index >= 0) {
            let curr = this.head;
            if (index === 0) {  // index 为0,改变头结点指向就行了
                this.head = newNode;
                this.head.next = curr;
                if (this.length > 1) {
                    this.head.prev = null;
                }
            } else {
                // 找到插入位置的前一个,
                for (let i = 1; i < index; i++) {
                    curr = curr.next;
                }
                let nextNode = curr.next;
                curr.next = newNode;
                newNode.prev = curr;
                newNode.next = nextNode;
                if (index !== this.length - 1) {
                    nextNode.prev = newNode;
                }
            }
            this.length++;
        } else {
            throw "索引值错误";
        }
    }

    indexOf(value) {
        let curr = this.head;   // 存入head
        if (this.equalsFn(curr.value, value)) {
            return 0;
        }
        for (let i = 1; i < this.length; i++) {
            curr = curr.next;
            if (this.equalsFn(curr.value, value)) {
                return i;
            }
        }

        return -1;
    }

    removeValue(value) {
        let curr = this.head;
        let prev = null;
        if (this.equalsFn(curr.value, value)) {
            this.head = curr.next;
            if (this.head) {
                this.head.prev = null;
            }
            this.length--;
        }
        for (let i = 1; i < this.length; i++) {
            prev = curr;
            curr = curr.next;
            if (this.equalsFn(curr.value, value)) {
                prev.next = curr.next;
                if (curr.next) {
                    curr.next.prev = prev;
                }
                this.length--;
            }
        }
        return undefined;
    }

    toString() {
        let objString = "";
        let curr = this.head;
        if (!curr) {
            return objString;
        } else {
            objString = `${curr.value}`;
            for (let i = 1; i < this.length; i++) {
                curr = curr.next;
                objString = `${objString}, ${curr.value}`;
            }
            return objString;
        }
    }

    getHead() {
        return this.head;
    }

    isEmpty() {
        return this.length === 0 ? true : false;
    }

    size() {
        return this.length;
    }
}

循环链表的概念

在这里插入图片描述

  • 循环链表可以像链表一样只有单向引用,也可以像双向链表一样有双向引用。
  • 循环链表和链表之间唯一的区别在于,最后一个元素指向下一个元素的指针不是引用undefined,而是指向第一个元素(head)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值