棧就是和列表類似的一種資料結構, 它可以用來解決計算機世界裡的很多問題. 棧是一種高效的資料結構, 因為資料只能在棧頂新增或刪除, 所以這樣的操作很快, 而且容易實現. 棧的使用遍布程式語言的方方面面, 從表示式求值到處理函式呼叫.棧只能通過列表的一端訪問, 這一端稱為棧頂.
棧被稱為 先進後出 的資料結構與佇列相反.
由於棧具有先進後出的特點, 所以任何不在棧頂的元素都無法訪問. 為了得到棧底的元素, 必須拿掉上面的元素.
對棧的三種主要操作:
將乙個元素壓入棧 使用push()
.
將乙個元素彈出棧 使用pop()
.
預覽棧頂的元素peek()
.
這裡需要注意的是的第三種.pop()
方法雖然可訪問棧頂的元素, 但是呼叫該方法後, 棧頂元素也就從棧中被永久刪除.peek()
只返回棧頂元素, 而不刪除.
這三種為主要方法, 但是棧還有其他方法和屬性.clear()
清除棧內所有元素,length
屬性記錄棧內元素的個數. 我們還可以定義乙個empty
屬性, 用以表示棧內是否含有元素, 不過使用length
屬性也可以達到相同目的.
實現乙個棧, 首要條件是決定儲存資料的底層資料結構. 這裡採用陣列.
從定義stack
類的建構函式開始:
class stack
push(element)
pop(element)
peek()
length()
clear()
}
用陣列_datastore
儲存棧內元素, 建構函式將其初始化為乙個空陣列. 變數_top
記錄棧頂位置, 被建構函式初始化為0
, 表示棧頂對應陣列的其實位置0
. 如果有元素被壓入棧, 該變數將隨之變化.
push()
方法. 向棧中壓入乙個新元素時, 需要將其儲存在陣列中變數_top
所對應的位置, 然後將_top
加1
, 讓其指向陣列中下乙個空位置. 這裡要注意++
操作符的位置, 它放在變數後面, 新元素就會放在_top
當前值對應位置, 然後再加1
, 指向下乙個位置.
pop()
方法. 恰好與push()
方法相反. 有返回值, 返回棧頂元素. 這裡要注意--
操作符的位置, 它放在變數前面, 先對_top
減1
然後再刪除對應位置元素.
peek()
方法. 返回陣列的第_top - 1
個位置的元素, 即棧頂元素. 如果對空棧呼叫peek()
, 結果為undefined
.
length()
方法. 通過返回變數_top
值的方式返回棧內的元素個數.
clear()
方法. 將變數_top
設為0, 輕鬆清空乙個棧.
可以利用棧將乙個數字從一種數制轉化成另一種數制. 假設將數字n
轉化為以b
為基數的數字, 實現轉化的演算法如下.
最高位為n % b
, 將此位壓入棧.
使用n / b
代替n
.
重複步驟1和2, 直到n
等於0
, 且沒有餘數.
持續將棧內元素彈出, 直到棧為空, 依次將這些元素排列, 就得到轉換後數字的字串形式.
注意: 此演算法只針對基數為2~9
的情況.
function mulbase(num, base) while (num > 0);
var converted = '';
while(s.length() > 0) ;
return converted;
};console.log(mulbase(32, 2)); // 得到32的二進位制值: 100000
console.log(mulbase(88, 8)); // 得到88的八進位制值: 130
回文: 乙個單詞、短語和數字, 從前往後寫和從後往前寫都是一樣的. eg: 單詞"dad"、"racecar"就是回文; 忽略空格和標點下面這個句子也是回文: "a man, a plan, a canal: panama"; 數字101也是回文.
使用棧可以輕鬆判斷乙個字串是否是回文. 我們將拿到的字串的每乙個字元按從左至右的順序入棧. 當所有字元都入棧後, 棧內就儲存了乙個反轉後的字串, 最後的字元在棧頂, 第乙個字元在棧底.
字串完整壓入棧內後, 通過持續彈出棧中的每乙個字母就可以得到乙個新的字串, 該字串剛好與原來的字串順序相反. 我們只需要比較這兩個字串即可.
function ispalindrome(word) ;
let rword = '';
while(s.length() > 0) ;
return word === rword;
};console.log(ispalindrome('hello')); // false
console.log(ispalindrome('dad')); // true
棧常常被用來實現程式語言, 使用棧實現遞迴即為一例. 這裡只是用棧來模擬遞迴過程.
為了演示如何用棧實現遞迴, 考慮一下求階乘函式的遞迴定義. 首先看5
的階乘是怎麼定義的:5! = 5 * 4 * 3 * 2 * 1 = 120
下面是乙個遞迴函式, 可以計算任何數字的階乘:
function factorial(n) ;
// 尾掉優化
function factorial(n, total = 1) ;
console.log(factorial(5)); // 120
使用棧來模擬計算5!
的過程, 首先將數字從5到1入棧, 然後使用乙個迴圈, 將數字挨個彈出連乘, 就得到正確答案
下面使用棧模擬遞迴過程:
function fact(n) ;
let product = 1;
while(s.length() > 0) ;
return product;
};console.log(fact(5)); // 120
例如判斷表示式為2.3 + 23 / 12 + (3.14159 * 0.24
的算數表示式的括號是否匹配.
function fn(express) else if (express[i] === `)`)
};console.log(`在第$個字元是不匹配的括號`)
};fn('2.3 + 23 / 12 + (3.14159 * 0.24'); // 在第16個字元是不匹配的括號
表示式詳解
乙個算數表示式的字尾表達形式如下:
op1 op2 operator
使用兩個棧, 乙個用來儲存運算元, 另乙個用來儲存操作符, 設計並實現乙個函式, 該函式可以將中綴表示式轉換為字尾表示式, 利用棧堆該表示式求值.
const express = '1+((2+3)*4)-5';
function fn(express) else if(['+', '-', '*', '/'].includes(i)) else if (['*', '/'].includes(i) && ['+', '-'].includes(s1.peek())) else
}} else if (i === '(') else if (i === ')')
s1.pop();
}});
while(s1.length() > 0) ;
let str = ''
while(s2.length() > 0) `;
};return str;
};console.log(fn(express))
現實生活中的例子是佩茲糖果盒. 想象一下你有一盒佩茲糖果, 裡面塞滿了紅色、黃色和白色的糖果, 但是你不喜歡黃色的糖果. 使用棧(有可能用到多個棧) 寫一段程式, 在不改變盒內其它糖果疊放順序的基礎上, 將黃色糖果移除.
const boxs = new stack();
boxs.push('red');
boxs.push('yellow');
boxs.push('white');
boxs.push('white');
boxs.push('yellow');
boxs.push('yellow');
boxs.push('red');
boxs.push('red');
boxs.push('white');
boxs.push('yellow');
boxs.push('red');
function changefn(sourcestack) else
};while(s2.length() > 0) ;
return results;
};changefn(boxs);
資料結構 棧 棧
可以把棧想像成乙個桶 進棧 就是把和桶口一樣大的燒餅往桶裡面扔 出棧 就是把燒餅拿出來 特點 先進後出。先扔進去的燒餅最後才能拿出來,最後扔進去的燒餅,第乙個拿出來 剛開始top 1 top 1 然後把進棧的元素賦值給data top 入棧操作 void push stack s,int x els...
資料結構 棧
例子 棧是一種被限制在只能在表的一端進行插入和刪除運算的線性表。區域性變數是用棧來儲存的 可以進行插入和刪除的一端稱為 棧頂 top 另一端稱為 棧底 bottom 當表中沒有元素時 表長為0的棧 稱為 空棧。棧的修改是按 後進先出的原則進行,因此棧被稱為後進先出 last in first out...
資料結構 棧
1.棧stack 是限定僅在表尾進行刪除和插入操作的線性表。允許插入刪除的一端叫做棧頂top,另外一端叫做棧底bottom。棧又稱為後進先出 lifo 的線性表。即表尾是指棧頂。2.順序棧 定義 top指向可存入元素的位置。typedef struct stacktypestacktype 插入 進...