JS數據結構第四篇 --- 棧

1、什麼是數據結構棧html

  在數據結構中有一個棧結構,在內存空間中也有一個棧空間,這兩個」棧「是兩個不一樣的概念。這篇咱們說的是數據結構中的棧。棧是一種特殊的線性表,特殊性體如今只能在棧頂進行操做,往棧頂添加元素,通常叫push, 入棧;從棧頂移除元素,通常叫pop, 出棧,操做如圖:git

  

這個特徵叫」後進先出「,Last  In  First  On, 簡稱LIFO。和JS數組中的push和pop函數功能有點像。固然棧的內部設計,就能夠用數組,或者也能夠用鏈表github

 

2、棧結構設計和應用示例數組

2.1 內部實現:數據結構

棧結構對外暴露的方法有入棧(push)、出棧(pop)、獲取棧頂元素(top)、獲取棧長度(length)、清空棧內元素。如圖:ide

這裏貼出內部用數組實現的棧設計構造函數,鏈表實現見Github函數

/**
 * 數據結構棧:先進後出,後進先出,即LIFO,棧的內部實現能夠用數組,也能夠用鏈表;
 * 這裏先用數組實現,對外暴露的方法有:
 * push(element): 放入一個元素,即入棧
 * pop()       :  移除棧頂元素,即出棧
 * top()       : 獲取棧頂元素
 * clear()     : 移除全部棧元素
 * length()    : 獲取棧長度
 */
const Stack = function(){
    let arr = []; //內部數組

    //入棧方法
    function push(element){
        arr.push(element);
    }
    //出棧方法
    function pop(){
        return arr.pop();
    }
    //獲取棧頂元素
    function top(){
        return arr.length > 0 ? arr[arr.length-1]:null;
    }
    //移除全部棧元素
    function clear(){
        arr = [];
    }
    //獲取棧長度
    function length(){
        return arr.length;
    }

    this.push = push;
    this.pop = pop;
    this.top = top;
    this.clear = clear;
    this.length = length;

}
View Code

 

2.2 在這個棧構造函數的基礎上,作幾題目應用實踐一下測試

2.2.1 用棧實現將十進制數字轉成二進制,和八進制this

/**
 * 十進制轉成二進制或八進制
 * @param num 十進制數字
 * @param base =2表示轉成二進制,=8表示轉成八進制
 */
function numChange(num, base){
    var stack = new Stack();
    do {
        stack.push(num%base);
        num = Math.floor(num/base);
    }while(num > 0)

    let str = '';
    while(stack.length()>0){
        str += stack.pop();
    }
    return str;
}

console.log(numChange(8, 2));
console.log(numChange(9, 2));
console.log(numChange(10, 2));
console.log(numChange(8, 8));
console.log(numChange(17, 8));
console.log(numChange(35, 8));
View Code

 

2.2.2 用棧來判斷一個字符串是否迴文。好比"abc"不是迴文,"abcba"是迴文,"abccba"是迴文spa

//測試3,判斷一個字符串是否迴文
function isCircle(s){
    let stack = new Stack();
    for(let i = 0; i < s.length; i++){
        stack.push(s[i]);
    }
    let newStr = '';
    while(stack.length() > 0){
        newStr += stack.pop();
    }

    return newStr == s;
}
console.log("\n\n判斷一個字符串是否迴文....");
console.log(isCircle("abc"));
console.log(isCircle("abcdcba"));
console.log(isCircle("helloolleh"));
View Code

 

3、力扣棧結構應用題目

3.1 有效的括號_第20題

/**
 * @param {string} s
 * @return {boolean}
 */
var isValid = function(s) {

    /**
     * 執行用時 :68 ms, 在全部 JavaScript 提交中擊敗了98.63%的用戶
     * 內存消耗 :33.7 MB, 在全部 JavaScript 提交中擊敗了76.56%的用戶
     */
    let arr = [], temp = top = null;
    for (let i = 0; i < s.length; i++){
        temp = s[i];

        //碰到左括號,入棧
        if (temp == '(' || temp == '[' || temp == '{'){
            arr.push(temp);
        }
        //碰到右括號,出棧
        else{
            if (arr.length < 1) return false;

            top = arr[arr.length-1];

            if ((temp == ')' && top == '(')||
                (temp == ']' && top == '[')||
                (temp == '}' && top == '{')){
                arr.pop();
            }
            else{
                return false;
            }
        }
    }
    return arr.length > 0 ? false : true;
};
View Code

 

3.2 根據括號計算分數_第856題

/**
 * @param {string} S
 * @return {number}
 * 執行用時 :80 ms, 在全部 JavaScript 提交中擊敗了62.96%的用戶
 * 內存消耗 :33.7 MB, 在全部 JavaScript 提交中擊敗了33.33%的用戶
 */
