JS数据结构(6)——双向链表

JS数据结构(6)——双向链表

1.什么是双向链表?

单向链表

要知道什么是双向链表,我们首先得了解单向链表。
单向链表的详细解释在这里: JS单向链表
单向链表的特点:

  • 只能从头遍历到尾
  • 链表的连接过程是单向的
  • 实现的原理是上一个链表结点中有一个指向下一个结点的next
    单向链表的结构:

    单向节点的缺点:
    可以轻松到达下一个节点,但是回到前一个节点是非常困难的。
双向链表

双向链表的特点:

  • 既可以从头遍历到尾,也可以从尾遍历到头
  • 链表连接的过程时双向的
  • 实现原理是一个链表结点,既有指向前一个的pre指针,也有指向后一个的next指针
  • 双向链表可以有效的解决单向链表的缺点。
  • 头节点用head表示,尾节点用tail表示

双向链表的缺点:

  • 每次在插入或删除时,需要处理四个指针,实现起来困难‘
  • 所占的内存空间比单向链表要大

双向链表的结构:

2.双向链表的封装

1.代码思路
  • 我们封装一个DoublyLinkedList的类,用于表示双向链表的结构
  • 在DoublLinkedList类中,需要封装一个内部类Node用于表示每个结点信息(包括指向上个结点的指针pre,指向下个结点的指针next,以及结点数据)
  • 双向链表中我们还需要保存三个属性,链表的长度,链表的头结点head,以及链表的尾结点tail
  • 双向链表的常见操作
    (1)append(element):向链表尾部添加一个新的项
    (2)insert(position,element):向链表的特定位置插入一个新的项
    (3)get(position):获取对应位置的元素
    (4)indexOf(element):返回元素在链表中的索引,如果没有返回-1
    (5)update(position,element):修改某个位置的元素
    (6)removeAt(position):移除链表中position位置的一项
    (7)remove(element):移除链表中元素为element的一项
    (8)isEmpty():判断链表是否为空,为空返回true,否则返回false
    (9)size():返回链表中的元素个数
    (10)forwardString():以字符串形式返回向前遍历的结点
    (11)backwordString():以字符串形式返回向后遍历的结点
    (12)getHead():获取链表的第一个元素
    (13)getTail():获取链表的最后一个元素
