天天看點

如何用JavaScript手動實作一個棧什麼是棧(Stack)現實中的例子手動實作一個棧棧的完整代碼使用Stack類用棧來解決問題小結

什麼是棧(Stack)

如何用JavaScript手動實作一個棧什麼是棧(Stack)現實中的例子手動實作一個棧棧的完整代碼使用Stack類用棧來解決問題小結
  • 棧是一種遵從後進先出(LIFO)原則的有序集合。
  • 新添加的或待删除的元素都儲存在棧的末尾,稱為棧頂,另一端叫棧底。
  • 在棧裡,新元素都靠近棧頂,舊元素都接近棧底

現實中的例子

在生活中也能發現很多棧的例子。例如,廚房裡堆放的盤子,總是疊在上方的先被使用;輸入框内容進行删除時,總是最後輸入的先删除;彈夾中的子彈,越後裝入的,越先發射......

手動實作一個棧

首先,建立一個類來表示棧

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方法,就可以實作在棧頂末尾添加新的元素了。

接着,來實作

pop

方法,用來實作移除棧裡的元素。棧遵從LIFO(後進先出)原則。移出去的是最後添加進去的元素。是以,可以使用數組的pop方法。

this.pop = function () {
    return items.pop();
}           

這樣一來,這個棧自然就遵從了LIFO原則

現在,再來為這個棧添額外的輔助方法。

如果想知道棧裡最後添加的元素是什麼,可以用

peek

方法。這個方法将傳回棧頂的元素

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來表示的。大學的計算機課都會先教進制轉換。以二進制為例:

如何用JavaScript手動實作一個棧什麼是棧(Stack)現實中的例子手動實作一個棧棧的完整代碼使用Stack類用棧來解決問題小結
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(對應10、11、12、13、14和15)。是以,需要對棧中的數字做個轉化才可以(行{6}、{7})。

來測試一下輸出結果:

console.log(baseConverter(1231,2));      //輸出10011001111
console.log(baseConverter(1231,8));      //輸出2317
console.log(baseConverter(1231,16));     //輸出4CF
           

顯然是正确的。

小結

我們用js代碼自己實作了棧。并且通過進制轉換的例子來實際應用了它。棧的應用執行個體還有很多,比如

平衡圓括号

漢諾塔

。感興趣可以自行百度去了解

原文連結:

行無忌的成長小屋:如何用JavaScript手動實作一個棧

原文釋出時間為:2018年05月26日

原文作者:行無忌

本文來源: 

掘金 https://juejin.im/entry/5b3a29f95188256228041f46

如需轉載請聯系原作者

繼續閱讀