进修javascript数据结构(二)——链表

媒介

人生老是直向前行走,从不留下什么。

原文地点:进修javascript数据构造(二)——链表

博主博客地点:Damonare的个人博客

正文

链表简介

    上一篇博客-进修javascript数据构造(一)——栈和行列说了栈和行列在javascript中的完成,我们应用javascript供应的API很轻易的完成了栈和行列,但这类数据构造有一个很明显的瑕玷,由于数组大小是牢固的所以我们在移除或是增加一项数据的时刻本钱很高,基本都须要吧数据重排一次。(javascript的Array类要领虽然很轻易但背地的道理同样是如许的)

    比拟数组我们本日主角——链表就要来的随性的多,简朴的邃晓可所以如许:在内存中,栈和行列(数组)的存在就是一个团体,假如想要对她内部某一个元素举行移除或是增加一个新元素就要动她内部一切的元素,所谓牵一发而动全身;而链表则不一样,每个元素都是由元素自身数据和指向下一个元素的指针组成,所以增加或是移除某一个元素不须要对链表团体举行操纵,只须要转变相干元素的指针指向就能够了。

    链表在实际生活中的例子也有许多,比方自行车的链条,环环相扣,但增加或是移除某一个环节只须要对症下药,对相干环节举行操纵就OK。再比方:火车,火车就是一个链表,每一节车箱就是元素,想要移除或是增加某一节车箱,只须要把衔接车箱的链条转变一下就好了。那末,在javascript中又该怎样去完成链表构造呢?

链表的竖立

起首我们要竖立一个链表类:

function LinkedList(){
    //种种属性和要领的声明
}

然后我们须要一种数据构造来保留链表内里的数据:

var Node=function(element){
    this.element=element;
    this.next=null;
}
//Node类示意要增加的元素,他有两个属性,一个是element,示意增加到链表中的详细的值;另一个是next,示意要指向链表中下一个元素的指针。

接下来,我们须要给链表声明一些要领:

  • append(element):向链表尾部增加一个新的元素;

  • insert(position,element):向链表特定位置插进去元素;

  • remove(element):从链表移除一项;

  • indexOf(element):返回链表中某元素的索引,假如没有返回-1;

  • removeAt(position):从特定位置移除一项;

  • isEmpty():推断链表是不是为空,假如为空返回true,不然返回false;

  • size():返回链表包括的元素个数;

  • toString():重写继续自Object类的toString()要领,由于我们运用了Node类;

链表的完全代码:

function LinkedList() {
    //Node类声明
    let Node = function(element){
        this.element = element;
        this.next = null;
    };
    //初始化链表长度
    let length = 0;
    //初始化第一个元素
    let head = null;
    this.append = function(element){
        //初始化增加的Node实例
        let node = new Node(element),
            current;
        if (head === null){
            //第一个Node实例进入链表,以后在这个LinkedList实例中head就不再是null了
            head = node;
        } else {
            current = head;
            //轮回链表晓得找到末了一项,轮回终了current指向链表末了一项元素
            while(current.next){
                current = current.next;
            }
            //找到末了一项元素后,将他的next属性指向新元素node,j竖立链接
            current.next = node;
        }
        //更新链表长度
        length++;
    };
    this.insert = function(position, element){
        //搜检是不是越界,凌驾链表长度或是小于0一定不符合逻辑的
        if (position >= 0 && position <= length){
            let node = new Node(element),
                current = head,
                previous,
                index = 0;
            if (position === 0){
                //在第一个位置增加
                node.next = current;
                head = node;
            } else {
                //轮回链表,找到准确位置,轮回终了,previous,current分别是被增加元素的前一个和后一个元素
                while (index++ < position){
                    previous = current;
                    current = current.next;
                }
                node.next = current;
                previous.next = node;
            }
            //更新链表长度
            length++;
            return true;
        } else {
            return false;
        }
    };
    this.removeAt = function(position){
        //搜检是不是越界,凌驾链表长度或是小于0一定不符合逻辑的
        if (position > -1 && position < length){
            let current = head,
                previous,
                index = 0;
            //移除第一个元素
            if (position === 0){
                //移除第一项,相当于head=null;
                head = current.next;
            } else {
                //轮回链表,找到准确位置,轮回终了,previous,current分别是被增加元素的前一个和后一个元素
                while (index++ < position){
                    previous = current;
                    current = current.next;
                }
                //链接previous和current的下一个元素,也就是把current移除了
                previous.next = current.next;
            }
            length--;
            return current.element;
        } else {
            return null;
        }
    };
    this.indexOf = function(element){
        let current = head,
            index = 0;
        //轮回链表找到元素位置
        while (current) {
            if (element === current.element) {
                return index;
            }
            index++;
            current = current.next;
        }
        return -1;
    };
    this.remove = function(element){
        //挪用已声明过的indexOf和removeAt要领
        let index = this.indexOf(element);
        return this.removeAt(index);
    };
    this.isEmpty = function() {
        return length === 0;
    };
    this.size = function() {
        return length;
    };
    this.getHead = function(){
        return head;
    };
    this.toString = function(){
        let current = head,
            string = '';
        while (current) {
            string += current.element + (current.next ? ', ' : '');
            current = current.next;
        }
        return string;
    };
    this.print = function(){
        console.log(this.toString());
    };
}
//一个实例化后的链表,内里是增加的数个Node类的实例

ES6版本:

