學習JavaScript數據結構與算法(棧)

1.棧數據結構

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

現實生活中典型的棧的例子就是一摞書或者餐廳裏疊放的盤子。算法

1.1 建立一個基於數組的棧

建立一個類來表示棧。數組

class Stack {
    constructor() {
        this.items = [];
    }
}
複製代碼

1.2 向棧添加元素

實現方法push,添加一個(或幾個)新元素到棧頂。bash

push(element) {
    this.items.push(element);
}
複製代碼

1.3 從棧移除元素

實現方法pop,移除棧頂的元素,同時返回被移除的元素。數據結構

pop() {
    return this.items.pop();
}
複製代碼

1.4 查看棧頂元素

實現方法peek,返回棧頂的元素,不對棧作任何修改。學習

peek() {
    return this.items[this.items.length -1];
}
複製代碼

1.5 檢查棧是否爲空

實現方法isEmpty,若是棧裏沒有任何元素就返回true,不然返回false。ui

isEmpty() {
    return this.items.length === 0;
}
複製代碼

1.6 清空棧元素

實現方法clear,移除棧裏的全部元素。this

clear() {
    this.items = [];
}
複製代碼

1.7 返回棧元素個數

實現方法size,返回棧裏的元素個數。該方法和數組的length屬性很相似。spa

size() {
    return this.items.length;
}
複製代碼

1.8 完整的Stack類

class Stack {
    constructor() {
        this.items = [];
    }
    push(element) {
        this.items.push(element);
    }
    pop() {
        return this.items.pop();
    }
    peek() {
        return this.items[this.items.length -1];
    }
    isEmpty() {
        return this.items.length === 0;
    }
    clear() {
        this.items = [];
    }
    size() {
        return this.items.length;
    }
}
複製代碼

1.9 使用Stack類

首先初始化Stack類,而後驗證一下棧是否爲空。code

const stack = new Stack();
console.log(stack.isEmpty()); // 輸出爲true
複製代碼

往棧裏添加元素5,8

stack.push(5);
stack.push(8);
複製代碼

調用peek方法

console.log(stack.peek()); // 8
複製代碼

再添加一個元素

stack.push(11);
console.log(stack.size()); // 3
console.log(stack.isEmpty()); // false
複製代碼

最後,再添加一個元素

stack.push(15);
console.log(stack.size()); // 4
複製代碼

而後,調用兩次pop方法從棧裏移除兩個元素。

stack.pop();
stack.pop();
console.log(stack.size()); // 2
複製代碼

2.建立一個基於JavaScript對象的Stack類

建立一個Stack類最簡單的方式是使用一個數組來存儲其元素。在處理大量數據的時候,咱們須要評估如何操做數據最高效。在使用數組時,大部分方法的時間複雜度是O(n),另外,數組是元素的一個有序集合,爲了保證元素排列有序,它會佔用更多的內存空間。

爲了解決上述問題,咱們能夠使用一個JavaScript對象來存儲全部的棧元素,保證它們的順序而且遵循LIFO原則。

首先聲明一個Stack類。

class Stack {
    constructor() {
        this.count = 0;
        this.items = {};
    }
}
複製代碼

2.1 向棧中插入元素

push(element) {
    this.items[this.count] = element;
    this.count++;
}
複製代碼

2.2 驗證一個棧是否爲空和它的大小

size() {
    return this.count
}
isEmpty() {
    return this.count === 0;
}
複製代碼

2.3 從棧中彈出元素

pop() {
    if(this.isEmpty()) {
        return undefined;
    }
    this.count--;
    const result = this.items[this.count];
    delete this.items[this.count];
    return result;
}
複製代碼

2.4 查看棧頂的值並將棧清空

peek() {
    if(this.isEmpty()) {
        return undefined;
    }
    return this.items[this.count -1]
}
clear() {
    this.items = {};
    this.count = 0;
}
複製代碼

2.5 建立toString方法

toString() {
    if(this.isEmpty()) {
        return ''
    }
    let objString = `${this.items[0]}`;
    for(let i = 1; i < this.count; i++) {
        objString = `${objString},${this.items[i]}`
    }
    return objString;
}
複製代碼

3.用棧解決問題

從十進制到二進制

十進制轉化成二進制,能夠將十進制數除以2(二進制是滿二進一)並對商取整,直到結果是0爲止。

function decimalToBinary(decNumber) {
    const remStack = new Stack();
    let number = decNumber;
    let rem;
    let binaryString = '';
    while(number > 0) {
        rem = Math.floor(number % 2);
        remStack.push(rem);
        number = Math.floor(number / 2);
    }
    while(!remStack.isEmpty()) {
        binaryString += remStack.pop().toString();
    }
    return binaryString;
}

console.log(decimalToBinary(233));
console.log(decimalToBinary(10));
console.log(decimalToBinary(1000));
複製代碼

進制轉換算法

咱們能夠修改上述算法,使之能把十進制轉換成基數爲2~36的任意進制。

function baseConverter(decNumber, base) {
    const remStack = new Stack();
    const digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    let number = decNumber;
    let rem;
    let baseString = '';
    if(!(base >=2 && base <= 36)) {
        return '';
    }
    while(number > 0) {
        rem = Math.floor(number % base);
        remStack.push(rem);
        number = Math.floor(number / base);
    }
    while(!remStack.isEmpty()) {
        baseString += digits[remStack.pop()];
    }
    return baseString;
}

console.log(baseConverter(100345,2)); 
console.log(baseConverter(100345,8)); 
console.log(baseConverter(100345,16)); 
console.log(baseConverter(100345,35)); 
複製代碼

5.小結

本節學習了棧這一數據結構的相關知識。使用數組和JavaScript對象實現了棧,還涉及瞭如何用push和pop往棧裏添加和移除元素。

6.經典題目

平衡圓括號

給定一個只包括 '(',')','{','}','[',']'的字符串,判斷字符串是否有效。 有效字符串需知足: 左括號必須用相同類型的右括號閉合。 左括號必須以正確的順序閉合。 注意空字符串可被認爲是有效字符串。

思路:當遇到右邊的括號時,入棧,當遇到左邊的括號時,判斷棧頂是否與左邊的括號匹配,若是不是的話,直接返回false,若是是進行下一次判斷,循環結束,若是棧爲空,則返回true,若是不爲空,則返回false。

function(s) {
    const item = [];
    const opens = '([{';
    const closers = ')]}';
    let index = 0;
    let symbol;
    let top;

    while (index < s.length) {
        symbol = s[index];
        if (opens.indexOf(symbol) >= 0) {
            item.push(symbol);
        }  else {
            top = item.pop();
            if (!(opens.indexOf(top) === closers.indexOf(symbol))) {
                return false;
            }
        }
        index++;
    }
    return item.length === 0;
};
複製代碼
相關文章
相關標籤/搜索