一、棧
棧(stack)又名堆疊,它是一種運算受限的線性表,限定僅在表尾進行插入和刪除操作的線性表
表尾這一端被稱為棧頂,相反地另一端被稱為棧底,向棧頂插入元素被稱為進棧、入棧、壓棧,從棧頂刪除元素又稱作出棧
所以其按照先進後出的原則儲存資料,先進入的資料被壓入棧底,最後的資料在棧頂,需要讀資料的時候從棧頂開始彈出資料,具有記憶作用
關於棧的簡單實現,如下:
class Stack { constructor() { this.items = []; } /** * 新增一個(或幾個)新元素到棧頂 * @param {*} element 新元素 */ push(element) { this.items.push(element) } /** * 移除棧頂的元素,同時返回被移除的元素 */ pop() { return this.items.pop() } /** * 返回棧頂的元素,不對棧做任何修改(這個方法不會移除棧頂的元素,僅僅返回它) */ peek() { return this.items[this.items.length - 1] } /** * 如果棧裡沒有任何元素就返回true,否則返回false */ isEmpty() { return this.items.length === 0 } /** * 移除棧裡的所有元素 */ clear() { this.items = [] } /** * 返回棧裡的元素個數。這個方法和陣列的length屬性很類似 */ size() { return this.items.length } }
關於棧的操作主要的方法如下:
- push:入棧操作
- pop:出棧操作
二、佇列
跟棧十分相似,佇列是一種特殊的線性表,特殊之處在於它只允許在表的前端(front)進行刪除操作,而在表的後端(rear)進行插入操作
進行插入操作的端稱為隊尾,進行刪除操作的端稱為隊頭,當佇列中沒有元素時,稱為空佇列
在佇列中插入一個佇列元素稱為入隊,從佇列中刪除一個佇列元素稱為出隊。因為佇列只允許在一端插入,在另一端刪除,所以只有最早進入佇列的元素才能最先從佇列中刪除,故佇列又稱為先進先出
簡單實現一個佇列的方式,如下:
class Queue { constructor() { this.list = [] this.frontIndex = 0 this.tailIndex = 0 } enqueue(item) { this.list[this.tailIndex++] = item } unqueue() { const item = this.list[this.frontIndex] this.frontIndex++ return item } }
上述這種入隊和出隊操作中,頭尾指標只增加不減小,致使被刪元素的空間永遠無法重新利用
當佇列中實際的元素個數遠遠小於向量空間的規模時,也可能由於尾指標已超越向量空間的上界而不能做入隊操作,出該現象稱為"假溢"
在實際使用佇列時,為了使佇列空間能重複使用,往往對佇列的使用方法稍加改進:
無論插入或刪除,一旦rear
指標增1或front
指標增1 時超出了所分配的佇列空間,就讓它指向這片連續空間的起始位置,這種佇列也就是迴圈佇列
下面實現一個迴圈佇列,如下:
class Queue { constructor(size) { this.size = size; // 長度需要限制, 來達到空間的利用, 代表空間的長度 this.list = []; this.font = 0; // 指向首元素 this.rear = 0; // 指向準備插入元素的位置 } enQueue() { if (this.isFull() == true) { return false } this.rear = this.rear % this.k; this._data[this.rear++] = value; return true } deQueue() { if(this.isEmpty()){ return false; } this.font++; this.font = this.font % this.k; return true; } isEmpty() { return this.font == this.rear - 1; } isFull() { return this.rear % this.k == this.font; } }
上述透過求餘的形式代表首尾指標增1 時超出了所分配的佇列空間
三、應用場景
棧
藉助棧的先進後出的特性,可以簡單實現一個逆序數處的功能,首先把所有元素依次入棧,然後把所有元素出棧並輸出
包括編譯器的在對輸入的語法進行分析的時候,例如"()"
、"{}"
、"[]"
這些成對出現的符號,藉助棧的特性,凡是遇到括號的前半部分,即把這個元素入棧,凡是遇到括號的後半部分就比對棧頂元素是否該元素相匹配,如果匹配,則前半部分出棧,否則就是匹配出錯
包括函式呼叫和遞迴的時候,每呼叫一個函式,底層都會進行入棧操作,出棧則返回函式的返回值
生活中的例子,可以把乒乓球盒比喻成一個堆疊,球一個一個放進去(入棧),最先放進去的要等其後面的全部拿出來後才能出來(出棧),這種就是典型的先進後出模型
佇列
當我們需要按照一定的順序來處理資料,而該資料的資料量在不斷地變化的時候,則需要佇列來幫助解題
佇列的使用廣泛應用在廣度優先搜尋種,例如層次遍歷一個二叉樹的節點值(後續將到)
生活中的例子,排隊買票,排在隊頭的永遠先處理,後面的必須等到前面的全部處理完畢再進行處理,這也是典型的先進先出模型
參考文獻
- https://baike.baidu.com/item/%E6%A0%88/12808149
- https://baike.baidu.com/item/%E9%98%9F%E5%88%97/14580481
如果對您有所幫助,歡迎您點個關注,我會定時更新技術文件,大家一起討論學習,一起進步。