基礎系列:掌握隊列基礎

先贊再看, 養成習慣 :P

俗話說得好, "時刻準備着"。前端

算法和數據結構, 對工程師來講是十分重要的。 node

而這一部分, 靠短時間的衝刺學習是很難掌握的。只有靠刻意的學習和不斷練習才能掌握。面試

今天咱們就來複習下隊列。算法

瞭解隊列的使用姿式

隊列是很是常見的數據結構, 面試中也常常出現。segmentfault

今天咱們就說一下這種數據結構, 而後看兩道題。數組

文中可能涉及到鏈表,鏈表我在以前的文章中寫過,參考連接:數據結構

[第28期] 回顧一下常見的鏈表操做
[第29期] 熟悉鏈表的幾個經典題目數據結構和算法

隊列

隊列是一種線性的數據結構, 表現上是先進先出, FIFO.函數

生活中典型的場景就是排隊了,從後插入新元素, 移除最舊的元素:學習

下面咱們用兩種姿式來實現一個隊列:

  1. 鏈表

leetcode #232 用棧實現隊列

使用棧實現隊列的下列操做:

  1. push(x) -- 將一個元素放入隊列的尾部。
  2. pop() -- 從隊列首部移除元素。
  3. peek() -- 返回隊列首部的元素。
  4. empty() -- 返回隊列是否爲空。

示例:

MyQueue queue = new MyQueue();

queue.push(1);
queue.push(2);
queue.peek();  // 返回 1
queue.pop();   // 返回 1
queue.empty(); // 返回 false

1.用棧實現隊列

棧是一種先進後出的數據結構, 隊列是一種先進先出的數據結構,那怎麼用棧來模擬隊列呢?

很簡單, 倒兩次就好了。

用兩個棧, 一個用於入隊, 一個用於出隊:

圖解:

代碼實現:

/**
 * Initialize your data structure here.
 */
var MyQueue = function() {
  this.input = [];
  this.output = [];
};

/**
 * Push element x to the back of queue.
 * @param {number} x
 * @return {void}
 */
MyQueue.prototype.push = function(x) {
  this.input.push(x);
};

/**
 * Removes the element from in front of queue and returns that element.
 * @return {number} 從隊列首部移除元素
 */
MyQueue.prototype.pop = function() {
  while (this.input.length) {
    this.output.push(this.input.pop());
  }
  var first = this.output.pop();

  while (this.output.length) {
    this.input.push(this.output.pop());
  }
  return first;
};

/**
 * Get the front element. 返回隊列首部的元素。
 * @return {number}
 */
MyQueue.prototype.peek = function() {
  return this.input[0];
};

/**
 * Returns whether the queue is empty.
 * @return {boolean} 返回隊列是否爲空
 */
MyQueue.prototype.empty = function() {
  return !this.input.length && !this.output.length;
};

var obj = new MyQueue();
obj.push(1);
obj.push(2);
obj.push(3);

var param_2 = obj.pop();
console.log(param_2); // 隊首出來, 1

var param_3 = obj.peek();
console.log(param_3); // 返回隊列首部的元素: 2

var param_4 = obj.empty();
console.log('isEmpty: ', param_4); // false

2. 用鏈表實現隊列

鏈表咱們都很熟悉了, 以前兩期都是關於鏈表的:xxx, xxx

先看一下基礎結構, 包含咱們要實現哪些功能:

// Queue using linkedlist
function QueueUsingLinkList() {
  let Node = function(elm) {
    this.element = elm;
    this.next = null;
  };

  // To keep track of the size
  let length = 0;

  //To keep track of the list
  let head = null;

  // Enqueue data in the queue
  this.enqueue = function(elm) {};

  // Remove the item from the queue
  this.dequeue = function() {};

  // Return the first element in the queue
  this.peek = function() {};

  //Return the last element in the queue
  this.rear = function() {};

  //Check if queue is empty
  this.isEmpty = function() {};

  //Return the size of the queue
  this.size = function() {};

  //Clear the queue
  this.clear = function() {};
}

enqueue, 往隊列中添加元素

首先要檢查隊列是否是空的, 若是是空的, 就把新元素當成頭結點,不然, 就把新元素加到末尾。

代碼實現:

//Enqueue data in the queue
this.enqueue = function (elm) {
    let node = new Node(elm),
        current;

    //If head is empty then
    //Add the node at the beginning
    if (head === null) {
        head = node;
    } else {
        //Else add the node as the
        //Next element of the existing list
        current = head;
        while (current.next) {
            current = current.next;
        }

        current.next = node;
    }

    //Increase the length
    length++;
};