2.代码实现
function DoublyLinkedList () {
  this.head = null;
  this.tail = null;
  this.length = 0;

  // 结点类
  function Node(data) {
    this.data = data;
    this.prev = null;
    this.next = null;
  }
  // append(element):向链表尾部添加一个新的项
  DoublyLinkedList.prototype.append = function(element) {
    var newNode = new Node(element);
    if(this.length === 0) {
      this.head = newNode;
      this.tail = newNode;
    }else {
      newNode.prev = this.tail;
      this.tail.next = newNode;
      this.tail = newNode;
    }
    this.length ++;
  } 
  // forwardString():以字符串形式返回向前遍历的结点
  DoublyLinkedList.prototype.forwardString = function() {
    var current = this.tail;
    var resultString = "";
    while(current){
      resultString += current.data + "  ";
      current = current.prev;
    }
    return resultString;
  }
  // backwordString():以字符串形式返回向后遍历的结点
  DoublyLinkedList.prototype.backwordString = function() {
    var current = this.head;
    var resultString = "";
    while(current){
      resultString += current.data + "  ";
      current = current.next;
    }
    return resultString;
  }
  // insert(position,element):向链表的特定位置插入一个新的项
  DoublyLinkedList.prototype.insert = function(position, element) {
    var current = this.head;
    var index = 0;
    var newNode = new Node(element);
    if(position < 0 || position > this.length)
      return null;
    if(position == 0 ){
      this.head.prev = newNode;
      newNode.next = this.head;
      this.head = newNode;
    }else if(position == this.length){
      this.tail.next = newNode;
      newNode.prev = this.tail;
      this.tail = newNode;
    }else {
      while(index++ < position - 1){
        current = current.next;
      }
      newNode.next = current.next;
      newNode.prev = current;
      current.next.prev = newNode;
      current.next = newNode;
    }
    this.length ++;
  }
  // get(position):获取对应位置的元素
  DoublyLinkedList.prototype.get = function(position) {
    if(position < 0 || position >= this.length)
      return null;
    var current = this.head;
    var index = 0;
    while(index < position) {
      index ++;
      current = current.next;
    }
    return current.data;
  }
  // indexOf(element):返回元素在链表中的索引,如果没有返回-1
  DoublyLinkedList.prototype.indexOf = function(element) {
    var current = this.head;
    var index = 0;
    while(current) {
      if(current.data == element)
        return index;
      current = current.next;
      index ++;
      return index;
    }
    return -1;
  }
  // update(position,element):修改某个位置的元素
  DoublyLinkedList.prototype.update = function(position,element) {
    if(position < 0 || position >= this.length)
      return null;
    var index = 0;
    var current = this.head;
    while(index < position) {
      index ++;
      current = current.next;
    }
    current.data = element;
    return true;
  }
  // removeAt(position):移除链表中position位置的一项
  DoublyLinkedList.prototype.removeAt = function(position) {
    if(position < 0 || position >= this.length)
      return null;
    var current = this.head;
    if(this.length == 1) {
      this.head = null;
      this.tail = null;
    }else {
      if(position == 0) {
        this.head.next.prev = null;
        this.head = this.head.next;
      }else if(position == this.length) {
        current = this.tail;
        this.tail.prev.next = null;
        this.tail = this.tail.prev;
      }else {
        var index = 0;
        while(index < position) {
          index ++;
          current = current.next;
        }
        current.next.prev = current.prev;
        current.prev.next = current.next;
      }
    }
    this.length --;
    return current.data;
  }
  // remove(element):移除链表中元素为element的一项 
  DoublyLinkedList.prototype.remove = function(element) {
    var position = this.indexOf(element);
    return this.removeAt(position);
  }
  // isEmpty():判断链表是否为空,为空返回true,否则返回false
  DoublyLinkedList.prototype.isEmpty = function() {
    return this.length == 0;
  }
  // size():返回链表中的元素个数
  DoublyLinkedList.prototype.size = function() {
    return this.length;
  }
  // getHead():获取链表的第一个元素
  DoublyLinkedList.prototype.getHead = function() {
    return this.head.data;
  }
  // getTail():获取链表的最后一个元素
  DoublyLinkedList.prototype.getTail = function() {
    return this.tail.data;
  }
} 

// 测试:
var DList = new DoublyLinkedList();

DList.append('aaa');             
DList.append('bbb');            
DList.append('ccc');
console.log(DList.backwordString());     // 结果为:aaa  bbb  ccc 
console.log(DList.forwardString());      // 结果为:ccc  bbb  aaa 

DList.insert(1,'hhh');
console.log(DList.backwordString());     // 结果为:aaa  hhh  bbb  ccc

console.log(DList.get(2));     // 结果为:bbb
console.log(DList.indexOf('hhh'));     // 结果为:1
console.log(DList.indexOf('abc'));     // 结果为:-1

console.log(DList.update(2,'mmm'));     // 结果为:true
console.log(DList.backwordString());    // 结果为:aaa  hhh  mmm  ccc 

console.log(DList.removeAt(2));     // 结果为:mmm
console.log(DList.backwordString());// 结果为:aaa  hhh  ccc 

console.log(DList.remove('hhh'));     // 结果为:hhh
console.log(DList.backwordString());  // 结果为:aaa  ccc 

console.log(DList.isEmpty());     // 结果为:false
console.log(DList.size());        // 结果为:2
console.log(DList.getHead());     // 结果为:aaa
console.log(DList.getTail());     // 结果为:ccc
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值