JavaScript数据结构与算法2

126 阅读4分钟

参考

单链表(LinkList)

  • 不必创建时确定大小,插入和删除操作的比用数组快
    • 但需要从头开始访问,无法通过下标值访问
function LinkList(){
  this.head = null;
  this.length = 0;
  function Node(data){
    this.data = data;
    this.next = null;
  }
  
  // append(element):链表尾添加元素,返回新链表元素的个数
  LinkList.prototype.append = function(element){
    // 创建新的节点存储元素
    var newNode = new Node(element);
    if(this.length === 0){
      // 链表空,头指针指向新节点
      this.head = newNode;
    }else{
      // 链表非空,遍历链表到尾节点,使尾节点的next指向新节点   
      var node = this.head;
      while(node.next){
        node = node.next;
      }
      node.next = newNode;
    } 
    return ++ this.length;
  }
  // insert(position):在position位置插入element
  LinkList.prototype.insert = function(position,element){
    // position的越界判断,链表的非空判断
    if(position < 0 || position > this.length || !this.length)
      return false;
      
    var newNode = new Node(element);
    if(position == 0){
    // 在第一个位置插入,先将newNode的下一个节点指向原来的头节点,
    // 再将首元指针指向newNode
      newNode.next = this.head;
      this.head = newNode;
    }else{
    // 遍历到链表尾节点,然后再添加 
       var node = this.head;
       var prev = null;
       while(position){
         prev = node;
         node = node.next;
         position --;
       }
       newNode.next = node;
       prev.next = newNode;
    }
    return ++ this.length;
  }
  
  // get(position):获取position位置的element,失败返回-1
  LinkList.prototype.get = function(position){
    // position越界判断,链表非空判断
    if(position < 0 || position > this.length - 1 || !this.length)
      return -1;
    // 遍历链表到position位置的节点
    var node = this.head;
    while(position){
      node = node.next;
      position --;
    }    
    return node.data;
  }
  // indexOf(element):获取element元素的下标
  LinkList.prototype.indexOf = function(element){
  // 遍历链表,判断每个节点是否要找的element,找不到return -1
    var node = this.head;
    var index = 0;
    while(node){
      if(node.data === element){
        return index;
      }
      index ++;
      node = node.next;
    }
    return -1;
  }
  
  // update(position,element):修改position位置的元素为element
  LinkList.prototype.update = function(position,element){
    // position越界判断,链表非null判断
    if(position < 0 || position > this.length - 1 || !this.length)
      return false;
    // 遍历链表到position位置的节点,再更新元素
    var node = this.head;
    while(position){
      node = node.next;
      position --;
    }
    node.data = element;
    return true;
  }
  
  // removeAt(position):移除position位置的元素
  LinkList.prototype.removeAt = function(position){
    // position的越界判断,链表非空判断
    if(position < 0 || position > this.length - 1 || !this.length)
      return false;
      
    var node = this.head;
    if(position == 0){
      // 移除头节点,更新头指针
      this.head = node.next;
    }else{
      // 遍历链表到position位置的节点,记录当前节点和前一个节点来进行移除
      var prev = null;
      while(position){
        prev = node;
        node = node.next;
        position --;
      }
      prev.next = node.next;
    }
    node.next = null;
    this.length --;
    
    return node.data;
  }
  // remove(element):移除链表中的element元素
  LinkList.prototype.remove = function(element){
    // 获取此元素的下标,再根据下标把此元素移除
    var index = this.indexOf(element);
    return this.removeAt(index);
  }  

  // isEmpty():判断链表是否null
  LinkList.prototype.isEmpty = function(){
    return this.length === 0;
  }
  // size():链表的大小
  LinkList.prototype.size = function(){
    return this.length;
  }
  // toString():正向遍历链表元素,将每个节点的元素转化为字符串
  LinkList.prototype.toString = function(){
    var resultString = '';
    var node = this.head;
    while(node.next){
      resultString += node.data;
      node = node.next;
    }
    return resultString;
    
  }
}

双向链表(DoubleLinkList)

  • 区别单链表
    • 1、多了尾指针指向链表尾部(tail)
    • 2、每个节点除了next指针、还多了prev指针指向前一个节点
