JavaScript-链表

《Javascript数据结构与算法》第五章

5.1 链表数据结构

链表不同与数组

  • 数组要插入或者移入一个元素的成本很高,因为所有元素都需要移动位置。
  • 链表插入或者移动一个元素时很高效,因为并不需要移动其他的元素位置。

链表存储元素的方式,在内存中不是有顺序的,每一个元素由

  • 1.存储元素本身的节点
  • 2.指向一下元素的指针组成

5.2 创建链表

5.2.0 创建链表的骨架
  • 1.链表需要有一个 Node 类,表示要加入链表的项,它包括 2 个部分,一个是该项的值,和一个只想下一项的指针
  • 2.链表还需要个表示链表长度的属性 length
  • 3.表示第一项的引用 head
  • 4.和一系列增删改查、查询长度的方法
function LinkedList() {
    function Node(element) {
        this.element = element;
        this.next = null;
    }

    this.length = 0;
    this.head = null;

    this.append = function(element) {};
    this.insert = function(position, element) {};
    this.remove = function(position) {};
}
5.2.1 append,向链表尾部添加元素
this.append = function(element) {
    var node = new Node(element); //此时node实例 {element:'111',next:null}

    this.length + 1;

    if (this.head === null) {
        this.head = node;
    } else {
        //插入到最后一项,但是由于没有顺序,所以我们没法直接得到链表的最后一项,只能while循环next为null
        let lastNode = head;
        while (lastNode.next !== null) {
            lastNode = lastNode.next;
        }
        lastNode.next = node;
    }
};
5.2.2 removeAt 从链表中删除元素

思路就是分 2 个情况

  • 如果要删除第 0 项,就把 head 指向 head.next 就行了
  • 如果要删除第 n 项,需要 while 循环找到这当前这个 current 项目,将 current 的前一项的 next,越过 current,指向指向 current 的下一项

这样当前元素被丢弃在计算机内存中,就等着被垃圾回收机制,自己回收了。

this.removeAt = function(position) {
    // 检查是否position参数的边界
    if (position > -1 && position < length) {
        let current = head,
            previous, // 表示position上一项元素
            index = 0;

        if (position === 0) {
            head = current.next;
        } else {
            // 如果index++,一直到index追上position时,那么这个current就是position索引对应的元素了
            while (index++ < position) {
                previous = current;
                current = current.next;
            }
            // 让position对应的元素的,上一项的next,越过要删除的这一项,直接指向下一项元素就好了
            previous.next = current.next;
        }
        length--;
        return current;
    } else {
        return null;
    }
};
5.2.3 insert 在某个位置插入
this.insert = function(position, element) {
    if (position >= 0 && position < length) {
        let node = new Node(element);
        let index = 0;
        let current = head;
        let previous;
        if (position === 0) {
            node.next = current;
            head = node;
        } else {
            while (index++ < position) {
                previous = current;
                current = current.next;
            }
            node.next = current;
            previous.next = node;
        }
        length++;
        return true;
    } else {
        return false;
    }
};
5.2.4 toString 打印链表
this.toString = function() {
    let current = head;
    let str = "";
    while (current) {
        str += current.element + (current.next ? " - " : "");
        current = current.next;
    }
    return str;
};
5.2.5 size 获取链表长度
this.size = function() {
    return length;
};

双向链表骨架

以上是单向链表的JS实现,实际上链表还有多种不同的类型,比如双向链表、循环链表

双向链表和单向链表的一个区别在于,每一个item,不仅仅包括value和next指针,还包括prev指针

同时双向链表不仅仅保存head,也保存最后一项的引用。

这样的好处是: 迭代单向链表时,如果错过了某一项,只能重新迭代,但是双向链表就找到上一项

function DoublyLinkedList(){
    let Node = function(){
        this.element = element;
        this.next = null;
        this.prev = null;  // 指向上一项的指针
    }

    let length = 0;
    let head = null;
    let tail = null;  // 保存最后一项的索引
}

循环链表

循环链表,是指最后一项的指针不是null,而是指向第一个元素的一种链表。

所以循环链表,有可能是单向链表,也可能是双向链表

双向循环链表,最后一项的指针指向head,第一项的指针指向tail


Ziwei
4.1k 声望420 粉丝

前端程序员