【JS数据结构与算法】双向链表(DoublylinkedList)封装及其方法

 

目录

双向链表结构

双向链表的封装

一、追溯方法(append(data))

二、toString()的两种方式。

1、forwardString()(返回正向遍历的节点字符串形式)

2、backwardString() (返回反向遍历的节点字符串形式)

3、toString() (由于列表项使用了Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值。)

4、代码测试

三、 inset(position, element) 

四、get(position)

1.方法一(对于多元素的获取效率非常低)

2、方法二(利用双向列表的双向性)

3、代码检验

五、indexOf(data)

六、upDate

方法一:(与get方法情况类似,可改进)

方法二:(改进后)

七、removeAt(position)

八、remove(element)

九、判断链表是否为空

十、返回链表的长度

十一、完整代码


双向链表结构

双向链表的封装

    //封装双向链表
    function DoublyLinkedList(){
      // 封装一个内部类,可创建一个新节点
      function Node(data){
        this.data = data;
        this.prev = null;
        this.next = null;
      }

      // 属性
      this.head = null;
      this.tail = null;
      this.length = 0;
    }

一、追溯方法(append(data))

向双向链表尾部添加一个新的节点(该方法与单向链表的append方法类似)

1、创建新节点

// 1、创建新节点
var newNode = new Node(data);

2、判断双向链表的长度是否为0;

     1.如果是,如图操作

this.head = newNode;
// 两种情况都需要的
this.tail = newNode;

      2.如果不是为0,则是下面这种操作。

newNode.prev = this.tail;
this.tail.next = newNode;
// 两种情况都需要的
this.tail = newNode;

3、append方法代码:

DoublyLinkedList.prototype.append = function(data){
        // 1、创建新节点
        var newNode = new Node(data);

        // 2、判断链表是否为空
        if (this.length == 0) {//2.1 链表为空
          this.head = newNode;
        }else{//2.2 链表不为空
          newNode.prev = this.tail;
          this.tail.next = newNode;
        }

        // 两种情况都需要的
        this.tail = newNode;

        // 3、长度要加1
        this.length += 1;
}

二、toString()的两种方式。

1、forwardString()(返回正向遍历的节点字符串形式)

DoublyLinkedList.prototype.forwardString = function(){
        var current = this.head;
        var resultString = '';
        while(current){
          resultString += current.data + ' ';
          current = current.next;
        }

        return resultString;
}

2、backwardString() (返回反向遍历的节点字符串形式)

 DoublyLinkedList.prototype.backwardString = function(){
        var previous = this.tail;
        var resultString = '';
        while(previous){
          resultString += previous.data + ' ';
          previous = previous.prev;
        }

        return resultString;
}

3、toString() (由于列表项使用了Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值。)

这里是正向遍历,所以直接调用forwardString()即可。

DoublyLinkedList.prototype.toString = function(){
        return this.forwardString();
}

4、代码测试

    // 测试代码
    // 创建DoublyLinkedList
    var DLinkedList = new DoublyLinkedList();

    DLinkedList.append('a');
    DLinkedList.append('b');
    DLinkedList.append('c');
    DLinkedList.append('d');


    alert(DLinkedList.forwardString()); //a b c d 
    alert(DLinkedList.backwardString());  //d c b a 
    alert(DLinkedList.toString()); //a b c d 

三、 inset(position, element) 

向链表的特定位置插入一个新的节点。思路与单向链表的inset方法类似,具体操作如图所示。

1、当链表为空时。

// head和tail都指向newNode
this.head = newNode;
this.tail = newNode;

2、当链表不为空,插入的位置为0时。

newNode.next = this.head;
this.head.prev = newNode;
this.head = newNode;

