javascript資料結構與演算法-棧

GoodLiang發表於2018-11-14

定義

棧作為一種資料結構,是一種只能在一端進行插入和刪除操作的特殊線性表。它按照先進後出的原則儲存資料,先進入的資料被壓入棧底,最後的資料在棧頂,需要讀資料的時候從棧頂開始彈出資料(最後一個資料被第一個讀出來)。棧具有記憶作用,對棧的插入與刪除操作中,不需要改變棧底指標。 棧是允許在同一端進行插入和刪除操作的特殊線性表。允許進行插入和刪除操作的一端稱為棧頂(top),另一端為棧底(bottom);棧底固定,而棧頂浮動;棧中元素個數為零時稱為空棧。插入一般稱為進棧(PUSH),刪除則稱為退棧(POP)。棧也稱為後進先出表。

方法和屬性

  • push方法 入棧
  • pop方法 刪除棧頂的元素
  • peek方法 檢視當前棧頂的元素
  • isEmpty方法
  • size方法
  • toString方法 列印出所有元素
  • length屬性 棧的元素個數
  • list屬性 儲存棧
    下面是出棧和入棧的示意圖,照片來自網路
    javascript資料結構與演算法-棧

程式碼實現棧

這裡我們用js陣列來模擬棧,應為js是一門強大的高階語言,陣列的push和pop方法在棧中也同樣適用

class Stack {
  constructor() {
    this.list = [];
    this.length = 0;
  }
  push(value) {
    this.length++;
    this.list.push(value);
  }
  pop() {
    if (this.isEmpty()) {
      return undefined;
    }
    this.length--;
    return this.list.pop();
  }
  isEmpty() {
    return this.length === 0;   
  }
  size() {
    return this.length;
  }
  peek() {
    if (this.isEmpty()) {
      return undefined;
    }
    return this.list[this.length - 1];
  }
  toString() {
    if (this.isEmpty()) {
      return '';
    }
    let objString = `${this.list[0]}`;
    for (let i = 1; i < this.length; i++) {
      objString = `${objString},${this.list[i]}`;
    }
    return objString;
  }
}
複製程式碼

或者用物件來實現棧,但是沒有陣列原生的那些函式了

入棧的時候,索引會變成物件的下標,就能set和get了

class Stack {
  constructor() {
    this.length = 0;
    this.items = {};
  }
  push(element) {
    this.items[this.length] = element;
    this.length++;
  }
  pop() {
    if (this.isEmpty()) {
      return undefined;
    }
    this.length--;
    const result = this.items[this.length];
    delete this.items[this.length];
    return result;
  }
  peek() {
    if (this.isEmpty()) {
      return undefined;
    }
    return this.items[this.length - 1];
  }
  isEmpty() {
    return this.length === 0;
  }
  size() {
    return this.length;
  }
  clear() {
    /* while (!this.isEmpty()) {
        this.pop();
      } */
    this.items = {};
    this.length = 0;
  }
  toString() {
    if (this.isEmpty()) {
      return '';
    }
    let objString = `${this.items[0]}`;
    for (let i = 1; i < this.length; i++) {
      objString = `${objString},${this.items[i]}`;
    }
    return objString;
  }
}
複製程式碼

用ts實現一遍

class Stack<T> {
  private count: number;
  private items: any;

  constructor() {
    this.count = 0;
    this.items = {};
  }

  push(element: T) {
    this.items[this.count] = element;
    this.count++;
  }

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

  peek() {
    if (this.isEmpty()) {
      return undefined;
    }
    return this.items[this.count - 1];
  }

  isEmpty() {
    return this.count === 0;
  }

  size() {
    return this.count;
  }

  clear() {
    /* while (!this.isEmpty()) {
      this.pop();
    } */

    this.items = {};
    this.count = 0;
  }
  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;
  }
}
複製程式碼

存在的問題

儘管程式碼看起來還行,但是我們發現list時公用的,es6貌似不能宣告私有變數和私有函式,畢竟別的語言的 private 太強大了,網上有很多種實現形式,目前比較讓人認可的,主要是weakmap和symbol兩種,但我覺得這樣寫程式碼也太不優雅了,先公共著吧,hhhhh

用棧實現10進位制向n進位制轉換

我們知道二進位制是除2取餘再從下往上拿餘數,取餘數是%,從下往上拿餘數和從迴圈棧頂拿元素相似。同理轉8 進位制就是除8取餘.... 實現思路:

  • 最高位為 num % base 然後直接壓入棧;
  • 使用 num / base 來代替 num ;
  • 重複上面的步驟,直到 n 為 0 ,並且沒有餘數;
  • 以此將棧內元素彈出,直到棧空,並依次將這些元素排列,就得到了轉換後的形式
let mulBase =(num,base)=>{
    let s = new Stack();
    while(num>0){
        s.push(num%base);
        num = Math.floor(num/=base);
    }
    var converted = "";
    while(s.size()>0){
        converted+=s.pop();
    }
    return converted;
} 
複製程式碼

用棧實現迴文判斷

實現思路:將字串的每一次一次入棧,探後迴圈出棧,判斷出棧後的字串和原來的字串是否是相等的,若一致,則是迴文

let isPalindrome=(str)=>{
    let s = new Stack();
    for(let i = 0;i<str.length;i++){
        // 依次入棧
        s.push(str[i]);
    }
    let newStr = "";
    while(s.size()>0){
        newStr+=s.pop();
    }
    if(newStr===str){
        return true;
    }else{
        return false;
    }
}
console.log(isPalindrome("123321")) // true
複製程式碼

另一種方法字串直接翻轉就好了

 let isPalindrome =( word )=>{
    return String(word).split('').reverse().join('') == word ? true : false;
}
複製程式碼

相關文章