javascript 链表(lineked lists)算法与说明

来源:互联网 发布:自学编程用什么语言 编辑:程序博客网 时间:2024/06/06 01:11

链表的介绍

链表存储有序的元素集合,但不同于数组,链表中的元素在内存中并不是连续放置的。每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(也称为指针或链接)组成。下图讲解:

相对于传统的数组,链表的一个好处在于,添加或移除元素的时候不需要移动其他元素。然而,链表需要使用指针,因此实现链表的时候需要注意。数组的另一个细节是可以直接访问任何位置元素,而要想访问链表中间的一个元素,需要从起点(表头)开始送达列表直到找到所需要元素。

现实实例就是火车,火车有多节车厢相互衔接,通过接轨来链接火车。车厢就是链表的元素,而接轨就是指针。


链表算法实例

1.链表增删改查。

let list = new LinkedList();list.append(15);list.append(10);list.append(13);//15,10,13list.indexOf(10);//1list.removeAt(1)//15,13list.insert(1,17);//15,17,13list.remove(11);//17,13


ES6链表实现代码:

let LinkedList = (function () {    class Node {//一个节点        constructor(element){            this.element = element;            this.next = null;        }    }    const length = new WeakMap();    const head = new WeakMap();    class LinkedList {        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) {//返回元素在列表中的索引,没有返回-1            let current = this.getHead(),                index = 0;            while (current) {                if (element === current.element) {                    return index;                }                index++;                current = current.next;            }            return -1;        }        isEmpty() {//链表不包含任何元素,返回true,如果长度大于0返回false            return this.size() === 0;        }        size() {//返回链表包含的元素个数            return length.get(this);        }        getHead() {//获取链头项            return head.get(this);        }        toString() {//已string输出链表            let current = this.getHead(),                string = '';            while (current) {                string += current.element + (current.next ? ', ' : '');                current = current.next;            }            return string;        }        print() {//string格式打印到控制台上。            console.log(this.toString());        }    }    return LinkedList;})();



双向链表

双向链表和普通链表的区别在于。在链表中,一个节点只有链向下一个节点的链接,而在双向链表中,链接是双向的:一个链向下一个元素,另一个链向前一个元素。如下图:


这里写图片描述

双向链表提供了两种送代列表的方法:从头到尾,或者反过来。我们也可以访问一个特定节点的下一个或前一个元素。在单向链表中,如果送代列表时错过了要找的元素,就需要回到列表起点,重新开始送代。这是双向链表的一个优点。


事例:

let list = new DoublyLinkedList();list.append(15);list.append(16);//15,16list.print();//15,16list.printInverse();//16, 15list.insert(0,13);//13,15,16list.removeAt(0);//15,16



ES6代码实例:

let DoublyLinkedList = (function () {    class Node {        constructor(element) {            this.element = element;            this.next = null;            this.prev = null; //NEW        }    }    const length = new WeakMap();    const head = new WeakMap();    const tail = new WeakMap(); //NEW    class DoublyLinkedList {        constructor () {            length.set(this, 0);            head.set(this, null);            tail.set(this, null);        }        append(element) {            let node = new Node(element),                current, _tail;            if (this.getHead() === null) { //first node on list                head.set(this, node);                tail.set(this, node); //NEW            } else {                //attach to the tail node //NEW                _tail = this.getTail();                _tail.next = node;                node.prev = _tail;                tail.set(this, node);            }            //update size of list            let l = this.size();            l++;            length.set(this, l);        }        insert(position, element) {            //check for out-of-bounds values            if (position >= 0 && position <= this.size()) {                let node = new Node(element),                    current = this.getHead(),                    previous,                    index = 0;                if (position === 0) { //add on first position                    if (!this.getHead()) {       //NEW                        head.set(this, node);                        tail.set(this, node);                    } else {                        node.next = current;                        current.prev = node; //NEW {1}                        head.set(this, node);                    }                } else if (position === this.size()) { //last item //NEW                    current = tail;     // {2}                    current.next = node;                    node.prev = current;                    tail.set(this, node);                } else {                    while (index++ < position) { //{3}                        previous = current;                        current = current.next;                    }                    node.next = current;                    previous.next = node;                    current.prev = node; //NEW                    node.prev = previous; //NEW                }                //update size of list                let l = this.size();                l++;                length.set(this, l);                return true;            } else {                return false;            }        }        removeAt(position) {            //check for out-of-bounds values            if (position > -1 && position < this.size()) {                let _head = this.getHead(),                    _tail = this.getTail(),                    current = _head,                    previous,                    index = 0;                //removing first item                if (position === 0) {                    _head = current.next; // {1}                    //if there is only one item, then we update tail as well //NEW                    if (this.size() === 1) { // {2}                        _tail = null;                    } else {                        _head.prev = null; // {3}                    }                } else if (position === this.size() - 1) { //last item //NEW                    current = _tail; // {4}                    _tail = current.prev;                    _tail.next = null;                } else {                    while (index++ < position) { // {5}                        previous = current;                        current = current.next;                    }                    //link previous with current's next - skip it to remove                    previous.next = current.next; // {6}                    current.next.prev = previous; //NEW                }                head.set(this,_head);                tail.set(this,_tail);                //update size of list                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 = -1;            //check first item            if (element == current.element) {                return 0;            }            index++;            //check in the middle of the list            while (current.next) {                if (element == current.element) {                    return index;                }                current = current.next;                index++;            }            //check last item            if (element == current.element) {                return index;            }            return -1;        }        isEmpty() {            return this.size() === 0;        }        size() {            return length.get(this);        }        toString() {            let current = this.getHead(),                s = current ? current.element : '';            while (current && current.next) {                current = current.next;                s += ', ' + current.element;            }            return s;        }        inverseToString() {            let current = this.getTail(),                s = current ? current.element : '';            while (current && current.prev) {                current = current.prev;                s += ', ' + current.element;            }            return s;        }        print() {            console.log(this.toString());        }        printInverse() {            console.log(this.inverseToString());        }        getHead() {            return head.get(this);        }        getTail() {            return tail.get(this);        }    }    return DoublyLinkedList;})();



循环链表

循环链表。就是最后一个元素指向不是null,而是指向第一个元素(head)。如下图。




实例用法:

let circularLinkedList = new CircularLinkedList();circularLinkedList.append(15);circularLinkedList.append(16);//15,16circularLinkedList.insert(0,14);//14,15,16circularLinkedList.removeAt(0);//15,16circularLinkedList.indexOf(16)//1



ES6循环链表实例:

let CircularLinkedList = (function () {    class Node {        constructor(element) {            this.element = element;            this.next = null;        }    }    const length = new WeakMap();    const head = new WeakMap();    class CircularLinkedList {        constructor () {            length.set(this, 0);            head.set(this, null);        }        append(element) {            let node = new Node(element),                current;            if (this.getHead() === null) { //first node on list                head.set(this, node);            } else {                current = this.getHead();                //loop the list until find last item                while (current.next !== this.getHead()) { //last element will be head instead of NULL                    current = current.next;                }                //get last item and assign next to added item to make the link                current.next = node;            }            //set node.next to head - to have circular list            node.next = this.getHead();            //update size of list            let l = this.size();            l++;            length.set(this, l);        }        insert(position, element) {            //check for out-of-bounds values            if (position >= 0 && position <= this.size()) {                let node = new Node(element),                    current = this.getHead(),                    previous,                    index = 0;              if (position === 0) { //add on first position                    node.next = current;                    //update last element                    while (current.next !== this.getHead()) { //last element will be head instead of NULL                        current = current.next;                    }                    head.set(this, node);                    current.next = this.getHead();                } else {                    while (index++ < position) {                        previous = current;                        current = current.next;                    }                    node.next = current;                    previous.next = node;                }                //update size of list                let l = this.size();                l++;                length.set(this, l);                return true;            } else {                return false;            }        }        removeAt(position) {            //check for out-of-bounds values            if (position > -1 && position < this.size()) {                let current = this.getHead(),                    previous,                    index = 0;                //removing first item                if (position === 0) {                    while (current.next !== this.getHead()) { //needs to update last element first                        current = current.next;                    }                    head.set(this, this.getHead().next);                    current.next = this.getHead();                } else { //no need to update last element for circular list                    while (index++ < position) {                        previous = current;                        current = current.next;                    }                    //link previous with current's next - skip it to remove                    previous.next = current.next;                }                let l = this.size();                l--;                length.set(this, l);                return current.element;            } else {                return null;            }        }        remove(element) {            let index = indexOf(element);            return removeAt(index);        }        indexOf(element) {            let current = this.getHead(),                index = -1;            //check first item            if (element == current.element) {                return 0;            }            index++;            //check in the middle of the list            while (current.next !== this.getHead()) {                if (element == current.element) {                    return index;                }                current = current.next;                index++;            }            //check last item            if (element == current.element) {                return index;            }            return -1;        }        isEmpty() {            return this.size() === 0;        }        size() {            return length.get(this);        }        getHead() {            return head.get(this);        }        toString() {            let current = this.getHead(),                s = current.element;            while (current.next !== this.getHead()) {                current = current.next;                s += ', ' + current.element;            }            return s.toString();        }        print() {            console.log(this.toString());        }    }    return CircularLinkedList;})();
原创粉丝点击