var scoreOfParentheses = function(S) {
    let arr = [], temp = null;
    for (let i = 0; i < S.length; i++){
        temp = S[i];

        if (temp == '('){
            arr.push(temp);
        }
        else{
            if (arr.length < 1) return 0;

            //調整棧,找到數組裏面配套的左括號,若是目標左括號在棧頂,調整"("爲1;
            // 若是目標左括號不在棧頂,則從棧頂到目標左括號累加,每累加一次,出棧一次;
            // 一直到目標左括號成爲棧頂,這事根據規則(A)=2*A,則目標左括號位置的值爲2*累加分
            // 好比:()()((()(()())())()())
            //      [1,1,(,(,1,4,1
            findTarget(arr);
        }
    }
    return findTarget(arr);
};

//尋找匹配左括號, 倒序找到第一個匹配的"(",而後調整目標位置的值
function findTarget(arr){
    let score = 0;
    for (let i = arr.length-1; i >= 0; i--){
        if (arr[i] == '('){
            arr[i] = score > 0 ? 2*score : 1;
            return 0;
        }
        else{
            score += arr.pop();
        }
    }
    return score;
}
View Code

 

3.3 逆波蘭式求值_第150題

咱們普通的運算式叫中綴表達式,後綴表達式是把運算符號寫在數字後面,前綴表達式是把運算符號寫在數字前面。好比

中綴表達式:a+b, 用後綴表達式爲:ab+, 用前綴表達式爲:+ab ;

中綴表達式:(a + b) * c - d/e, 用後綴表達式爲:ab+c*de/-,  前綴表達式爲:-*+abc/de

中綴表達式方便人類識別,後綴表達式是爲了方便計算機識別,後綴表達式也叫逆波蘭式;前綴表達式也叫波蘭式

 

/**
 * @param {string[]} tokens
 * @return {number}
 * 執行用時 :92 ms, 在全部 JavaScript 提交中擊敗了91.72%的用戶
 * 內存消耗 :37.2 MB, 在全部 JavaScript 提交中擊敗了40.48%的用戶
 */
var evalRPN = function(tokens) {
    //用棧來實現,碰到數字入棧,碰到運算符號,出棧計算
    let arr = [], str = null;
    for (let i =0; i < tokens.length; i++){
        str = tokens[i];

        if (str == "+" || str == "-" || str == "*" || str == "/"){
            let num2 = parseInt(arr.pop()), num1 = parseInt(arr.pop()), res = 0;
            if (str == "+"){
                res = num1 + num2;
            }
            else if(str == "-"){
                res = num1 - num2;
            }
            else if(str == "*"){
                res = num1 * num2;
            }
            else if(str == "/"){
                res = parseInt(num1 / num2);
            }
            arr.push(res);
        }
        else{
            arr.push(str);
        }
    }
    return arr.length ? arr.pop() : 0;
};
View Code

 

3.4 基本計算器_第224題(困難)

/**
 * 按順序計算,存儲左括號前面的運算符,碰到「-」號,後面匹配的數字爲相反數。至關於去括號計算
 * @param s
 * @return {number}
 * 執行用時 :112 ms, 在全部 JavaScript 提交中擊敗了88.14%的用戶
 * 內存消耗 :36.8 MB, 在全部 JavaScript 提交中擊敗了94.12%的用戶
 */
var calculate = function(s){
    let arr = [], sum = 0, num = 0, flag = 1;
    s = "+" + s; //前面加一個+號

    for (let i = 0; i < s.length; i++){

        if (s[i] == '+' || s[i] == '-'){ //+-後面可能爲數字/空格/左括號
            temp = s[i];
            let need_up = false;
            while(s[i+1] < '0' || s[i+1] > '9'){
                if (s[i+1] == '('){  //將左括號前面的符號壓入棧。一個左括號匹配一個+-號
                    need_up = true;
                    arr.push(temp);
                }
                i++;
            }

            //+-號後面的數字,或者+-號後面口號裏面的數字
            while(s[i+1] >= '0' && s[i+1] <= '9'){
                num = num*10 + (s[i+1] - '0'); //拼接完整數字
                i++;
            }

            if (temp == '+'){
                sum += flag * num;
            }
            else{
                sum -= flag * num;
            }
            num = 0;

            if (need_up && arr[arr.length-1] == '-'){
                flag *= (-1); //若是左括號前是-號,flag須要反轉
            }
        }
        else if(s[i] == ')'){
            if (arr[arr.length-1] == '-'){
                flag *= (-1); //移除-號時,flag須要反轉
            }
            arr.pop(); //碰到右括號移除一個運算符
        }
    }
    return sum;
}
View Code

 

棧鏈表實現和題目完整Demo見:https://github.com/xiaotanit/Tan_DataStruct

相關文章
相關標籤/搜索