JavaScript实现链表

时隔一个多月,终于又开始写关于js的文章啦,本次我写的是如何使用JavaScript实现链表。
在这我就不再介绍链表的定义了,直接开始内容部分。
老规矩,先看看链表的方法。

定义链表的方法

在尾部添加新的项

方法:append()
语法:LinkedList.append(element1,element2…elementX)
参数:必需。element不能为空。
描述:添加一个或几个新项在链表尾部,返回添加的项的内容

指定位置插入新的项

方法:insert()
语法:LinkedList.insert(index,element)
参数:必需。index为整数,element内容不能为空。
描述:向链表的特定位置插入一个新的项,返回添加的项的内容

返回元素在链表中的索引

方法:indexOf()
语法:LinkedList.indexOf(element)
参数:必需。element不能为空。
描述:返回元素在链表中首次出现的索引。如果不存在索引的元素,则返回-1

移除指定位置的项

方法:removeAt()
语法:LinkedList.removeAt(index)
参数:必需。index为整数。
描述:删除指定项并返回项的内容。

移除包含指定元素的项

方法:remove()
语法:LinkedList.remove(element)
参数:必需。element不能为空。
描述:删除第一个包含指定元素的项并返回项的内容。如果不存在包含指定元素的项,则返回错误提示。

链表是否为空

方法:isEmpty()
语法:LinkedList.isEmpty()
参数:无
描述:如果链表中没有任何项则返回true,否则返回false

返回链表的长度

方法:size()
语法:LinkedList.size()
参数:无
描述:返回链表中项的个数

清空链表

方法:clear()
语法:LinkedList.clear()
参数:无
描述:移除链表中的所有项

输出链表

方法:show()
语法:LinkedList.show()
参数:无
描述:返回链表中的所有项

