第四章:javascript: 棧 第三章:javascript: 列表

列表是一種最天然的數據組織方式。上一章已經介紹如何使用List類將數據組織成一個列表。若是數據存儲的順序不重要。也沒必要對數據進行查找,那麼列表就是一種再好不過的數據結構。對於其它的一些應用,列表就顯得有些簡陋了。咱們須要某種和列表相似但更復雜的數據結構。javascript

棧就是和列表相似的一種數據結構,它能夠用來解決計算機世界裏不少的問題。棧是一種高效的數據結構,由於數據只能在棧頂添加或刪除,因此這樣的操做很快,並且容易實現。棧的使用遍及程序語言的方方面面,從表達式求值處處理函數調用html

一:對棧的操做java

棧是一種特殊列表,棧內的元素只能經過列表的一端訪問,這一端被稱爲棧頂。咖啡廳的一摞盤子是現實世界中最多見的棧的例子。只能從上面取盤子,盤子洗淨後,也只能摞在這一摞盤子的最上面。棧被稱爲一種後入先出(LIFO,last-in-first-out)的數據結構算法

因爲棧具備後入先出的特色,全部任何不在棧頂的元素都沒法訪問,爲了拿到棧底的元素,必選先拿掉上面的元素。如圖:編程

對於棧的兩種主要操做是將一個元素壓入棧和將一個元素彈出棧,入棧使用push()方法。出棧使用pop()方法。數組

另一個經常使用操做是預覽棧頂的元素。pop()方法雖然能夠訪問棧頂的元素,可是調用該方法後,棧頂的元素也從棧中永久的刪除了。peek()方法則只返回棧頂元素,而不刪除它。數據結構

爲了記錄棧頂元素的位置,同時也爲了標記哪裏能夠增長新的元素。咱們使用變量top,當向棧內壓入元素時,該變量增大,從棧內彈出元素時,該變量減少。編程語言


push(),pop()和peek()是棧的三個主要操做方法,可是棧還有其餘的方法和屬性。clear()方法清除棧內全部元素length屬性記錄棧內元素的個數。咱們還定義了一個empty屬性,用於表示棧內是否還有元素(使用length也能夠達到一樣的目的)。函數


二:棧的實現:post

實現一個棧,當務之急是決定存儲數據的底層數據結構。這裏採用的是數組。

咱們實現以Stack類的構造函數開始:

    function Stack() {
        this.dataStore = [];
        this.top = 0;
        this.push = push;
        this.pop = pop;
        this.peek = peek;
    }

咱們使用數組dataStore保存棧內元素,構造函數將其初始化爲一個空數組,變量top記錄棧頂的位置,被構造的函數初始化爲0,表示棧頂對於數組的起始位置爲0.若是有元素壓入棧,該變量的值隨之變化。

先來實現push()方法。當向棧內壓入一個新元素時,須要將其保存在數組中top所對應的位置,而後將top加1.讓其指向數組中的下一個空位置。

    function push (element) {
        this.dataStore[this.top++] = element;
    }

這裏特別要注意++操做符的位置,它放在this.top的後面,這樣新入棧的元素就被放在top的當前值對應的位置,而後再將top值加1.指向下一個位置

pop()方法剛好與push()方法相反,它返回棧頂元素,同時將變量top的值減1.

    function pop() {
        return this.dataStore[--this.top]
    }

peek()方法返回數組的第top-1個位置的元素,即棧頂元素

    function peek() {
        return this.dataStore[this.top - 1]
    }

若是對空數組調用peek()方法,結果爲undefined。這是由於棧是空的,棧頂沒有任何元素。

有時候須要知道棧內存儲了多個元素。length()方法經過返回變量top值返回棧內元素的個數;

    function length() {
        return this.top
    }

最後,能夠將top的值設置爲0,輕鬆清空一個棧。

    function clear() {
        this.top = 0;
    }

附:測試代碼

    function Stack() {
        this.dataStore = [];
        this.top = 0;
        this.push = push;
        this.pop = pop;
        this.peek = peek;
        this.clear = clear;
        this.length = length;
    }

    //壓入棧
    function push (element) {
        this.dataStore[this.top++] = element;
    }

    //彈出棧
    function pop() {
        return this.dataStore[--this.top]
    }

    //棧頂元素
    function peek() {    
        // if (this.dataStore[this.top - 1] == undefined) {
        //     return "none"
        // }
        return this.dataStore[this.top - 1]
    }

    //清空棧
    function clear() {
        this.top = 0;
    }

    //棧元素個數
    function length() {
        return this.top
    }

    var newstak = new Stack();
    newstak.push("牛牛")
    newstak.push("豆豆")
    newstak.push("花花")

    console.log(newstak.length())
    console.log(newstak.peek())

    var poped = newstak.pop();
    console.log(poped);//
    console.log(newstak.peek());//
    newstak.clear();

    console.log(newstak.length())
    console.log(newstak.peek());
    newstak.push("羊羊");
    console.log(newstak);
    console.log(newstak.peek());

三.使用Stack類 

有一些問題特別適合用棧來解決,先介紹幾個例子:

1.數制間互相轉換

能夠利用棧將一個數字從一種數值轉換成另外一種數制。假設想將數字n轉換爲以b爲基數的數字。實現轉換算法以下

  • 1.最高位爲 n % b ,將此位壓入棧
  • 2.使用n / b 代替n
  • 3.重複步驟1和2,直到n等於0,且沒有餘數。
  • 4.持續將棧內元素彈出,直到棧爲空。依次將這些元素排列,就獲得轉換後數字的字符串形式。
  • (此算法只徵對基數爲2-9的狀況)

使用棧,在javascript中實現該算法就很容易,下面就是該函數的定義,能夠將數字轉化爲二至九進制的數字。

    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;
    }

下面展現了若是使用該方法將數字轉換爲二進制和八進制數。
將數字轉換爲二進制和八進制。

    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);
    //32 converted to base 2 is 100000
    console.log(num + " converted to base " + base + " is " + newNum)

    num = 125;
    base = 8;

    var newNum = mulBase(num, base);

    //125 converted to base 8 is 175
    console.log(num + " converted to base " + base + " is " + newNum)

2.迴文


迴文是這樣一種現象:一個單詞,短語或數字,從前日後寫和日後寫都是同樣的。好比: 單詞"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 word = "";
        while(s.length() > 0) {
            rword += s.pop();
        }
        if (word == rword) {
            return true;
        }
        else {
            return false;
        }
    }

    var word = "hello";
    if (isPalindrome(word)) {
        console.log(word + " 是迴文的");
    } else {
        console.log(word + " 不是迴文的")
    }

    var word = "racecar";
    if (isPalindrome(word)) {
        console.log(word + " 是迴文的");
    } else {
        console.log(word + " 不是迴文的")
    }

三:遞歸演示;

棧經常使用來實現編程語言,使用棧實現遞歸即爲一例(這裏只用棧來模擬遞歸過程)。

爲了演示如何用棧實現遞歸,考慮如下求階乘的遞歸定義。首先看看5的階乘是如何定義的

5! = 5*4*3*2*1 = 120

下面是一個遞歸函數,能夠計算任何數字的階乘

function factorial(n) {
    if (n === 0) {
    return 1;
    } else {
    return n * factorial(n - 1)
    }
}


使用棧來模擬計算5的階乘,返回120

使用棧來模擬計算5!的過程,首先將數字從5到1壓入棧,而後使用一個循環,將數字彈出連乘,就獲得了5 的階乘

    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;
    }

 

 (本章完結

上一章:第三章:javascript: 列表 下一章第五章: 隊列

相關文章
相關標籤/搜索