如何用JavaScript手動實現一個棧

什麼是棧(Stack)

  • 棧是一種聽從後進先出(LIFO)原則的有序集合。
  • 新添加的或待刪除的元素都保存在棧的末尾,稱爲棧頂,另外一端叫棧底。
  • 在棧裏,新元素都靠近棧頂,舊元素都接近棧底

現實中的例子

在生活中也能發現不少棧的例子。例如,廚房裏堆放的盤子,老是疊在上方的先被使用;輸入框內容進行刪除時,老是最後輸入的先刪除;彈夾中的子彈,越後裝入的,越先發射......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類

棧已經建立好了,咱們來測試一下

首先,來初始化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代碼完成了棧的模擬,而不是真正從底層去實現了棧。咱們的目的是更好的去理解棧的用法,而且經過進制轉換的例子來實際應用了它。棧的應用實例還有不少,好比平衡圓括號漢諾塔。感興趣能夠自行百度去了解

原文連接:行無忌的成長小屋:如何用JavaScript手動實現一個棧

相關文章
相關標籤/搜索