dequeue, 從隊列中刪除元素

隊列是先進先出的數據結構, 因此出隊的時候, 要移除並返回頭部的元素,長度減一,並把指針日後移步一位。

代碼實現:

//Remove the item from the queue
  this.dequeue = function () {
      let current = head;

      //If there is item then remove it 
      //and make the next element as the first
      if (current) {
          let elm = current.element;
          current = current.next;
          head = current;
          length--;
          return elm;
      }

      return null;
  }

其餘輔助方法

核心的入隊, 出隊,咱們已經實現了, 爲了方便調試, 咱們順便實現幾個輔助函數:

  • peek 查看頭部元素
  • rear 查看尾部元素
  • to array 轉換成數組
  • size 查看大小
  • isEmpty 查看是否爲空
  • 清空隊列

isEmpty

//Check if queue is empty
this.isEmpty = function() {
    return length === 0;
}

size

//Return the size of the queue
this.size = function() {
    return length;
}

以數組的形勢查看:

//Convert the queue to an array
this.toArray = function () {
    let arr = [];
    let current = head;
    while (current) {
        arr.push(current.element);
        current = current.next;
    }

    return arr;
}

rear 查看尾部元素

//Return the last element in the queue
this.rear = function () {
    let current = head;

    //If head is empty
    //Return null
    if (current === null) {
        return null;
    }

    //Return the last elememnt
    while (current.next) {
        current = current.next;
    }

    return current.element;
}

peek

//Return the first element in the queue
this.peek = function () {
    if (head) {
        return head.element;
    }

    return null;
}

clear

//Clear the queue
this.clear = function() {
  head = null;
  length = 0;
}

測試

let queue = new QueueUsingLinkList();
console.log(queue.isEmpty()); // true

queue.enqueue('pranav');
queue.enqueue('sachin');
queue.enqueue('yogesh');
console.log(queue.toArray()); // ["pranav", "sachin", "yogesh"]

queue.dequeue();
queue.dequeue();
console.log(queue.toArray()); // ["yogesh"]

queue.enqueue('prashant');
queue.enqueue('yadav');
queue.dequeue();
console.log(queue.toArray()); // ["prashant", "yadav"]
console.log(queue.size()); // 2
console.log(queue.peek()); // "prashant"
console.log(queue.rear()); // "yadav"

完整代碼

//Queue using linkedlist
function QueueUsingLinkList() {
    //Node 
    let Node = function (elm) {
        this.element = elm;
        this.next = null;
    }

    //To keep track of the size  
    let length = 0;

    //To keep track of the list
    let head = null;

    //Enqueue data in the queue
    this.enqueue = function (elm) {
        let node = new Node(elm),
            current;

        //If head is empty then 
        //Add the node at the beginning
        if (head === null) {
            head = node;
        } else {
            //Else add the node as the
            //Next element of the existing list
            current = head;
            while (current.next) {
                current = current.next;
            }

            current.next = node;
        }

        //Increase the length
        length++;
    }

    //Remove the item from the queue
    this.dequeue = function () {
        let current = head;

        //If there is item then remove it 
        //and make the next element as the first
        if (current) {
            let elm = current.element;
            current = current.next;
            head = current;
            length--;
            return elm;
        }

        return null;
    }

    //Return the first element in the queue
    this.peek = function () {
        if (head) {
            return head.element;
        }

        return null;
    }

    //Return the last element in the queue
    this.rear = function () {
        let current = head;

        //If head is empty
        //Return null
        if (current === null) {
            return null;
        }

        //Return the last elememnt
        while (current.next) {
            current = current.next;
        }

        return current.element;
    }

    //Convert the queue to an array
    this.toArray = function () {
        let arr = [];
        let current = head;
        while (current) {
            arr.push(current.element);
            current = current.next;
        }

        return arr;
    }

    //Check if queue is empty
    this.isEmpty = function () {
        return length === 0;
    }

    //Return the size of the queue
    this.size = function () {
        return length;
    }

    //Clear the queue
    this.clear = function () {
        head = null;
        length = 0;
    }

}

總結

掌握這些常見的數據結的基礎操做,對咱們的平常工做也有好處。

要學好數據結構和算法, 須要 三分理論, 七分實踐。

但願今天的內容對你有所啓發,謝謝 :)

最後

若是你以爲內容有幫助, 能夠關注下個人公衆號 「 前端e進階 」,一塊兒學習, :)
clipboard.png

相關文章
相關標籤/搜索