javascript數據結構與算法----雙向鏈表

單向鏈表的特點
在這裏插入圖片描述
單向鏈表的缺點
在這裏插入圖片描述
雙向鏈表
在這裏插入圖片描述
雙向鏈表的缺點
在這裏插入圖片描述
在這裏插入圖片描述
雙向鏈表的特點
在這裏插入圖片描述
雙向鏈表基本屬性的封裝
在單向鏈表中head存儲的是第一個節點的引用,在雙向鏈表中tail存儲的是最後一個節點的引用

// 雙向鏈表的封裝
function DoubleLinkedList(){
    // 屬性
    this.head = null
    // 在雙向鏈表裏面this.tail一定是指向最後一個節點
    this.tail = null
    this.length = 0
    // 內部的類進行節點的創建(3個屬性)
    function Node(data){
        this.data = data
        this.prev = null
        this.next = null
    }
    // 封裝常見的操作
}

雙向鏈表的常見操作
在這裏插入圖片描述
(1)實現append方法

DoubleLinkedList.prototype.append=function(data){
            // 根據傳入的數據創建節點
            var newNode = new Node(data)
            // 如果當前鏈表沒有元素
            if(this.length == 0){
                this.head = newNode
                this.tail = newNode
            }else{
                newNode.prev = this.tail
                this.tail.next = newNode
                this.tail = newNode
            }
            this.length += 1
        }

(2)實現toString ,forwardString ,backwardString 方法

    // 將鏈表轉爲字符串的形式
    DoubleLinkedList.prototype.toString = function(){
      return this.backwardString()
    } 
    // forwardString:向前遍歷
    DoubleLinkedList.prototype.forwardString = function(){
      var current = this.tail
      var resultString = ''
      // 依次向前遍歷獲取每一個節點
      while(current){
        resultString += current.data + ' '
        current = current.prev
      }
      return resultString
    }
    // backwardString:向後串聯爲字符串
    DoubleLinkedList.prototype.backwardString = function(){
      var current = this.head
      var resultString = ''
      // 依次向後遍歷獲取每一個節點
      while(current){
        resultString += current.data + ' '
        current = current.next
      }

      return resultString
    }

(3)實現insert方法
(當position是0的情況的圖示)
在這裏插入圖片描述

DoubleLinkedList.prototype.insert=function(position,data){
  // 當存入position的時候,先進行越界判斷
  var newNode = new Node(data)
  if(position<0 || position>this.length) return false
  // 當前兩邊是否有元素
  if(this.length === 0){
    // 將head的指針指向newNode
    this.head = newNode
    this.tail = newNode
  }else{
    // 判斷position是否是0
    if(position === 0){
      // this.head指向的是原本的那個元素
      this.head.prev = newNode
      newNode.next = this.head
      this.head = newNode
    }else if(position == this.length){
      // this.tail指向最後一個節點
        newNode.prev = this.tail
        this.tail.next = newNode
        this.tail = newNode
    }else{
      var current = this.head,
          index = 0
          previous = null;
      while(index++<position){
        previous = current
        current = current.next
      }
      newNode.next = current
      previous.next = newNode
      
      current.prev = newNode
      newNode.prev = previous
    }
  }

  length += 1
  return true

}

(4)實現get方法

DoubleLinkedList.prototype.get=(position)=>{
  // 越界判斷
  if(position<0 || position>= this.length) return null
  var current = this.head
  var index = 0
  while(index++ < position){
    current = current.next
  }
  return current.data
}

但是通過這樣實現的get方法,當鏈表的元素過多的時候, 其實是效率不高的,因爲這個方法是從前依次王后進行尋找,如果找的是鏈表末尾的元素,在單向鏈表中必須是從前往後尋找,但是在雙向鏈表中,可以通過從後往前的方式,在尋找末尾元素的時候會更加快捷,方便。

DoubleLinkedList.prototype.get=(position)=>{
  // 越界判斷
  if(position<0 || position>= this.length) return null
  var current = this.head
  // 噹噹前尋找的位置處於前半段的時候
  var len = this.length
  var index = 0
  if(len / 2 > position ){
    while(index++ < position){
      current = current.next
    }
    return current.data
  }else{
    // 當前尋找的元素處於後半段
    current = this.tail
    index = this.length -1
    while(index-- > position) {
      current = current.prev
    }
    console.log('我是後半段')
    return current.data
  }
  
}

(4)實現indexOf方法

DoubleLinkedList.prototype.indexOf=(data)=>{
  var current = this.head
  var index =0

  // 查找與data相同的節點
  while(current){
    if(current.data === data){
      return index
    }
    current = current.next
    index += 1
  }
  return -1
}

(5)實現update方法(也可以像get方法一樣,進行一個優化)

DoubleLinkedList.prototype.update=(position,newDate)=>{
  //  越界判斷
  if(position<0 || position>=this.length) return false
  var current = this.head
  var index = 0
  while(index++ < position){
    current = current.next
  }
  // 找到的時候修改值
  current.data = newDate
  return true
}

(6)實現removeAt方法(當一個節點,沒有其他節點的引用指向它的話,那麼這個節點就會被回收)

         DoubleLinkedList.prototype.removeAt=(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 -1){
          current = this.tail
          this.tail.prev.next = null
          this.tail = this.tail.prev
        }else{
          var index = 0
          while(index++ < position){
            current = current.next
          }
          // 找到以後需要改變2個指針
          current.prev.next =current.next
          current.next.prev = current.prev
        }
      }

      // 最後修改length屬性
      this.length -=1
      return current.data
    }

(7)實現remove方法

DoubleLinkedList.prototype.remove=(data)=>{
  // 獲取索引
  var index = this.indexOf(data)
  return this.removeAt(index)
}

(8)其餘方法的實現(isEmpty,size)

DoubleLinkedList.prototype.isEmpty=(data)=>{
  return this.length == 0
}
DoubleLinkedList.prototype.size=(data)=>{
  return this.length
}

(9)雙向鏈表獲取第一個節點元素

DoubleLinkedList.prototype.getFirst=(data)=>{
   return this.head.data
 }

(10)雙向鏈表獲取最後一個節點元素

DoubleLinkedList.prototype.getLast=(data)=>{
  // 獲取索引
  return this.tail.data
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章