链表--双向链表的基本方法

双向链表是基于单向链表的,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。

1、创建Node类

function Node(element) {
    this.element=element;
    this.next = null;
    this.previous=null;
}

2、查找最后的节点

其实,这里的问题主要就是如何判断链表的最后节点,如果当前节点的下一个节点为空,是不是就说明了我后面已经没有节点了,那我自然就是最后一个。所以,这里就通过一个while循环不断往后推,只要你不是,那我就找你的下一个,直到你的后面为空,我就找到了。

this.lastNode = function () {
            var lastNode = this.head;
            while (lastNode.next != null) {
                lastNode = lastNode.next;
            }
            return lastNode;
        }

3、查找节点

首先,定义node节点为头结点,如果node不为空并且它的节点元素不等于我要找的元素,那么就让node节点等于它的下一个节点元素,继续判断是否符合循环条件。简单来说,就是从头挨个挨个找,找到我就跳出循环,返回node,找不到最后还是返回node,不过此时的node已经为空了。

this.find = function (element) {
            var node = this.head;
            while (node != null && node.element != element) {
                node = node.next;
            }
            return node;
        }

4、在after后插入节点

this.insertAfter = function (element, after) {
            //找到当前节点
            var node = this.find(after);
            //创建新的节点
            var newNode = new Node(element);
            //新节点和当前节点的后一个节点连接在一起
            if (node.next != null)
                 node.next.previous=newNode;
            newNode.next = node.next;
            //连接当前节点和after节点
            node.next = newNode;
            newNode.previous = node;
        }

5、在before前插入节点

this.insertBefore = function (element, before) {
            //找到当前节点
            var node = this.find(before);
            if(node.previous==null){
                return;
            }
            //创建新的节点
            var newNode = new Node(element);
            //新节点和当前节点的前一个节点连接在一起;
            node.previous.next = newNode;
            newNode.previous = node.previous;
            //连接当前节点和before节点
            node.previous = newNode;
            newNode.next = node;
        }

6、删除节点

this.remove = function (element) {
            //获得当前的节点
            var node = this.find(element);
            //获得当前节点的前一个节点
            var preNode = node.previous;
            //获得当前节点的后一个节点
            var nextNode = node.next;
            //连接节点
            preNode.next = nextNode;
            if (nextNode != null) {
                preNode = nextNode.previous;
            }
        }

7、遍历链表

this.forEach = function (call) {
            var node = this.head;
            while (node != null) {
                call(node);
                node = node.next;
            }
        }

8、反向遍历链表

this.forEach = function (call) {
            var node = this.head;
            while (node != null) {
                call(node);
                node = node.next;
            }
        }

9、当前节点向前移动n个节点

这和之前说过的单向链表的advance方法很相似,我们不妨想一想,既然是双向,肯定是前面的指向后面的,后面的指向前面的,接下来,我们将通过一个实例来解释:

双向链表中:head    1      2       3        4        5

现在我要将3往前移动5个节点,currElement等于3,n等于5,其实,现在我们已经知道了最后的结果是head   3    1    2    4    5

(1)调用查找节点的方法,获得当前的节点3;

(2)获得当前节点的前一个节点,所以,buffer等于3的前一个节点2,preNode等于buffer也等于2;

(3)如果preNode的元素不等于头结点,这是因为如果等于头结点说明已经不能往前走了,再走就走出去了;n大于0表明我还没移动5个节点。当这两个条件同时满足后,就让preNode等于它的前一个节点,同时n要减一,因为我已经往前移动一位了。

    结合我们上面说的,现在我的preNode应该是等于1,n=4,那我什么时候跳出循环呢?在下一次循环的时候,preNode应该等于头结点,n=3,这个时候我的preNode元素已经不再满足循环条件,跳出循环;

(4)如果当前节点的下一个节点不为空,让buffer的下一个节点指向当前节点currentNode的下一个节点,即让2的下一个节点指向3的下一个节点,其实就是将当前节点的前一个节点和它的后一个节点连接在一起,如果是单向链表,这一步就算是结束了,但是对于双向链表来说,还要让当前节点currentNode的下一个节点的前一个节点等于buffer,实际上就是3的下一个节点4的前一个节点等于2,简单来说,就是我的后面是你,你的前面是我。

(5)当前节点currentNode的下一个节点等于preNode的下一个节点,当前节点currentNode的下一个节点的前一个节点等于当前节点currentNode。

    当前节点是5,preNode我们循环出来是头结点,5的下一个节点指向的是头结点的下一个节点,说明头结点后面是5;头结点的下一个节点的前一个节点等于头结点,其实就是头结点本身。

(6)preNode的下一个节点等于当前节点,当前节点的前一个节点等于preNode。

        this.advance=function (currElement,n){
            //获得当前节点
            var currentNode = this.find(currElement);
            //获得当前节点的前一个节点
            var buffer = currentNode.previous;
            var preNode = buffer;
            while(preNode.element!='head'&&n>0){
                preNode = preNode.previous;
                n--;
            }
            if(currentNode.next!=null){
                buffer.next=currentNode.next;
                currentNode.next.previous = buffer;
                currentNode.next=preNode.next;
                preNode.next.previous = currentNode;
                preNode.next=currentNode;
                currentNode.previous=preNode;
            }

        }

10、当前节点向后移动n个节点

        this.back=function (currElement,n){
            //获得当前节点
            var currentNode = this.find(currElement);
            //假设当前节点为最后节点
            var lastNode = currentNode;
            //在n>0的条件下,下一个节点为空的时候停下来
            while(lastNode.next!=null&&n>0){
                lastNode = lastNode.next;
                n--;
            }
            //currentNode节点和lastNode相等,说明currentNode本身就是最后的节点
            if(currentNode==lastNode){
                return;
            }
            //当前节点的前一个节点和当前节点的后一个节点连接在一起
            currentNode.previous.next = currentNode.next;
            currentNode.next.previous=currentNode.previous;
            //把当前节点连在lastNode节点后面
            currentNode.next=lastNode.next;
            lastNode.next=currentNode;
            currentNode.previous=lastNode;
            currentNode.next.previous=currentNode;
        }
    }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值