数据结构:用JS实现链表

来源:互联网 发布:2017好玩的手游 知乎 编辑:程序博客网 时间:2024/06/15 06:38

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

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

创建链表

我们先搭建一个类的骨架

function LinkedList () {    //辅助类 表示要加入链表的项    var Node = function (element) {        this.element = element;        this.next = null; //指向链表中下一个节点项的指针    };    var length = 0;    var head = null;    this.append = function (element) {}; //向链表尾部添加一个新的项    this.insert = function (position, element) {}; //向链表特定位置插入一个新的项    this.removeAt = function (position) {}; //从链表特定位置移除一项    this.remove = function (element) {}; //从链表中移除一项    this.indexOf = function (element) {}; //返回元素在链表中的索引,如果没有则返回-1    this.isEmpty = function () {}; //判断链表是否为空    this.size = function () {}; //返回链表包含元素个数    this.getHead = function () {}; //返回链表第一个元素    this.toString = function () {}; //只输出元素的值    this.print = function () {}; //打印元素的值}

下面,我们来一一实现他们

this.append = function (element) {    var node = new Node(element),        current;    if (head === null) { //链表为空,添加到首部        head = node;    }else {        current = head;        //循环链表,直到找到最后一项        while (current.next) {            current = current.next;        }        //找到最后一项,将其next赋为node,建立连接        current.next = node;    }    length++;};

这里写图片描述
在普通链表中:链表最后一个节点的下一个元素始终是null。

this.removeAt = function (position) {    //检查是否越界    if (position > -1 && position < length) {        var current = head,            previous,            index = 0;        if (position === 0) { //移除第一项            head = current.next;        }else {            while (index++ < position) {                previous = current;                current = current.next;            }            //将previous与current的下一项链接起来,跳过current,从而移除它            previous.next = current.next;        }        length--;        return current.element;    }else {        return null;    }};

这里写图片描述

this.insert = function (position, element) {    //检查是否越界    if (position >= 0 && position <= length) {        var node = new Node(element),            current = head,            previous,            index = 0;        if (position === 0) { //在第一个位置添加            node.next = current;            head = node;        }else {            while (index++ < position) {                previous = current;                current = current.next;            }            //通过改变指针,将node链接在previous和current之间            node.next = current;            previous.next = node;        }        length++;        return true;    }else {        return false;    }};

这里写图片描述

//只输出链表中元素this.toString = function () {    var current = head,        string = "";    while (current) {        string += "," + current.element;        current = current.next;    }    return string.slice(1);}; 
this.indexOf = function (element) {    var current = head,        index = 0;    while (current) {        if (current.element === element) {            return index;        }        index++;        current = current.next;    }    return -1;};
this.remove = function (element) {    var index = this.indexOf(element);    return this.removeAt(index);};
this.isEmpty = function () {    return length === 0;}; 
this.size = function () {    return length;};
//head是一个私有变量,当需要在类的实现外部循环访问链表时,就可以使用getHead方法获取类的第一个元素this.getHead = function () {    return head;};
this.print = function () {    console.log( this.toString() );};

接下来,我们在上面的基础上做点扩展

双向链表

一个链向下一个元素,另一个链向前一个元素。
这里写图片描述

function DoublyLinkedList () {    var Node = function (element) {        this.element = element;        this.next = null;        this.prev = null; //新    };    var length = 0;    var head = null;    var tail = null; //新 对最后一项的引用    //方法}
this.append = function (element) {    var node = new Node(element),        current;    if (head === null) { //链表为空,添加到首部        head = node;        tail = node; //新    }else {        current = head;        //循环链表,直到找到最后一项        while (current.next) {            current = current.next;        }        //找到最后一项,将其next赋为node,建立连接        current.next = node;        tail = node; //新    }    length++;};
this.insert = function (position, element) {    //检查是否越界    if (position >= 0 && position <= length) {        var node = new Node(element),            current = head,            previous,            index = 0;        if (position === 0) { //在第一个位置添加            if (!head) { //新                head = node;                tail = node;            }else {                node.next = current;                current.prev = node; //新                head = node;                        }        }else if (position === length) { //新 最后一项            //改变指针,再把node赋值给tail            current = tail;            current.next = node;            node.prev = current;            tail = node;        }else {            while (index++ < position) {                previous = current;                current = current.next;            }            //通过改变指针,将node链接在previous和current之间            node.next = current;            previous.next = node;            current.prev = node; //新            node.prev = previous; //新        }        length++;        return true;    }else {        return false;    }};
this.removeAt = function (position) {    //检查是否越界    if (position > -1 && position < length) {        var current = head,            previous,            index = 0;        if (position === 0) { //移除第一项            head = current.next;            //新 如果只有一项,更新tail            if (length === 1) {                tail = null;            }else {                head.prev = null;            }        }else if(position === length - 1) { //新 最后一项            current = tail;            tail = current.prev;            tail.next = null;        }else {            while (index++ < position) {                previous = current;                current = current.next;            }            //将previous与current的下一项链接起来,跳过current,从而移除它            previous.next = current.next;            current.next.prev = previous; //新        }        length--;        return current.element;    }else {        return null;    }};

其它的方法和单向链表一样

扩展就到这里,有兴趣的朋友可以试试在此基础上再进行扩展
比如,循环链表:将链表最后一项的next指向head
在升级就是双向循环链表,感觉要被玩坏了~

原创粉丝点击