function DoubleLinkList(){
  this.head = null;// 指向头节点的头指针
  this.tail = null;// 指向尾节点的尾指针
  this.length = 0;// 双向链表的节点数
  function Node(data){
      this.data = data;
      this.prev = null;// 指向前一个节点的指针
      this.next = null;// 指向后一个节点的指针
  }

  // append(element):在链表尾部添加新的节点
  DoubleLinkList.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;
      }
  // 节点数 +1
      return ++ this.length;
  }
  // insert(position,element):在position出添加element元素
  DoubleLinkList.prototype.insert = function(position,element){
      // 判断position是否越界
      if(position < 0 || position > this.length)
          return false;

      var newNode = new Node(element);
      // 空链表,头指针和尾指针指向新节点
      if(this.length === 0){
          this.head = newNode;
          this.tail = newNode;
      }else{
          // 非空链表
          if(position == 0){
              // 0位置添加元素,新节点指向原头节点,原头节点的前一个节点是新节点
              newNode.next = this.head;
              this.head.prev = newNode;
              // 更新头指针
              this.head = newNode;
          }else if(position == this.length){
              // 在尾部添加元素,用尾指针的下一节点指向新节点,
              // 新节点的前一节点是原尾节点
              this.tail.next = newNode;
              newNode.prev = this.tail;
              // 跟新尾指针
              this.tail = newNode;
          }else{ 
              var node = this.head;
              while(position){
                  node = node.next;
                  position --;
              }
              
              newNode.next = node;
              newNode.prev = node.prev;
              node.prev.next = newNode;
              node.prev = newNode;
          }
      }

      this.length ++;
      return true;
  }

  // get(position)
  DoubleLinkList.prototype.get = function(position){
      // 判断position是否越界
      if(position < 0 || position > this.length - 1)
          return  null;
  // 通过中间数,来判断应该从头节点开始遍历还是尾节点开始遍历链表去寻找相应位置元素
      var temp = Math.ceil(this.length / 2);
      var node = temp > position 
                      ? this.head : this.tail;

      var index_p = temp > position
                         ? position : this.length - 1 - position;
      while(index_p){
          node = temp > position
                      ? node.next : node.prev;
          index_p --;
      }

      return node;
  }
  // indexOf(element):返回元素在链表的下标,空链表、失败返回-1
  DoubleLinkList.prototype.indexOf = function(element){
      var node = this.head;
      var index = 0;
      while(node){
          if(node.data === element){
              return index;
          }
          node = node.next;
          index ++;
      }
      return -1;
  }

  // update(position,element)
  DoubleLinkList.prototype.update = function(position,element){
      // position是否越界,链表是否为NULL
      if(position < 0 || position > this.length - 1 || !this.length)
          return false;
      // 遍历链表到指定位置的节点,再修改元素
      var node = this.head;
      while(position){
          node = node.next;
          position --;
      }
      node.data = element;
      return true;
  }

  // removeAt(position)
  DoubleLinkList.prototype.removeAt = function(position){
      // 判断position是否越界,链表是否NULL
      if(position < 0 || position > this.length - 1 || !this.length)
          return false;
      
      var node = this.head;
      if(this.length === 1){
      // 链表只有一个节点,直接移除
          this.head = null;
          this.tail = null;
      }else{
          // 结点数 > 1
          if(position == 0){
              // 移除头节点,跟新头节点指向原头节点的下一节点,跟新头指针
              this.head.next.prev = null;
              this.head = this.head.next;

          }else if(position == this.length - 1){
              // 移除尾节点,跟新尾节点指向原尾节点的前一节点,跟新尾指针
              this.tail.prev.next = null;
              node = this.tail;

              this.tail = this.tail.prev;
          }else{
              while(position){
                  node = node.next;
                  position --;
              }
              node.prev.next = node.next;
              node.next.prev = node.prev;
          }                 
          node.prev = null;
          node.next = null;
      }
                              
      this.length --;
      return node;
  }
  // remove(element)
  DoubleLinkList.prototype.remove = function(element){
  // 先获取移除的元素的下标,再根据下标移除元素
      var index = this.indexOf(element);
      return  this.removeAt(index);
  }

  // isEmpty()
  DoubleLinkList.prototype.isEmpty = function(){
      return this.length === 0;
  }
  // size()
  DoubleLinkList.prototype.size = function(){
      return this.length;
  }
  // toString():返回正向遍历的节点元素的字符串
  DoubleLinkList.prototype.toString = function(){
      var resultString = '';
      var node = this.head;
      while(node){
          resultString += node.data;
          node = node.next;
      }
      return resultString;
  }
  
  // fowarString():返回正向遍历的节点元素的字符串
  DoubleLinkList.prototype.forwardString = function(){
      var resultString = '';
      var node = this.head;
      while(node){
          resultString += node.data;
          node = node.next;
      }
      return resultString;
  }

  // backwordString():返回反向遍历的节点元素的字符串
  DoubleLinkList.prototype.backwordString = function(){
      var resultString = '';
      var node = this.tail;
      while(node){
          resultString += node.data;
          node = node.prev;
      }
      return resultString;
  }
}


// 测试代码
var doubleList = new DoubleLinkList();
doubleList.append("0");
doubleList.append("1");
doubleList.insert(0,"2");
doubleList.insert(4,"3");
doubleList.insert(2,"4");