1.棧的定義
棧是一種和列表類似的數據結構,可以用它來解決很多的編程問題,棧是一種高效的數據結構,因為數據只能在棧的頂端添加或者刪除,所以這樣的操作很快而且容易實現。
棧是一種特殊的列表,站內的元素只能拖過列表的一端進行訪問,這一端陳偉棧頂。一疊盤子是最常見的棧結構,只能從頂部取盤子,洗好的盤子也只能放在頂端。棧被稱為后入先出的數據結構。
由於棧具有后入先出的特點,所以任何不在棧頂的元素都無法訪問。為了得到棧底的元素,必須拿掉上面的元素。
對棧的操作有將一個元素壓入棧和將一個元素彈出棧。把元素壓入棧頂使用push()方法,從棧頂彈出元素使用pop()方法。還有一個方法是預覽棧頂元素,使用pop()方法雖然可以訪問棧頂的元素,但是調用該方法后棧頂的元素將被永久的刪除。peek()方法只返回棧頂的元素,而不刪除它。
為了記錄棧頂元素的位置,同時也為了標記從哪里可以加入新元素,我們使用變量top,當向棧內壓入元素是該變量增大,從站內彈出元素時,該變量減小。
pop(),push(),peek()方法是最主要的三個方法,同時定義clear()方法可以清楚棧內所有的元素,length屬性定義棧內元素的個數,同時定義一個empty屬性標識棧內是否還有元素,不過使用length屬性可以達到同樣的目的。
棧結構的代碼如下:
//使用數組dataStore保存站內元素,構造函數將其初始化為一個空數組。 //變量top定義棧頂的位置,構造時初始化為0,表示棧的起始位置為0 function Stack(){ this.dataStore = []; this.top = 0; this.push = push; this.pop = pop; this.peek = peek; this.clear = clear; this.length = length; //注意++操作符的位置,它放在this.top的后面,這樣新入棧的元素就被放在top的當前位置對應的位置,同時top自加1,指向下一個位置 function push(element){ this.dataStore[this.top++] = element; } //返回棧頂元素,同時top的位置減1 function pop(){ return this.dataStore[--this.top]; } //peek()方法返回數組的第top-1個位置的元素,即棧頂元素 function peek(){ return this.dataStore[this.top-1]; } //將top的值設置0,即清空一個棧 function clear(){ this.top = 0; } //返回變量top的值即為棧內元素的個數 function length(){ return this.top; } }
使用下面的代碼來檢驗棧結構
var s = new Stack(); s.push("David"); s.push("Baymond"); s.push("Bryan"); document.writeln("length:" + s.length()); document.writeln(s.peek()); var popped = s.pop(); document.writeln("the popped element is:" + popped); document.writeln(s.peek()); s.push("Cynthia"); document.writeln(s.peek()); s.clear(); document.writeln("length:" + s.length()); document.writeln(s.peek()); s.push("Clayton"); document.writeln(s.peek());
輸出如下:
length:3
Bryan
the popped element is:Bryan
Baymond
Cynthia
length:0
undefined
Clayton
2.用棧實現進制轉換
可以使用棧將一個數字從一種數制轉換成另一種數制,假設想將數字n轉換為以b為基數的數字,實現方法如下:
(1)最高位為n%b,將此位壓入棧
(2)使用n/b代替n
(3)重復(1),(2)直到n等於0,且沒有余數
(4)持續將站內元素彈出,直達棧為空,依次將這些元素排列,就得到轉換后的數字的字符串形式
來看下面的代碼,如何將數字轉換為2進制和8進制
function mulBase(num,base){ var s = new Stack(); do{ s.push(num % base); num = Math.floor( num /= base ); }while(num>0); var converted = ""; while (s.length()>0){ converted += s.pop(); } return converted; } var num = 32; var base = 2; var newNum = mulBase(num, base); document.writeln(num + " converted to base " + base + " is " + newNum); num = 125; base = 8; newNum = mulBase(num, base); document.writeln(num + " converted to base " + base + " is " + newNum);
最后輸出的結果如下:
32 converted to base 2 is 100000 125 converted to base 8 is 175
3.用棧判斷回文
回文是這樣一種現象:一個單詞,短語或者數字,從前往后和從后往前寫都是一樣的。比如單詞“dad”,“racecar”就是回文;如果忽略空格和標點符號,下面這個句子也是回文,“A man, a plan, a canal: Panama”,數字1001也是回文。
使用棧可以輕松的判斷一個字符是否是回文。我們將拿到的字符串的每個字符按照從左至右的順序入棧,當所有字符都入棧之后站內就保存了一個反轉后的字符串,最后的字符在棧頂,第一個在棧尾。字符串完全壓入站內后,通過持續彈出棧中的每個字母就可以的大一個新的字符串,該字符串剛好與原來的字符串順序相反。我們只要比較這兩個字符串即可,如果他們相等就說明這個是一個回文。代碼如下:
function isPalindrome(word){ var s = new Stack(); for (var i=0; i<word.length; ++i) { s.push(word[i]); } var reword = ""; while(s.length()>0){ reword += s.pop(); } if(word == reword){ return true; }else{ return false; } } var word = "hello"; if(isPalindrome(word)){ document.writeln(word + " is a palindrome."); }else{ document.writeln(word + " is not a palindrome"); } word = "racecar"; if(isPalindrome(word)){ document.writeln(word + " is a palindrome."); }else{ document.writeln(word + " is not a palindrome"); }
輸出結果如下:
hello is not a palindrome
racecar is a palindrome.
4.用棧實現遞歸
遞歸是一種很常見的算法,使用棧來實現遞歸是一件很輕松的事情,例如計算階乘可以使用遞歸算法,如下:
function factorial(n) { if (n === 0) { return 1; } else { return n * factorial(n-1); } }
使用棧來模擬階乘過程,例如:首先將5到1壓入棧內,然后使用給一個循環,將數字一次彈出連乘就得到正確的答案,代碼如下:
function fact(n){ var s = new Stack(); while (n>1){ s.push(n--); } var product = 1; while (s.length()>0){ product *= s.pop(); } return product; } document.writeln(fact(5));
結果如下:
120
5.使用棧判斷表達式中的括號是否完整
表達式中的{和},(和),[和]必須是匹配的,不然的話表達式就會出現語法錯誤,使用棧可以判斷表達式中的括號是否左右匹配。思路是遇到左括號就入棧,遇到右括號就和當前棧頂元素匹配,如果匹配成功就將棧頂元素出棧,最后判斷棧中元素個數,如果是0就代表是完整的,否則就是不完整的。代碼如下:
function isMatch(str){ var left = "({["; var right = ")}]"; var s = new Stack(); var i = 0; while (str[i]){ //左符號入棧 if(left.indexOf(str[i])>-1){ s.push(str[i]) } //遇到右括號 else if( right.indexOf(str[i])>-1 && right.indexOf( str[i] ) == left.indexOf( s.peek()) ){ s.pop(); } i++ } // document.writeln( s.peek() ); if(s.length() == 0){ document.writeln(str + " is match success"); }else{ document.writeln(str + " is not match"); } } isMatch("2.3 + {23 / 12 + (3.14159×0.24)");