一.什麼是棧(stack)?
1.1.簡介
首先我們需要知道數組是一種線性結構,並且可以在數組的任意位置插入和刪除數據,而棧(stack)是一種受限的線性結構。以上可能比較難以理解,什麼是受限制的線性結構?讓我們首先來了解下棧結構的特點吧,下面就是棧的圖解:
總結棧的特點就是在放入數據的過程中是先進後出,後進後出(LIFO:last in first out)
1.2.程序中的棧實現
-
函數調用棧:A(B(C(D))),既A函數中調用B,B調用C,C調用D;在A執行的過程中將A壓入棧,隨後B執行時B也被壓入棧,同理C和D執行時也會被壓入棧。所有當前棧的順序是:A->B->C->D(棧頂);同時D因爲在棧頂,在先執行完後,會彈出棧被釋放,因此彈出棧的順序爲:D->C->B->A
-
遞歸:爲什麼說遞歸也是棧的實現方式呢?因爲在遞歸的使用時如果未設置停止遞歸的條件就會造成棧溢出!因爲遞歸也是的調用自身就是一種函數調用棧,因此如果未停止,會一直調用自身,不會把函數彈出棧,不停的將函數壓入棧,最好造成棧溢出!(Stack OverFloat)
1.3.一道面試題理解棧結構
首先我們來分析題目:六個元素順序進棧,注意只是順序進棧,並沒有說是同時進入喲,可能有進有出,如果同時豈不是考的太簡單了?哈哈,是不是嘛,所有我們要根據答案來一一判斷。
- A:65進棧-5出棧-4進棧出棧-3進棧出棧-6出棧-21進棧(符合入棧順序654321)
- B:654進棧-4出棧-5出棧-3進棧出棧-2進棧出棧-1進棧出棧-6出棧(符合)
- C:6543進棧-3出棧-4出棧-6出棧(此處不符合,理論上不應該是6,6上面還有5未出棧)
- D:65432進棧-2出棧-3出棧-4出棧-1進棧出棧-5出棧-6出棧(符合)
綜上所述,答案是 C
二.棧結構實現
2.1.棧的封裝
首先我們先需瞭解棧常見的操作有哪些?
- push(element): 添加一個新元素到棧頂位置.
- pop():移除棧頂的元素,同時返回被移除的元素。
- peek():返回棧頂的元素,不對棧做任何修改(這個方法不會移除棧頂的元素,僅僅返回它)。
- isEmpty():如果棧裏沒有任何元素就返回true,否則返回false。
- clear():移除棧裏的所有元素。
- size():返回棧裏的元素個數。這個方法和數組的length屬性很類似。
封裝代碼如下:
// 封裝棧類
function Stack() {
// 棧中的屬性
this.items = []
// 棧的相關操作
// 1.將元素壓入棧
Stack.prototype.push = function (element) {
this.items.push(element)
}
// 2.從棧中取出元素
Stack.prototype.pop = function () {
return this.items.pop()
}
// 3.查看一下棧頂元素
Stack.prototype.peek = function () {
return this.items[this.items.length - 1]
}
// 4.判斷棧是否爲空
Stack.prototype.isEmpty = function () {
return this.items.length == 0
}
// 5.獲取棧中元素的個數
Stack.prototype.size = function () {
return this.items.length
}
// 6.toString方法
Stack.prototype.toString = function () {
// 形式自定 1 2 3 4 5
var resultString = ''
this.items.forEach((element) => {
resultString += element + ' '
})
return resultString
}
}
測試代碼:
// 棧的使用
var s = new Stack()
s.push(1)
s.push(2)
s.push(3)
s.push(4)
console.log(s.items) // [1,2,3,4]
s.pop()
console.log(s.items) // [1,2,3]
console.log(s.peek()) // 3
console.log(s.isEmpty()) // false
console.log(s.size()) // 3
console.log(s.toString()) // 1 2 3 (String)
2.2.棧結構的簡單應用(十進制轉二進制)
首先你必須要理解十進制轉二進制的方法,除以二取餘,一直除到結果爲0爲止。舉個例子吧,把10進制的數字10轉換爲二進制的數字,過程大概是如下流程:
結果就是1010,就是將餘數類似棧的方式依次取出來。
- 如果我們希望通過代碼來實現這個過程呢?
// 封裝十進制轉二進制的函數
function dec2bin(decNumber) {
// 1.定義棧對象,上文封裝的棧類
var stack = new Stack()
// 2.循環操作
while (decNumber > 0) {
// 2.1獲取餘數,並且放入棧中
stack.push(decNumber % 2)
// 2.2更新decNumber,獲取整除後的結果,作爲下一次運行的數字
decNumber = Math.floor(decNumber / 2)
}
// 3.從棧中取出0和1
let binaryString = ''
while (!stack.isEmpty()) {
binaryString += stack.pop()
}
return binaryString
}
測試代碼:
// 測試代碼
console.log(dec2bin(10)) //1010
console.log(dec2bin(100)) //1100100
三.總結
看完是否對棧結構有一個清晰的瞭解?記住後進先出(LIFO:last farst in out)!