单链表代码实现

 function LinkedList() {
            var Node = function (element) {
                    this.element = element;
                    this.next = null;
                }, //节点
                length = 0, //长度
                head = null; //头部
//动态原型模式创建原型方法
            if (typeof LinkedList.prototype.append != 'function') {
                /*
                在尾部添加新的项。
                */
                LinkedList.prototype.append = function () {
                    var arr = arguments,
                        node,
                        current;
                    //添加内容不能为空
                    if (!arr) {
                        return false;
                    } else {
                        node = new Node(arr[0]);
                        //如果是首节点,直接建立连接
                        if (head == null) {
                            head = node;
                        } else {
                            //否则从首节点开始
                            current = head;
                            //循环链表,直到找到最后一个节点
                            while (current.next) {
                                current = current.next;
                            }
                            //尾节点指向新的节点
                            current.next = node;
                        }
                        length++; //更新长度
                        //循环添加节点
                        for (var i = 1; i < arr.length; i++) {
                            LinkedList.prototype.append(arr[i]);
                        }
                    }
                }
                /*
                在指定位置插入新的项
                */
                LinkedList.prototype.insert = function (index, element) {
                    if (!/^[0-9]*[1-9][0-9]*$/.test(index)) {
                        return new TypeError("插入的位置必须为正整数")
                    }
                    if (!element) {
                        return new TypeError("插入内容不能为空")
                    }
                    //检查index越界情况
                    if (index >= 0 && index <= length) {
                        var node = new Node(element),
                            current = head, //当前节点
                            previous, //前一个节点
                            position = 0; //当前位置
                        if (index === 0) {
                            //在第一个位置插入
                            node.next = current; //新的节点指向原首节点
                            head = node; //切断head与原首节点的联系,新节点成为首节点
                        } else {
                            //找到要插入位置
                            while (position++ < index) {
                                previous = current; //前一个节点改为当前节点
                                current = current.next; //当前节点更改为下个节点                               
                            }
                            //完成插入
                            node.next = current;
                            previous.next = node;
                        }
                        //更新长度
                        length++;
                        //插入成功返回element
                        return element;
                    } else {
                        return new Error("index越界,不能正常插入!index必须为正整数,且不能超出链表长度");
                    }
                }
                /*
                返回元素在链表中的索引
                */
                LinkedList.prototype.indexOf = function (element) {
                    var current = head, //当前节点
                        index = 0; //记录当前位置
                    //循环比较项的元素
                    while (current.element !== element && current.next !== null) {
                        current = current.next;
                        index++;
                    }
                    //如果找到元素,返回索引,否则返回-1
                    if (current.element === element) {
                        return index;
                    } else {
                        return -1;
                    }
                }
                /*
                移除指定位置的项
                */
                LinkedList.prototype.removeAt = function (index) {
                    if (!/^[0-9]*[0-9][0-9]*$/.test(index) || index > length - 1) {
                        return new Error("删除的位置必须为零或正整数且不能超过链表长度")
                    }
                    if(head==null){
                        return new Error("链表长度为空!无法删除");
                    }
                    var current = head, //当前的节点
                        position = 0, //当前的位置
                        previous, //前一个节点
                        content; //节点内容
                    //如果是首节点,则把下一个节点当成首节点
                    if (index === 0) {
                        content=current.element;
                        current = current.next;
                        head = current;
                    } else {
                        //跳转到需要删除的位置
                        while (position++ < index) {
                            previous = current; //当前节点变成上个节点
                            current = current.next; //下个节点变成当前节点
                        }
                        previous.next = current.next; //跳过当前节点 
                        content = current.element; //获取节点内容
                        current = null; //删除当前节点               
                    }
                    length--; //更新长度
                    return content; //返回删除的节点内容
                }

                /*
                移除包含指定元素的项
                */
                LinkedList.prototype.remove = function (element) {
                    var index = LinkedList.prototype.indexOf(element);
                    if (index === -1) {
                        return new Error("链表中不包含指定元素的项");
                    }
                    return LinkedList.prototype.removeAt(index)

                }
                /*
               链表是否为空
                */
                LinkedList.prototype.isEmpty = function () {
                    return length === 0;
                }
                /*
               链表的长度
                */
                LinkedList.prototype.size = function () {
                    return length;
                }
                /*
               清空链表
                */
                LinkedList.prototype.clear = function () {                   
                    head=null;//删除首节点与后续节点的联系。后续节点会被JavaScript垃圾回收机制回收
                    length=0;//更新长度
                }
                 /*
               输出链表
                */
                LinkedList.prototype.show = function () {
                    var current = head, //首节点
                        arr = []; //用于存储项的内容的数组
                    while (current) {
                        arr.push(current.element);
                        current = current.next;
                    }
                    return head===null?"链表为空":arr;
                }
            }
        }
测试代码
  var lis = new LinkedList();
        lis.append(1, 2, 3, 4, 5, 6);
        console.log(lis.show());//[1, 2, 3, 4, 5, 6]
        lis.insert(3, 3.5);
        console.log(lis.show());//[1, 2, 3, 3.5, 4, 5, 6]
        console.log(lis.indexOf(3.5));//3
        console.log(lis.remove(3.5));//3.5
        console.log(lis.show());//[1, 2, 3, 4, 5, 6]
        console.log(lis.removeAt(5));//6
        console.log(lis.isEmpty());//false
        console.log(lis.size());//5
        console.log(lis.clear());//undefined
        console.log(lis.show());//链表为空

测试代码


双链表代码实现

