JavaScript數據結構《隊列》

隊列和棧很是的相似,可是他們採用了不一樣的原則,棧採用的是後進先出,隊列正好相反,採用的是先進先出的原則。隊列的定義以下java

隊列是遵循FIFO(先進先出)原則的有序集合,新添加的元素保存在隊列的尾部,要移除的元素保存在隊列的頂部。在隊列的這種數據結構裏面,新增的元素都在尾部,要移除的元素都在頂部。數組

舉一個生活中的例子,在咱們平時去吃肯德基吃飯時確定要排隊,這條隊伍就能夠看作是一個隊列,排在隊伍前面的就是隊列的頂部,隊伍後面的就是隊列的尾部,後來的人都要排在隊伍的後面(隊列的尾部),這就符合了隊列先進先出的原則了(先排隊的能夠先點餐)。網絡

代碼實現

下面用代碼來實現隊列這個數據結構,一樣都採用ES6的語法,咱們先定義一個類Queue來表示隊列,而後在這個類的基礎上定義一下方法來模擬隊列的行爲。數據結構

class Queue {

  constructor() {
    // 定義一個數組來保存隊列裏面的元素
    this.items = []
  }

  // 在隊列尾部添加一個或者多個元素
  enqueue(element) { }
    
  // 移除隊列頂部的元素,並返回被移除的元素
  dequeue() { }
    
  // 清空隊列
  remove() { }
    
  // 返回隊列頂部的元素,不對隊列自己作修改
  front() { }
    
  // 判斷隊列是否爲空
  isEmpty() { }
    
  // 返回隊列裏面元素的個數
  length() { }
}

這樣咱們就定義好一個基類了,下面來分別實現隊列的行爲方法this

enqueue

第一個要實現的就是enqueue方法,這個方法接收一個參數,而後把該參數插入隊列的尾部,由於這裏咱們是用數組來存儲隊列的元素的,因此能夠用數組的push方法來實現該操做,代碼以下線程

enqueue (element) {
   this.items.push(element)
 }

dequeue

下面接着實現dequeue方法,這個方法會從隊列裏面移除項,因爲隊列遵循的是先進先出的原則,因此咱們要移除的元素就是隊列頂部的元素,一樣由於這裏咱們是用數組來存儲隊列的元素的,因此能夠用數組的shift方法來實現該操做。代碼以下調試

dequeue () {
    return this.items.shift()
}

remove

接着來實現remove方法,改方法會移除隊列裏面全部的項,同理咱們把保存隊列元素的數組置空就行了,代碼以下code

remove () {
    this.items = []
}

front

上面的方法都是對隊列自己有修改的,接下來要實現的方法front作的是隻讀操做,front方法會返回隊列頂部的元素但不對隊列自己進行修改,代碼實現以下隊列

front () {
    return this.items[0]
}

isEmpty

isEmpty方法判斷隊列是否爲空,也就是保存隊列的數組的長度是否等於0,代碼實現以下ip

isEmpty () {
    return this.items.length === 0
}

length

最後一個方法返回隊列的長度,同理就是返回保存隊列元素的數組的長度就行了,代碼以下

length () {
    return this.item.length
}

這裏和棧同樣添加一個輔助方法print來打印棧裏面的元素,方便咱們觀察調試,這個方法和隊列的行爲無關,只是一個輔助方法

print(){
    this.items.forEach((item, index) => {
        console.log(`${index+1}:${item}`)
    })
}

這樣隊列的方法就所有寫好了,最後完整Queue類的代碼以下

class Queue {

  constructor() {
    // 定義一個數組來保存隊列裏面的元素
    this.items = []
  }

  // 在隊列尾部添加一個或者多個元素
  enqueue (element) {
      this.items.push(element)
  }
  // 移除隊列頂部的元素,並返回被移除的元素
  dequeue() { 
      return this.items.shift()
  }
  // 清空隊列
  remove() {
      this.items = []
  }
  // 返回隊列頂部的元素,不對隊列自己作修改
  front() { 
      return this.items[0]
  }
  // 判斷隊列是否爲空
  isEmpty() { 
      return this.items.length === 0
  }
  // 返回隊列裏面元素的個數
  length() { 
      return this.item.length
  }
    
  print(){
      this.items.forEach((item, index) => {
          console.log(`${index+1}:${item}`)
      })
  }
}

使用Queue類

要使用這個類咱們得先實例化它

const queue = new Queue()

queue.isEmpty() // true

queue.push('我是隊列的第一個元素')
queue.push('我是隊列的第二個元素')

queue.print() // 1: 我是隊列的第一個元素 2:我是隊列的第二個元素

queue.dequeue() // 我是隊列的第一個元素

queue.front() // 我是隊列的第二個元素

queue.length() // 1

queue.isEmpty() // false

queue.remove() // 這時隊列裏面已經沒有元素了

queue.isEmpty() // true

總結

隊列這種數據結構運用的是很是的普遍的,就好比javaScript的運行機制,咱們都知道javaScript是單線程的,是不能同時執行多個任務,可是單線程就意味着全部任務須要排隊。可是在javaScript裏面,不少時候阻止線程運行的很慢的是網絡IO之類,這時候CPU是空閒的,這樣就會形成資源的浪費。因此javaScript在主線程以外實現了一個任務隊列,像IO之類比較慢的操做暫時都會掛在任務隊列上,這樣不會影響到主線程上任務的執行,等到IO的響應回來後再回到主線程上來執行掛起的任務。例子就是咱們的Ajax請求,定時器等。