數據結構學習與運用-棧

棧的定義

棧是一種先進後出的數據結構,咱們把容許插入和刪除的一端稱爲棧頂,另外一端稱爲棧底,不含任何元素的棧稱爲空棧。node

一、棧的操做端一般被稱爲棧頂,另外一端被稱爲棧底。 二、棧的插入操做稱爲進棧(壓棧|push);棧刪除操做稱爲出棧(彈棧|pop)。面試

棧的分類

根據棧的存儲方式,棧能夠分爲靜態棧(數組實現)和動態棧(鏈表實現)。算法

靜態棧

對於靜態棧,咱們通常經過數組來實現的。實現一個棧,裏面主要涉及到 2 種狀態和 2 種操做。數組

  1. 2 種狀態:棧滿和棧空
  2. 2 種操做:出棧和入棧

Java代碼實現靜態棧bash

首先咱們須要使用到一個數組來存儲數據,其次還須要一個變量用於棧的容量大小,還有一個變量來指示棧頂的數據。所以棧的內部數據結構以下所示:數據結構

private T data[];// 用數組表示棧元素
  private int maxSize;// 棧空間大小(常量)
  private int top;// 棧頂指針(指向棧頂元素)
複製代碼

對於棧的構造函數,咱們能夠以下表示:函數

public LJStack(int maxSize) {
    this.maxSize = maxSize;
    this.top = -1;
    this.data = (T[]) new Object[maxSize];
  }
複製代碼

對於棧空的判斷很簡單,只須要判斷 top 是否等於-1便可:測試

/**
   * 判斷棧是否爲空
   * 
   * @return
   */
  public boolean isEmpty() {
    return this.top == (-1) ? true : false;
  }
複製代碼

對於棧滿的狀態判斷也很簡單,經過 top 的值是否等於棧的容量大小 -1 即:ui

/**
   * 判斷棧是否爲滿了
   * 
   * @return
   */
  public boolean isFull() {
    return this.top == this.maxSize - 1 ? true : false;
  }
複製代碼

兩種狀態已經實現了,接下來咱們來看下兩種操做,對於入棧操做,核心就是數組的增長而已:this

/**
   * 壓棧操做,將數據存入到棧中
   * 
   * @param value
   */
  public boolean push(T value) {
    if (isFull()) {
      return false;
    } else {
      data[++top] = value;
      return true;
    }
  }
複製代碼

對於出棧來講就是將取出數組最後一個值:

/**
   * 出棧操做
   * @return
   */
  public T pop() {
    if (isEmpty()) {
      return null;
    } else {
      return data[top--];
    }
  }
複製代碼

以上即是用數組來實現的靜態棧,咱們能夠進行簡單的測試一下:

LJStack<String> stack = new LJStack<String>(10);
System.out.println("是否棧空:" + stack.isEmpty());
stack.push("AAAA");
stack.push("BBBB");
stack.push("CCCC");
stack.push("DDDD");
stack.push("1111");
stack.push("2222");
stack.push("3333");
stack.push("4444");
stack.push("5555");
stack.push("6666");
stack.push("7777");
stack.push("8888");
System.out.println("是否棧滿:" + stack.isFull());
複製代碼

打印出結果是:

在這裏插入圖片描述

咱們觀察結果會發現,打印棧裏面的結果發現,居然沒有「7777」,「8888」,那是由於棧滿了,因此沒法入棧了。所以能夠判斷,上面咱們寫的代碼是正確的。

鏈式棧

接着咱們來討論一下鏈式棧的實現。其實鏈式棧是經過鏈表實現棧,咱們能夠想象有個棧頂節點,當入棧的時候,原先的棧頂節點成爲新的節點後繼節點,新的節點成爲新的棧頂節點。同理,出棧的時候,將棧頂節點彈出,第二個節點成爲新的棧頂節點。

Java代碼實現鏈式棧