双链表在原来的单链表基础上增加了一个前节点(previous)的指向,同时多出了一个尾节点(tail)的概念。由于增加了尾节点和前节点指向,append方法可以直接在尾部增加新的项、insert方法可以选择向前搜索或向后搜索来查找要插入的位置,显著的提升运行的效率。

    function DoublyLinkedList() {
            var Node = function (element) {
                    this.element = element;
                    this.previous = null;
                    this.next = null;
                }, //节点
                length = 0, //长度
                head = null, //头部
                tail = null; //尾部
            //动态原型模式创建原型方法
            if (typeof DoublyLinkedList.prototype.append != 'function') {
                /*
                在尾部添加新的项
                */
                DoublyLinkedList.prototype.append = function () {
                    var arr = arguments,
                        node, //新的节点
                        current; //当前节点
                    //添加内容不能为空
                    if (!arr) {
                        return false;
                    } else {
                        node = new Node(arr[0]);
                        //如果是首节点,直接建立连接
                        if (head == null) {
                            //首节点和尾节点都是一个节点
                            head = node;
                            tail = node;
                        } else {
                            //否则从尾节点开始
                            current = tail;
                            current.next = node; //尾节点的下个节点指向新的节点
                            node.previous = current; //新节点的前节点指向原来的尾节点
                            tail = node; //尾节点更改新的节点
                        }
                        length++; //更新长度
                        //循环添加节点
                        for (var i = 1; i < arr.length; i++) {
                            DoublyLinkedList.prototype.append(arr[i]);
                        }
                    }
                }
                /*
                在指定位置插入新的项
                */
                DoublyLinkedList.prototype.insert = function (index, element) {
                    if (!/^[0-9]*[1-9][0-9]*$/.test(index)) {
                        return new TypeError("插入的位置必须为正整数");
                    }
                    if (!element) {
                        return new TypeError("插入内容不能为空")
                    }
                    var current = head, //当前节点
                        previous, //上个节点
                        node = new Node(element); //新的节点

                    //如果链表为空
                    if (!head) {
                        //首节点和尾节点都是一个节点
                        head = node;
                        tail = node;
                    } else {
                        //链表不为空时,插入位置分成三种情况,一是首位插入,二是尾部插入,三是中间插入                   
                        if (index === 0) {
                            node.previous = null; //新节点的前节点为空
                            current.previous = node; //原首节点的前节点设为新节点
                            node.next = current; //新节点的下个节点为原首节点
                            head = node; //新节点成为首节点                                
                        } else if (index === length - 1) {
                            current = tail; //当前节点换成尾节点
                            previous = current.previous; //获尾二节点(倒数第二个节点)
                            previous.next = node; //原尾二节点的下个节点指向新节点
                            node.next = current; //新节点的下个节点指向尾节点
                            node.previous = previous; //新节点的前节点指向原尾二节点
                            current.previous = node; //尾节点的前节点指向新的节点
                        } else if (index > 0 && index < length - 1) {
                            var direction = (index - length / 2) <= 0 ? "front" : "later", //判断方向
                                position, //当前位置
                                previous, //前一个节点
                                current; //当前节点
                            //从前到后查询节点
                            if (direction === "front") {
                                position = 0,
                                    current = head;
                                while (position++ < index) {
                                    current = current.next;
                                }
                            } else {
                                //从后到前查询节点
                                position = length - 1,
                                    current = tail;
                                while (position > index) {
                                    current = current.previous;
                                    position--;
                                }
                            }
                            //完成节点插入
                            previous = current.previous;
                            previous.next = node;
                            node.previous = previous;
                            node.next = current;
                            current.previous = node;
                        }

                    }
                    length++; //更新长度
                    return node.element;
                }

                /*
                返回元素在链表中的索引
                */
                DoublyLinkedList.prototype.indexOf = function (element) {
                    var current = head, //当前节点
                        index = 0; //记录当前位置
                    if (!element) {
                        return new TypeError("插入内容不能为空")
                    }
                    //循环比较项的元素
                    while (current.element !== element && current.next !== null) {
                        current = current.next;
                        index++;
                    }
                    //如果找到元素,返回索引,否则返回-1
                    if (current.element === element) {
                        return index;
                    } else {
                        return -1;
                    }
                }
                /*
                移除指定位置的项
                */
                DoublyLinkedList.prototype.removeAt = function (index) {
                    if (!/^[0-9]*[0-9][0-9]*$/.test(index) || index > length - 1) {
                        return new Error("删除的位置必须为零或正整数且不能超过链表长度")
                    }
                    if (head == null) {
                        return new Error("链表长度为空!无法删除");
                    }
                    var current, //当前的节点
                        position = 0, //当前的位置
                        previous, //前一个节点
                        content, //节点内容
                        direction = (index - length / 2) <= 0 ? "front" : "later"; //判断方向

                    //位置的移除分成三种情况,一是首节点,二是尾节点,三是中间
                    if (index === 0) {
                        content = head.element; //获取首节点内容
                        current = head.next; //当前节点为首节点的下个节点 
                        current.previous = null; //当前节点的上个几点为空                  
                        head = current; //当前节点成为新的首节点
                    } else if (index === length - 1) {
                        content = tail.element; //获取尾节点内容
                        current = tail; //当前节点为尾节点
                        previous = current.previous; //获取尾节点的前一个节点
                        current = null; //清空尾节点内容                       
                        tail = previous; //设置新的尾节点
                        tail.previous = null; //尾节点的下个节点为空
                    } else if (index > 0 && index < length - 1) {
                        //从前到后查询节点
                        if (direction === "front") {
                            position = 0,
                                current = head;
                            while (position++ < index) {
                                current = current.next;
                            }
                        } else {
                            //从后到前查询节点
                            position = length - 1,
                                current = tail;
                            while (position > index) {
                                current = current.previous;
                                position--;
                            }
                        }
                        //完成删除
                        previous = current.previous;
                        previous.next = current.next;
                        current.next.previous = previous;
                        current = null;
                    }

                    length--; //更新长度
                    return content; //返回删除的节点内容
                }
                /*
                移除包含指定元素的项
                */
                DoublyLinkedList.prototype.remove = function (element) {
                    //移除第一个包含指定元素的项,说明智能从前往后查询
                    var current = head;//当前节点                       
                    if (!element) {
                        return new TypeError("插入内容不能为空")
                    }
                    if (current != null) {
                        //循环比较项的元素
                        while (current.element !== element && current.next !== null) {
                            current = current.next;
                        }
                        //找到指定元素之后要分成三种情况,一是头部删除,二是尾部删除,三是中间删除
                        if(current.previous==null){
                            current.next.previous=null;
                            content=current.element;
                            current=null;
                        }else if(current.next==null){
                            current.previous.next=null;
                            current=null;
                        }else{
                            current.previous.next=current.next;
                            current.next.previous=current.previous;
                            content=current.element;
                            current=null;
                        }
                        return content;
                        length--;
                    } else {
                        return new Error("链表为空,无法删除")
                    }

                }
                /*
                       链表是否为空
                        */
                DoublyLinkedList.prototype.isEmpty = function () {
                    return length === 0;
                }
                /*
                       链表的长度
                        */
                DoublyLinkedList.prototype.size = function () {
                    return length;
                }
                /*
                       清空链表
                       手动释放和自动释放内存并无太大差异。并且在测试中手动清空内存会显著增加运行时间。
                        */
                DoublyLinkedList.prototype.clear = function () {
                    //手动释放所有内存 
                    // var current=tail,//最后一个节点
                    //     previous;//上个节点                 
                    // while(length-->0){
                    //     previous=current.previous;
                    //     current=null;
                    //     current=previous;
                    // }
                    // head=null;
                    // tail=null;
                    // length = 0; //更新长度
                    //自动释放所有内存
                    head = null;
                    tail = null;
                    length = 0;
                }
                /*
                输出链表
                        */
                DoublyLinkedList.prototype.show = function () {
                    var current = head, //首节点
                        arr = []; //用于存储项的内容的数组
                    while (current) {
                        arr.push(current.element);
                        current = current.next;
                    }
                    return head === null ? "链表为空" : arr;
                }
            }
        }
测试代码
var lis = new DoublyLinkedList();
lis.append(1, 2, 3, 4, 5, 6);
        console.log(lis.show());//[1, 2, 3, 4, 5, 6]
        lis.insert(3, 3.5);
        console.log(lis.show());//[1, 2, 3, 3.5, 4, 5, 6]
        console.log(lis.indexOf(3.5));//3
        console.log(lis.remove(3.5));//3.5
        console.log(lis.show());//[1, 2, 3, 4, 5, 6]
        console.log(lis.removeAt(5));//6
        console.log(lis.isEmpty());//false
        console.log(lis.size());//5
        console.log(lis.clear());//undefined
        console.log(lis.show());//链表为空

测试2

参考资料:
《学习JavaScript数据结构与算法》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值