在生活中也能發現不少棧的例子。例如,廚房裏堆放的盤子,老是疊在上方的先被使用;輸入框內容進行刪除時,老是最後輸入的先刪除;彈夾中的子彈,越後裝入的,越先發射......git
首先,建立一個類來表示棧github
function Stack () { }
咱們須要選擇一種數據結構來保存棧裏的元素,能夠選擇數組算法
function Stack(){ var items = []; //用來保存棧裏的元素 }
接下來,爲棧添加一些方法數組
push(element(s)); //添加新元素到棧頂 pop(); //移除棧頂的元素,同時返回被移除的元素 peek(); //返回棧頂的元素,不對棧作任何修改 isEmpty(); //若是棧裏沒有任何元素就返回true,不然false clear(); //移除棧裏的全部元素 size(); //返回棧裏的元素個數,相似於數組的length屬性
咱們須要實現的第一個方法時push
。用來往棧裏添加新元素,有一點很重要:該方法只添加到棧頂,也就是棧的末尾。因此,能夠這樣寫:數據結構
this.push = function (element) { items.push(element); }
利用數組的push方法,就能夠實如今棧頂末尾添加新的元素了。ide
接着,來實現pop
方法,用來實現移除棧裏的元素。棧聽從LIFO(後進先出)原則。移出去的是最後添加進去的元素。所以,可使用數組的pop方法。函數
this.pop = function () { return items.pop(); }
這樣一來,這個棧天然就聽從了LIFO原則測試
如今,再來爲這個棧添額外的輔助方法。this
若是想知道棧裏最後添加的元素是什麼,能夠用peek
方法。這個方法將返回棧頂的元素spa
this.peek = function () { return items[items.length-1]; }
由於類內部是用數組保存元素的,因此這裏訪問數組最後一個元素用length-1
下一個要實現的方法是isEmpty
,若是棧爲空的話,就返回true,不然返回false:
this.isEmpty = function () { return items.length == 0; }
使用isEmpty方法,就能簡單地判斷棧內部是否爲空。
相似於數組地length屬性,咱們也能夠實現棧地length。
this.size = function () { return items.length; }
由於棧地內部使用數組保存元素,因此數組地length就是棧的長度。
實現clear
方法,clear方法用來清空棧中全部的元素。最簡單的實現方法是:
this.clear = function () { items = []; }
其實屢次調用pop方法也能夠,可是沒有這個方法來的簡單快捷。
最後,爲了檢查棧裏的內容,還須要實現一個輔助方法:print
。它會把棧裏的元素都輸出到控制檯:
this.print = function () { console.log(items.toString()); }
至此,咱們就完整地建立了一個棧!
function Stack(){ var items = []; //用來保存棧裏的元素 this.push = function (element) { items.push(element); } this.pop = function () { return items.pop(); } this.peek = function () { return items[items.length-1]; } this.isEmpty = function () { return items.length == 0; } this.size = function () { return items.length; } this.clear = function () { items = []; } this.print = function () { console.log(items.toString()); } }
棧已經建立好了,咱們來測試一下
首先,來初始化Stack類。而後,驗證一下棧是否爲空
var stack = new Stack(); console.log(stack.isEmpty()); //控制檯輸出true
接下來,往棧裏面添加一下元素:
stack.push(5); stack.push(8);
若是調用peek方法,很顯然將會輸出8,由於它是棧頂的元素:
console.log(stack.peek()); //控制檯輸出8
再添加一個元素:
stack.push(11); console.log(stack.size()); //控制檯輸出3
咱們往棧裏又添加了11。若是調用size方法,輸出爲3,由於棧裏有三個元素(5,8和11)。若是這時候調用isEmpty方法,會看到輸出了false(由於此時棧不爲空)。最後,再來往裏面添加一個元素:
stack.push(15);
而後,調用兩次pop方法從棧裏移除兩個元素:
stack.pop(); stack.pop(); console.log(stack.size()); //控制檯輸出2 stack.print(); //控制檯輸出[5,8]
到這裏,整個棧的功能測試完成。
使用棧來完成進制轉換。
現實生活中,咱們主要用10進制,但在計算科學中,二進制很是重要,由於計算機裏全部的內容都是用二進制數字0和1來表示的。大學的計算機課都會先教進制轉換。以二進制爲例:
function divideBy2 (decNumber) { var remStack = new Stack(), rem, binaryString = ''; while (decNumber>0) { //{1} rem = Math.floor(decNumber % 2); //{2} remStack.push(rem); //{3} decNumber = Math.floor(decNumber / 2); //{4} } while (!remStack.isEmpty()) { //{5} binaryString += remStack.pop().toString(); } return binaryString; }
這段代碼裏,當結果知足和2作整除的條件時,(行{1}),咱們會得到當前結果和2的餘數,放到棧裏(行{2}、{3})。而後讓結果和2作整除(行{4})
注:JavaScript有數字類型,可是它不會區分時整數仍是浮點數。所以,要使用Math.floor函數讓除法的操做僅返回整數部分。
最後,用pop方法把棧中的元素都移除,把出棧的元素鏈接成字符串(行{5})。
測試一下:
console.log(divideBy2(520)); //輸出1000001000 console.log(divideBy2(10)); //輸出1010 console.log(divideBy2(1000)); //輸出1111101000
接下來,能夠很容易的修改上面的算法,使它可以把十進制轉化爲任何進制。除了讓十進制數字和2整除轉成二進制數,還能夠傳入其餘任意進制的基數做爲參數,就像下面的算法這樣:
function baseConverter (decNumber, base) { var remStack = new Stack(), rem, baseString = ''; digits = '0123456789ABCDEF'; //{6} while (decNumber>0) { rem = Math.floor(decNumber % base); remStack.push(rem); //{3} decNumber = Math.floor(decNumber / base); } while (!remStack.isEmpty()) { baseString += digits[remStack.pop()]; //{7} } return baseString; }
在將十進制轉成二進制時,餘數是0或1;在將十進制轉成八進制時,餘數時0-8之間的數;可是將十進制轉成十六進制時,餘數時0-9之間的數字加上A、B、C、D、E、F(對應十、十一、十二、1三、14和15)。所以,須要對棧中的數字作個轉化才能夠(行{6}、{7})。
來測試一下輸出結果:
console.log(baseConverter(1231,2)); //輸出10011001111 console.log(baseConverter(1231,8)); //輸出2317 console.log(baseConverter(1231,16)); //輸出4CF
顯然是正確的。
咱們用js代碼本身實現了棧。而且經過進制轉換的例子來實際應用了它。棧的應用實例還有不少,好比平衡圓括號和漢諾塔。感興趣能夠自行百度去了解