既然鏈式棧是經過鏈表來實現的,首先咱們須要構造一個鏈表的節點LJLinkNode,

public class LJLinkNode <T>{
  private T data;//數據域
  private LJLinkNode<T> next;//指針域
  
  public LJLinkNode() {
    this.data=null;
    this.next=null;
  }
  
  public LJLinkNode(T data) {
    this.data=data;
    this.next=null;
  }
  
  public void setData(T data) {
    this.data=data;
  }
  
  public T getData() {
    return this.data;
  }
  
  public void setNext(LJLinkNode<T> next) {
    this.next=next;
  }
  
  public LJLinkNode<T> getNext(){
    return this.next;
  }
}
複製代碼

具體實現以下:

private LJLinkNode<T> topLinkNode;// 棧頂節點
​
  /**
   * 初始化
   */
  public LJLinkStack() {
    this.topLinkNode = new LJLinkNode<T>();
  }
​
  /**
   * 初始化
   */
  public void initLinkStack() {
    this.topLinkNode.setData(null);
    this.topLinkNode.setNext(null);
  }
複製代碼

判斷棧空狀態:

/**
   * 判斷是否棧空
   * 
   * @return
   */
  public boolean isEmpty() {
    return this.topLinkNode.getNext() == null;
  }
複製代碼

壓棧操做:

/**
   * 壓棧 
   * 當入棧的時候,原先的棧頂節點成爲新的節點後繼節點,新的節點成爲新的棧頂節點。
   * 
   * @param node
   */
  public void push(LJLinkNode<T> node) {
    if (isEmpty()) {
      this.topLinkNode.setNext(node);
    } else {
      node.setNext(this.topLinkNode.getNext());
      this.topLinkNode.setNext(node);
    }
  }
複製代碼

出棧操做:

/**
   * 出棧 
   * 出棧的時候,將棧頂節點彈出,第二個節點成爲新的棧頂節點。
   * @return
   */
  public LJLinkNode<T> pop() {
    if (isEmpty()) {
      // 棧空沒法彈棧
      return null;
    } else {
      LJLinkNode<T> delNode = this.topLinkNode.getNext();// 取出刪除節點
      this.topLinkNode.setNext(this.topLinkNode.getNext().getNext());// 刪除節點
      return delNode;
    }
  }
複製代碼

咱們來測試一下寫的代碼:

LJLinkStack<String> linkStack = new LJLinkStack<String>();
    System.out.println("棧是否爲空:" + linkStack.isEmpty());
    linkStack.push(new LJLinkNode<String>("AAAAA"));
    linkStack.push(new LJLinkNode<String>("BBBBB"));
    linkStack.push(new LJLinkNode<String>("CCCCC"));
​
    // 依次彈棧
    System.out.println("彈棧順序:");
    System.out.println(linkStack.pop().getData());
    System.out.println(linkStack.pop().getData());
    System.out.println(linkStack.pop().getData());
複製代碼

打印結果以下:

在這裏插入圖片描述

以上即是棧的靜態及動態實現方式。那麼這兩種方式有什麼具體運用呢?接着咱們來經過具體的面試題目來運用棧。

算法運用

題目:匹配有效的括號

給定一個只包括 '('')''{''}''['']' 的字符串,判斷字符串是否有效。


有效字符串需知足:


左括號必須用相同類型的右括號閉合。
左括號必須以正確的順序閉合。
注意空字符串可被認爲是有效字符串。


示例 1:
輸入: "()"
輸出: true

示例 2:
輸入: "()[]{}"
輸出: true

示例 3:
輸入: "(]"
輸出: false

示例 4:
輸入: "([)]"
輸出: false

示例 5:
輸入: "{[]}"
輸出: true
複製代碼

來源:力扣(LeetCode) 連接:leetcode-cn.com/problems/va…

在這裏插入圖片描述

在這裏插入圖片描述
相關文章
相關標籤/搜索