数据结构与算法之链表

链表

JS中数组被实现成了对象,对比其他语言的数组效率很低。因此可以考虑使用链表来替代。除了对数据的随机访问,链表几乎可以用在任何使用以为数组的情况中。如果需要随机访问,数组仍然是更好的选择。

单向链表

链表是由一组节点组成的集合。 每个节点都使用一个对象的引用指向它的后继。 指向另一
个节点的引用叫做链。

遍历链表, 就是跟着链接, 从链表的首元素一直走到尾元素,下面最前面的节点叫做头节点,在最后面的尾元素指向一个null节点。

1555743953692

//  节点类
function Node(element){
    this.element = element;
    this.next = null;
}

//  LinkedList类,建立一个新的链表
function LList(){
    this.head = new Node("head");
}
LList.prototype = {
    constructor: LList,
    find(element){
        var node = this.head;
        while(node.element != element){
            if(node.next){
                node = node.next;
            }else{
                return null;
            }
        }
        return node;
    },
    insert(newElement, item){  //在item后面插入新元素
        var current = this.find(item);
        var newNode = new Node(newElement);
        newNode.next = current.next;
        current.next = newNode;
    },
    remove(item){
        var preNode = this.findPrevious(item);
        if(preNode.next !== null){
            preNode.next = preNode.next.next;     
        }
    },
    display(){  //不显示头节点
        var current = this.head;
        while(current.next !== null){
            console.log(current.next.element);
            current = current.next;
        }
    },
    findPrevious(item){  //用来查找该值节点的前一个节点
        var current = this.head;
        while(current.next.element !== item){
            if(current.next !== null){
                current = current.next;
            }else{
                return null;
            }
        }
        return current;
    }
}
双向链表

1555746606695

//  节点类
function Node(element){
    this.element = element;
    this.next = null;
    this.previous = null;
}

//  LinkedList类,建立一个新的链表
function LList(){
    this.head = new Node("head");
}
LList.prototype = {
    constructor: LList,
    find(element){
        var node = this.head;
        while(node.element != element){
            if(node.next){
                node = node.next;
            }else{
                return null;
            }
        }
        return node;
    },
    insert(newElement, item){  //在item后面插入新元素
        var current = this.find(item);
        var newNode = new Node(newElement);
        newNode.next = current.next;
        newNode.previous = current;
        current.next = newNode;
    },
    remove(item){  //双向链表删除节点效率更高了,因为不需要再查找前驱节点了
        var removeNode = this.find(item);
        if(removeNode){
            removeNode.previous.next = removeNode.next;
            removeNode.next.previous = removeNode.previous;
            removeNode.next = null;
            removeNode.previous = null;
        }
    },
    display(){  //不显示头节点
        var current = this.head;
        while(current.next !== null){
            console.log(current.next.element);
            current = current.next;
        }
    },
    findLast(){  //查找链表的最后一项
        var current = this.head;
        while(current.next !== null){
            current = current.next;
        }
        return current;
    },
    dispReverse(){
        var current = this.findLast();
        while(current.previous !== null){
            console.log(current.element);
            current = current.previous;
        }
    },
}
循环链表

循环链表和单向链表相似, 节点类型都是一样的。 唯一的区别是, 在创建循环链表时, 让其头节点的 next 属性指向它本身,这样插入节点都会使得链表的尾节点都指向头节点,形成一个循环链表。

1555760081924

如果你希望可以从后向前遍历链表, 但是又不想付出额外代价来创建一个双向链表, 那么就需要使用循环链表。 从循环链表的尾节点向后移动, 就等于从后向前遍历链表。

避免无限循环,需要对方法进行修改:

//  节点类
function Node(element){
    this.element = element;
    this.next = null;
}

//  LinkedList类,建立一个新的链表
function LList(){
    this.head = new Node("head");
    this.head.next = this.head;
}
LList.prototype = {
    constructor: LList,
    find(element){
        var node = this.head;
        while(node.element != element){
            if(node.next === this.head){
                return null;
            }
            node = node.next;
        }
        return node;
    },
    insert(newElement, item){  //在item后面插入新元素
        var current = this.find(item);
        var newNode = new Node(newElement);
        newNode.next = current.next;
        current.next = newNode;
    },
    remove(item){
        var preNode = this.findPrevious(item);
        preNode.next = preNode.next.next;     
    },
    display(){  //不显示头节点
        var current = this.head;
        while(current.next !== this.head){
            console.log(current.next.element);
            current = current.next;
        }
    },
    findPrevious(item){  //用来查找该值节点的前一个节点
        var current = this.head;
        while(current.next.element !== item){
            if(current.next === this.head){
                return null;
            }
            current = current.next;
        }
        return current;
    }
}
posted @ 2019-06-15 12:17  simple小前端  阅读(232)  评论(0编辑  收藏  举报