3、当链表不为空,插入的位置是在表尾,与append的第二种方法相同(2.如果不是为0,则是下面这种操作。

newNode.prev = this.tail;
this.tail.next = newNode;
// 两种情况都需要的
this.tail = newNode;

4、当链表不为空,插入的位置是在链表之中。

var index = 0;
var current = this.head;
while(index++ < position){
   current = current.next;
}
newNode.prev = current.prev; // 1
current.prev.next = newNode; // 2
newNode.next = current; // 3
current.prev = newNode; // 4

注意:这里需要注意的是,current所指向之前的节点(current.prev)和节点所带的next指向(current.prev.next)是新节点需要定位的节点,所以在改变current.prev的指向之前需要先执行①和②的操作。

5、链表长度加1

this.length += 1;

6、代码实现

      DoublyLinkedList.prototype.inset = function(position, data){
        
        // 1、 先判断position是否合法
        if (position < 0 || position > this.length) return false;

        // 2、创建新节点
        var newNode = new Node(data);

        // 3、 判断链表长度是否为0
        if (this.length == 0) { // 3.1 链表长度为0
          // head和tail都指向newNode
          this.head = newNode;
          this.tail = newNode;
        }else{ // 3.2链表长度为0

          // 4、 判断插入位置是否为0
          if (position == 0) { // 4.1 插入位置为0
            newNode.next = this.head;
            this.head.prev = newNode;
            this.head = newNode;
          }else if(position == this.length){// 4.2插入位置为链表末尾
            newNode.prev = this.tail;
            this.tail.next = newNode;
          }else{  // 4.3 插入位置在链表之中
            var index = 0;
            var current = this.head;
            while(index++ < position){
              current = current.next;
            }
            newNode.prev = current.prev;
            current.prev.next = newNode;
            newNode.next = current;
            current.prev = newNode;
          }
        }
        // 5、长度要加1
        this.length += 1;
      }

7、代码检验

    // 测试代码
    // 创建DoublyLinkedList
    var DLinkedList = new DoublyLinkedList();

    DLinkedList.append('a');
    DLinkedList.append('b');
    DLinkedList.append('c');
    DLinkedList.append('d');
    alert(DLinkedList.toString()); //a b c d 

    DLinkedList.inset(0,'e');
    alert(DLinkedList.toString()); //e a b c d 

    DLinkedList.inset(2,'f');
    alert(DLinkedList.toString()); //e a f b c d 

    DLinkedList.inset(6,'g');
    alert(DLinkedList.toString()); //e a f b c d g 

四、get(position)

获取对应位置的元素

1.方法一(对于多元素的获取效率非常低

      DoublyLinkedList.prototype.get =function(position){
        // 1、 先判断position是否合法
        if (position < 0 || position > this.length - 1) return null;

        // 2、根据position位置信息找到对应节点
        var index = 0;
        var current = this.head;
        while(index++ < position){
          current = current.next;
        }
        return current.data;
      }

2、方法二(利用双向列表的双向性)

      DoublyLinkedList.prototype.getFast =function(position){
        // 1、 先判断position是否合法
        if (position < 0 || position > this.length - 1) return null;

        // 2、根据position位置信息找到对应节点
        var previous = this.head;
        var current = this.tail;
        if (position < this.length / 2) {  //从前往后遍历
          var index = 0;
          while(index++ < position){
            previous = previous.next;
          }
          return previous.data;
        }else{    // 从后往前遍历
          var index = this.length - 1;
          while(index-- > position){
            current = current.prev;
          }
          return current.data;
        }
      }

 

3、代码检验

    // 测试代码
    // 创建DoublyLinkedList
    var DLinkedList = new DoublyLinkedList();

    DLinkedList.append('a');
    DLinkedList.append('b');
    DLinkedList.append('c');
    DLinkedList.append('d');
    DLinkedList.append('e');
    alert(DLinkedList.getFast(-1)); //null
    alert(DLinkedList.getFast(0)); //a
    alert(DLinkedList.getFast(1)); //b
    alert(DLinkedList.getFast(2)); //c
    alert(DLinkedList.getFast(3)); //d
    alert(DLinkedList.getFast(4)); //e
    alert(DLinkedList.getFast(5)); //null

五、indexOf(data)

返回元素在列表中的索引,如果列表中没有该元素则返回-1

      DoublyLinkedList.prototype.indexOf =function(data){
        var index = 0;
        var current = this.head;

        while(current){
          if (current.data == data) return index;
          current = current.next;
          index += 1;
        }

        return -1;
      }

2、测试代码

    // 测试代码
    // 创建DoublyLinkedList
    var DLinkedList = new DoublyLinkedList();

    DLinkedList.append('a');
    DLinkedList.append('b');
    DLinkedList.append('c');
    alert(DLinkedList.indexOf('a')); //0
    alert(DLinkedList.indexOf('b')); //1
    alert(DLinkedList.indexOf('c')); //2
    alert(DLinkedList.indexOf('d')); //-1
    alert(DLinkedList.indexOf('e')); //-1

六、upDate

修改某位置的元素

方法一:(与get方法情况类似,可改进)

      DoublyLinkedList.prototype.upDate = function(position, data){
 
        // 越界判断
        if (position < 0 || position >= this.length) return false;
 
        var index = 0;
        var current = this.head;
        while(index++ < position){
          current = current.next;
        }
        current.data = data;
        return true;
      }

方法二:(改进后)

      DoublyLinkedList.prototype.upDate = function(position, data){
 
        // 越界判断
        if (position < 0 || position >= this.length) return false;
 
        // 2、根据position位置信息找到对应节点
        var previous = this.head;
        var current = this.tail;
        if (position < this.length / 2) {  //从前往后遍历
          var index = 0;
          while(index++ < position){
            previous = previous.next;
          }
          previous.data = data;
        }else{ //从后往前遍历
          var index = this.length - 1;
          while(index-- > position){
            current = current.prev;
          }
          current.data = data;
        }
        return true;
      }

七、removeAt(position)

删除相应位置的元素,如果删除成功返回其值

情况一:当链表的长度为1

this.head = null;
this.tail = null;

情况二:链表长度不为1,删除第一个节点。

this.head.next.prev = null
this.head = this.head.next;

情况三:链表长度不为1,删除最后一个节点。

this.tail.prev.next = null;
this.tail = this.tail.prev;

情况二:链表长度不为1,删除的节点不是第一个和最后一个。

var index = 0;
var current = this.head;
while(index++ < position){
    current = current.next;
}
current.prev.next = current.next;
current.next.prev = current.prev;

最后别忘记length-1

完整代码

     DoublyLinkedList.prototype.removeAt = function(position){
        // 判断position是否合法
        if (position < 0 || position >= this.length) return false;

        // 寻找节点
        var current = this.head;
        if (this.length == 1) {
          this.head = null;
          this.tail = null;
        }else{
          if (position == 0) {
            // 让head指向第二个节点
            this.head.next.prev = null
            this.head = this.head.next;
          }else if (position == this.length - 1) {
            current = this.tail;
            this.tail.prev.next = null;
            this.tail = this.tail.prev;
          }else{
            var index = 0;
            while(index++ < position){
              current = current.next;
            }
            current.prev.next = current.next;
            current.next.prev = current.prev;
          }
        }

        // length-1
        this.length -= 1;

        return current.data;
      }

测试代码

    // 测试代码
    // 创建DoublyLinkedList
    var DLinkedList = new DoublyLinkedList();

    DLinkedList.append('a');
    DLinkedList.append('b');
    DLinkedList.append('c');
    DLinkedList.removeAt(3);
    alert(DLinkedList.toString()); //a b c 
    DLinkedList.removeAt(0);
    alert(DLinkedList.toString()); //b c 
    DLinkedList.removeAt(1);
    alert(DLinkedList.toString()); //b
    DLinkedList.removeAt(0);
    alert(DLinkedList.toString()); //

八、remove(element)

删除一项数据

      DoublyLinkedList.prototype.remove = function(data){
        // 根据data获取元素位置
        var index = this.indexOf(data);

        // 根据index将对应节点删除
        return this.removeAt(index);
      }

这里删除的是indexOf遍历时满足的第一个节点,后续不再查找。

九、判断链表是否为空

DoublyLinkedList.prototype.isEmpty = function(){
    return this.length === 0;
}

十、返回链表的长度

DoublyLinkedList.prototype.size = function(){
    return this.length;
}

十一、完整代码

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>双向链表的封装</title>
</head>
<body>
  <script type="text/javascript">

    //封装双向链表
    function DoublyLinkedList(){
      // 封装一个内部类,可创建一个新节点
      function Node(data){
        this.data = data;
        this.prev = null;
        this.next = null;
      }

      // 属性
      this.head = null;
      this.tail = null;
      this.length = 0;

      // 一、append方法:
      DoublyLinkedList.prototype.append = function(data){
        // 1、创建新节点
        var newNode = new Node(data);

        // 2、判断链表是否为空
        if (this.length == 0) {//2.1链表为空
          this.head = newNode;
        }else{//2.2 链表不为空
          newNode.prev = this.tail;
          this.tail.next = newNode;
        }

        // 两种情况都需要的
        this.tail = newNode;

        // 3、长度要加1
        this.length += 1;
      }

      // 二、两种toString方法

      // 2.1forwardString
      DoublyLinkedList.prototype.forwardString = function(){
        var current = this.head;
        var resultString = '';
        while(current){
          resultString += current.data + ' ';
          current = current.next;
        }

        return resultString;
      }
      
      // 2.2 backwardString
      DoublyLinkedList.prototype.backwardString = function(){
        var previous = this.tail;
        var resultString = '';
        while(previous){
          resultString += previous.data + ' ';
          previous = previous.prev;
        }

        return resultString;
      }

      // 2.3 toString
      DoublyLinkedList.prototype.toString = function(){
        return this.forwardString();
      }


      // 三、 inset()
      DoublyLinkedList.prototype.inset = function(position, data){
        
        // 1、 先判断position是否合法
        if (position < 0 || position > this.length) return false;

        // 2、创建新节点
        var newNode = new Node(data);

        // 3、 判断链表长度是否为0
        if (this.length == 0) { // 3.1 链表长度为0
          // head和tail都指向newNode
          this.head = newNode;
          this.tail = newNode;
        }else{ // 3.2链表长度为0
          // 4、 判断插入位置是否为0
          if (position == 0) { // 4.1 插入位置为0
            newNode.next = this.head;
            this.head.prev = newNode;
            this.head = newNode;
          }else if(position == this.length){// 4.2插入位置为链表末尾
            newNode.prev = this.tail;
            this.tail.next = newNode;
          }else{  // 4.3 插入位置在链表之中
            var index = 0;
            var current = this.head;
            while(index++ < position){
              current = current.next;
            }
            newNode.prev = current.prev;
            current.prev.next = newNode;
            newNode.next = current;
            current.prev = newNode;
          }
        }
        // 5、长度要加1
        this.length += 1;
      }

      // 四、get()

      // 方法一
      DoublyLinkedList.prototype.get =function(position){
        // 1、 先判断position是否合法
        if (position < 0 || position > this.length - 1) return null;

        // 2、根据position位置信息找到对应节点
        var index = 0;
        var current = this.head;
        while(index++ < position){
          current = current.next;
        }
        return current.data;
      }

      // 方法二(优化)
      DoublyLinkedList.prototype.getFast =function(position){
        // 1、 先判断position是否合法
        if (position < 0 || position > this.length - 1) return null;

        // 2、根据position位置信息找到对应节点
        var previous = this.head;
        var current = this.tail;
        if (position < this.length / 2) {
          var index = 0;
          while(index++ < position){
            previous = previous.next;
          }
          return previous.data;
        }else{
          var index = this.length - 1;
          while(index-- > position){
            current = current.prev;
          }
          return current.data;
        }
      }


      // 五、
      DoublyLinkedList.prototype.indexOf =function(data){
        var index = 0;
        var current = this.head;

        while(current){
          if (current.data == data) return index;
          current = current.next;
          index += 1;
        }

        return -1;
      }

      // 六
      DoublyLinkedList.prototype.upDate = function(position, data){
 
        // 越界判断
        if (position < 0 || position >= this.length) return false;
 
        // 2、根据position位置信息找到对应节点
        var previous = this.head;
        var current = this.tail;
        if (position < this.length / 2) {
          var index = 0;
          while(index++ < position){
            previous = previous.next;
          }
          previous.data = data;
        }else{
          var index = this.length - 1;
          while(index-- > position){
            current = current.prev;
          }
          current.data = data;
        }
        return true;
      }


      // 七
      DoublyLinkedList.prototype.removeAt = function(position){
        // 判断position是否合法
        if (position < 0 || position >= this.length) return false;

        // 寻找节点
        var current = this.head;
        if (this.length == 1) {
          this.head = null;
          this.tail = null;
        }else{
          if (position == 0) {
            // 让head指向第二个节点
            this.head.next.prev = null
            this.head = this.head.next;
          }else if (position == this.length - 1) {
            current = this.tail;
            this.tail.prev.next = null;
            this.tail = this.tail.prev;
          }else{
            var index = 0;
            while(index++ < position){
              current = current.next;
            }
            current.prev.next = current.next;
            current.next.prev = current.prev;
          }
        }

        // length-1
        this.length -= 1;

        return current.data;
      }


      // 八、remove(data)
      DoublyLinkedList.prototype.remove = function(data){
        // 根据data获取元素位置
        var index = this.indexOf(data);

        // 根据index将对应节点删除
        return this.removeAt(index);
      }

      // 九、判断链表是否为空
      DoublyLinkedList.prototype.isEmpty = function(){
        return this.length == 0;
      }

      // 十、获取队列中的元素个数
      DoublyLinkedList.prototype.size = function(){
        return this.length;
      }


    }

    // 创建DoublyLinkedList
    var DLinkedList = new DoublyLinkedList();

    // 测试代码


  </script>
</body>
</html>

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值