let LinkedList2 = (function () {
    class Node {
        constructor(element){
            this.element = element;
            this.next = null;
        }
    }
    //这里我们运用WeakMap对象来纪录长度状况
    const length = new WeakMap();
    const head = new WeakMap();
    class LinkedList2 {
        constructor () {
            length.set(this, 0);
            head.set(this, null);
        }
        append(element) {
            let node = new Node(element),
                current;
            if (this.getHead() === null) {
                head.set(this, node);
            } else {
                current = this.getHead();
                while (current.next) {
                    current = current.next;
                }
                current.next = node;
            }
            let l = this.size();
            l++;
            length.set(this, l);
        }
        insert(position, element) {
            if (position >= 0 && position <= this.size()) {

                let node = new Node(element),
                    current = this.getHead(),
                    previous,
                    index = 0;
                if (position === 0) {
                    node.next = current;
                    head.set(this, node);
                } else {
                    while (index++ < position) {
                        previous = current;
                        current = current.next;
                    }
                    node.next = current;
                    previous.next = node;
                }
                let l = this.size();
                l++;
                length.set(this, l);
                return true;
            } else {
                return false;
            }
        }
        removeAt(position) {
            if (position > -1 && position < this.size()) {
                let current = this.getHead(),
                    previous,
                    index = 0;
                if (position === 0) {
                    head.set(this, current.next);
                } else {
                    while (index++ < position) {
                        previous = current;
                        current = current.next;
                    }
                    previous.next = current.next;
                }
                let l = this.size();
                l--;
                length.set(this, l);
                return current.element;
            } else {
                return null;
            }
        }
        remove(element) {
            let index = this.indexOf(element);
            return this.removeAt(index);
        }
        indexOf(element) {
            let current = this.getHead(),
                index = 0;
            while (current) {
                if (element === current.element) {
                    return index;
                }
                index++;
                current = current.next;
            }
            return -1;
        }
        isEmpty() {
            return this.size() === 0;
        }
        size() {
            return length.get(this);
        }
        getHead() {
            return head.get(this);
        }
        toString() {
            let current = this.getHead(),
                string = '';
            while (current) {
                string += current.element + (current.next ? ', ' : '');
                current = current.next;
            }
            return string;

        }
        print() {
            console.log(this.toString());
        }
    }
    return LinkedList2;
})();

双向链表

function DoublyLinkedList() {
    let Node = function(element){
        this.element = element;
        this.next = null;
        this.prev = null; //NEW
    };
    let length = 0;
    let head = null;
    let tail = null; //NEW
    this.append = function(element){
        let node = new Node(element),
            current;
        if (head === null){
            head = node;
            tail = node; //NEW
        } else {
            //NEW
            tail.next = node;
            node.prev = tail;
            tail = node;
        }
        length++;
    };
    this.insert = function(position, element){
        if (position >= 0 && position <= length){
            let node = new Node(element),
                current = head,
                previous,
                index = 0;
            if (position === 0){
                if (!head){       //NEW
                    head = node;
                    tail = node;
                } else {
                    node.next = current;
                    current.prev = node; //NEW
                    head = node;
                }
            } else  if (position === length) { ////NEW
                current = tail;   
                current.next = node;
                node.prev = current;
                tail = node;
            } else {
                while (index++ < position){
                    previous = current;
                    current = current.next;
                }
                node.next = current;
                previous.next = node;
                current.prev = node; //NEW
                node.prev = previous; //NEW
            }
            length++;
            return true;
        } else {
            return false;
        }
    };
    this.removeAt = function(position){
        if (position > -1 && position < length){
            let current = head,
                previous,
                index = 0;
            if (position === 0){ //NEW
                if (length === 1){ //
                    tail = null;
                } else {
                    head.prev = null;
                }
            } else if (position === length-1){  //NEW
                current = tail;
                tail = current.prev;
                tail.next = null;
            } else {
                while (index++ < position){
                    previous = current;
                    current = current.next;
                }
                previous.next = current.next;
                current.next.prev = previous; //NEW
            }
            length--;
            return current.element;
        } else {
            return null;
        }
    };
    this.remove = function(element){
        let index = this.indexOf(element);
        return this.removeAt(index);
    };
    this.indexOf = function(element){
        let current = head,
            index = -1;
        if (element == current.element){
            return 0;
        }
        index++;
        while(current.next){
            if (element == current.element){
                return index;
            }
            current = current.next;
            index++;
        }
        //check last item
        if (element == current.element){
            return index;
        }
        return -1;
    };
    this.isEmpty = function() {
        return length === 0;
    };
    this. size = function() {
        return length;
    };
    this.toString = function(){
        let current = head,
            s = current ? current.element : '';
        while(current && current.next){
            current = current.next;
            s += ', ' + current.element;
        }
        return s;
    };
    this.inverseToString = function() {
        let current = tail,
            s = current ? current.element : '';
        while(current && current.prev){
            current = current.prev;
            s += ', ' + current.element;
        }
        return s;
    };
    this.print = function(){
        console.log(this.toString());
    };
    this.printInverse = function(){
        console.log(this.inverseToString());
    };
    this.getHead = function(){
        return head;
    };
    this.getTail = function(){
        return tail;
    }
}

    双向链表和单项比起来就是Node类多了一个prev属性,也就是每个node不仅唯一一个指向它背面元素的指针也有一个指向它前面的指针。

轮回链表

    邃晓了前面的基本链表和双向链表以后这个一定不在话下了,轮回,实在就是全部链表实例变成了一个圈,在单项链表中末了一个元素的next属性为null,如今让它指向第一个元素也就是head,那末他就成了单向轮回链表。在双向链表中末了一个元素的next属性为null,如今让它指向第一个元素也就是head,那末他就成了双向轮回链表。就那末回事…

跋文

说到如今一向都是线性表,就是递次数据构造,他们都是有递次的,数据都是一条绳索上的蚂蚱。那末,假如数据是没有递次的呢?那又该运用哪一种数据构造呢?这个放到[进修javascript数据构造(三)——鸠合]中进修。

    原文作者:damonare
    原文地址: https://segmentfault.com/a/1190000007469957
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