在生活中也能發現不少棧的例子。例如,廚房裏堆放的盤子,老是疊在上方的先被使用;輸入框內容進行刪除時,老是最後輸入的先刪除;彈夾中的子彈,越後裝入的,越先發射......git
首先,建立一個類來表示棧github
function Stack () { }
複製代碼
咱們須要選擇一種數據結構來保存棧裏的元素,能夠選擇數組算法
function Stack(){
var items = []; //用來保存棧裏的元素
}
複製代碼
接下來,爲棧添加一些方法數組
push(element(s)); //添加新元素到棧頂
pop(); //移除棧頂的元素,同時返回被移除的元素
peek(); //返回棧頂的元素,不對棧作任何修改
isEmpty(); //若是棧裏沒有任何元素就返回true,不然false
clear(); //移除棧裏的全部元素
size(); //返回棧裏的元素個數,相似於數組的length屬性
複製代碼
咱們須要實現的第一個方法時push
。用來往棧裏添加新元素,有一點很重要:該方法只添加到棧頂,也就是棧的末尾。因此,能夠這樣寫:bash
this.push = function (element) {
items.push(element);
}
複製代碼
利用數組的push方法,就能夠實如今棧頂末尾添加新的元素了。數據結構
接着,來實現pop
方法,用來實現移除棧裏的元素。棧聽從LIFO(後進先出)原則。移出去的是最後添加進去的元素。所以,可使用數組的pop方法。ide
this.pop = function () {
return items.pop();
}
複製代碼
這樣一來,這個棧天然就聽從了LIFO原則函數
如今,再來爲這個棧添額外的輔助方法。測試
若是想知道棧裏最後添加的元素是什麼,能夠用peek
方法。這個方法將返回棧頂的元素this
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代碼完成了棧的模擬,而不是真正從底層去實現了棧。咱們的目的是更好的去理解棧的用法,而且經過進制轉換的例子來實際應用了它。棧的應用實例還有不少,好比平衡圓括號和漢諾塔。感興趣能夠自行百度去了解