資料結構之棧
一:概述
由圖我們可看成棧只能從棧頂存取元素,同時先進入的元素反而是後出,而棧頂永遠指向棧內最頂部的元素。到此可以給出棧的正式定義:棧(Stack)是一種有序特殊的線性表,只能在表的一端(稱為棧頂,top,總是指向棧頂元素)執行插入和刪除操作,最後插入的元素將第一個被刪除,因此棧也稱為後進先出(Last In First Out,LIFO)或先進後出(First In Last Out FILO)的線性表。棧的基本操作建立棧,判空,入棧,出棧,獲取棧頂元素等,注意棧不支援對指定位置進行刪除,插入,其介面Stack宣告如下:
public interface Stack<T> {
// 棧是否為空
boolean isEmpty();
// 入棧
void push(T data);
// 取出棧頂元素,不出棧
T peek();
// 出棧
T pop();
}
二:順序棧的設計與實現
順序棧,顧名思義就是採用順序表實現的的棧,順序棧的內部以順序表為基礎,實現對元素的存取操作,當然我們還可以採用內部陣列實現順序棧,在這裡我們使用內部資料組來實現棧:
public class SeqStack<T> implements Stack<T>{
//棧頂索引,-1代表空棧
private int top = -1;
//預設容量大小
private int capacity = 10;
//存放資料的陣列
private T[] arr;
//棧的實際使用量
private int size;
public SeqStack() {
arr = (T[]) new Object[capacity];
}
//是否是空棧的判斷依據是top是否為-1;如果大於等於0,說明棧中有元素
@Override
public boolean isEmpty() {
return top == -1;
}
//獲取棧頂元素,本例基於陣列來實現棧,所以棧頂元素,就是陣列的最後一個元素
@Override
public T peek() {
//如果是空棧就丟擲異常
if(isEmpty()) {
new EmptyStackException();
}
//返回陣列的最後一個元素
return arr[top];
}
//獲取棧頂元素並出棧
@Override
public T pop() {
//國際慣例,空棧丟擲異常
if(isEmpty()) {
new EmptyStackException();
}
size --;
//需要注意的是,這裡不會將陣列的最後一個元素置空,因為top的值已經修改
//下次再push的時候只是把原來的陣列元素的值進行了修改,因為一旦pop後,
//top的值減小了,原來的陣列的元素永遠訪問不到,完全沒有必要置空.
return arr[top--];
}
//入棧
@Override
public void push(T data) {
//如果棧已滿,那麼擴容
if(size == arr.length) {
ensureCapacity(size*2+1);
}
//先將棧頂指標+1,然後將元素放入top + 1那個位置
arr[++top] = data;
size++;
}
//擴容的思路很簡單,建立一個新的陣列,然後將原來陣列的資料複製到新陣列
private void ensureCapacity(int capacity) {
//以防萬一
if(capacity > size) {
return;
}
T[] old = arr;
arr = (T[]) new Object[capacity];
for(int i = 0 ; i < old.length ; i++) {
arr[i] = old[i];
}
}
}
測試程式碼:
public static void main(String[] args) {
SeqStack<String> stack = new SeqStack<>();
stack.push("A");
stack.push("B");
stack.push("C");
stack.push("D");
int l = stack.size;
System.out.println("size : " + l + " , top index : " + stack.top +
" , top : " + stack.peek());
for(int i = 0 ; i < l; i ++) {
stack.pop();
}
//此處丟擲異常
System.out.println("size : " + l + " , top : " + stack.peek());
}
測試結果:
push A , size : 1
push B , size : 2
push C , size : 3
push D , size : 4
size : 4 , top index : 3 , top : D
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at teststack.SeqStack.peek(SeqStack.java:58)
at teststack.SeqStack.main(SeqStack.java:42)
從上面可以看出,順序棧的邏輯很簡單,就是操作底層的陣列而已,所有的入棧和出棧操作,都是往陣列新增和刪除元素,然後改變top指標的位置。
以上就是順序棧的實現,簡單。
三:鏈式棧的設計與實現
public class LinkStack<T> implements Stack<T>{
//棧頂元素
private Node<T> top;
private int size;
public LinkStack() {
top = new Node<T>();
}
//如果棧頂元素為空,或者棧頂元素的資料為空,一律視為空棧
@Override
public boolean isEmpty() {
return top == null || top.data == null;
}
@Override
public void push(T data) {
if (data == null) {
try {
throw new Exception("data can\'t be null");
} catch (Exception e) {
e.printStackTrace();
}
}
//如果棧頂節點是空的話,那麼建立一個新的節點當做棧頂節點
if (top == null) {
top = new Node<>(data);
//如果棧頂節點的資料為空的話,那麼將資料賦值給該節點
} else if (top.data == null) {
top.data = data;
//如果棧頂節點和資料都不為空,說明不是空棧,這時候需要建立一個
//新的節點,將它賦值給棧頂節點,同時將它的next指向當前的棧頂節點
} else {
Node<T> p = new Node<T>(data, this.top);
top = p;
}
size++;
}
// 獲取棧頂元素,我們一直持有棧頂節點的引用,直接返回好了
@Override
public T peek() {
if (isEmpty()) {
new EmptyStackException();
}
return top.data;
}
//出棧,就是將棧頂節點的下一個節點當做新的棧頂節點,
//實質上就是移除連結串列中的頭結點,很簡單
@Override
public T pop() {
if (isEmpty()) {
new EmptyStackException();
}
T data = top.data;
top = top.next;
size--;
return data;
}
//節點
class Node<T> {
public T data;
public Node<T> next;
public Node() {
}
public Node(T data) {
this.data = data;
}
public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
}
測試程式碼:
public static void main(String[] args) {
LinkStack<String> sl = new LinkStack<>();
sl.push("A");
sl.push("B");
sl.push("C");
int length = sl.size;
for (int i = 0; i < length; i++) {
System.out.println("sl.pop->" + sl.pop() + " , size : " + sl.size);
}
sl.push("T");
System.out.println("sl.pop->" + sl.peek() + " , size : " + sl.size);
}
測試結果:
sl.pop->C , size : 2
sl.pop->B , size : 1
sl.pop->A , size : 0
sl.pop->T , size : 1
綜上可知,棧的實現還是很簡單的,下面講下棧的應用場景。
四:棧的應用
棧是一種很重要的資料結構,在計算機中有著很廣泛的應用,如下一些操作都應用到了棧:
符號匹配
中綴表示式轉換為字尾表示式
計算字尾表示式
實現函式的巢狀呼叫
HTML和XML檔案中的標籤匹配
網頁瀏覽器中已訪問頁面的歷史記錄
符號匹配:
在編寫程式的過程中,我們經常會遇到諸如圓括號“()”與花括號“{}”,這些符號都必須是左右匹配的,這就是我們所說的符合匹配型別,當然符合不僅需要個數相等,而且需要先左後右的依次出現,否則就不符合匹配規則,如“)(”,明顯是錯誤的匹配,而“()”才是正確的匹配。有時候符合如括號還會巢狀出現,如“9-(5+(5+1))”,而巢狀的匹配原則是一個右括號與其前面最近的一個括號匹配,事實上編譯器幫我檢查語法錯誤是也是執行一樣的匹配原理,而這一系列操作都需要藉助棧來完成,接下來我們使用棧來實現括號”()”是否匹配的檢測。
判斷原則如下(str=”((5-3)*8-2)”):
a.設定str是一個表示式字串,從左到右依次對字串str中的每個字元char進行語法檢測,如果char是,左括號則入棧,如果char是右括號則出棧(有一對匹配就可以去匹配一個左括號,因此可以出棧),若此時出棧的字元char為左括號,則說明這一對括號匹配正常,如果此時棧為空或者出棧字元不為左括號,則表示缺少與char匹配的左括號,即目前不完整。
b.重複執行a操作,直到str檢測結束,如果此時棧為空,則全部括號匹配,如果棧中還有左括號,是說明缺少右括號。
接著我們用棧作為儲存容器通過程式碼來實現這個過程
public class CheckExpression {
public static String isValid(String expstr){
//建立棧
LinkedStack<String> stack = new LinkedStack<>();
int i = 0 ;
//遍歷字串,挨個取出每個字元
while(i < expstr.lenght()){
char c = expstr.charAt(i);
i++;
switch (ch){
//如果該字元是左括號,那麼放入棧中
case '(' :
stack.push(ch + "");
break;
//如果是右括號,那麼將左括號出棧
case ")" :
if(stack.isEmpty() || !stack.pop().equals("(")) {
return "FAILURE";
}
}
}
//經過這麼一輪迴圈,如果棧為空,說明每個左括號都有
//右括號和他匹配,這時候校驗通過,否則不通過
if(stack.isEmpty()) {
return "PASS";
}else {
return "FAILURE";
}
}
}
測試程式碼:
String expstr="((5-3)*8-2)";
System.out.println(expstr + " check " + check(expstr));
String expstr1="((5-3)*8-2";
System.out.println(expstr1 + " check " + check(expstr1));
測試結果:
((5-3)*8-2) check PASS
((5-3)*8-2 check FAILURE
摘自:https://blog.csdn.net/javazejian/article/details/53362993
相關文章
- 資料結構之——棧資料結構
- 資料結構之「棧」資料結構
- JavaScript資料結構之-棧JavaScript資料結構
- js資料結構之棧JS資料結構
- JavaScript資料結構之棧JavaScript資料結構
- python資料結構之棧Python資料結構
- 重學資料結構之棧資料結構
- 資料結構之php實現棧資料結構PHP
- JavaScript 資料結構之隊棧互搏JavaScript資料結構
- 資料結構 - 棧資料結構
- 資料結構-棧資料結構
- 資料結構二之棧和佇列資料結構佇列
- 資料結構(1):棧資料結構
- javascript資料結構 -- 棧JavaScript資料結構
- 前端資料結構(1)之棧及其應用前端資料結構
- JavaScript資料結構之陣列棧佇列JavaScript資料結構陣列佇列
- 實戰PHP資料結構基礎之棧PHP資料結構
- 資料結構與演算法-資料結構(棧)資料結構演算法
- 畫江湖之資料結構【第二話:佇列和棧】棧資料結構佇列
- 畫江湖之資料結構 [第二話:佇列和棧] 棧資料結構佇列
- 資料結構-佇列、棧資料結構佇列
- 資料結構03-棧資料結構
- 資料結構:棧詳解資料結構
- 波波的資料結構-棧資料結構
- Java版-資料結構-棧Java資料結構
- js資料結構--棧(stack)JS資料結構
- JavaScript資料結構02 - 棧JavaScript資料結構
- 資料結構筆記——棧資料結構筆記
- 看得見的資料結構Android版之棧篇資料結構Android
- php實現基本資料結構之棧、佇列PHP資料結構佇列
- 資料結構(筆試題-棧(入棧出棧)資料結構筆試
- 資料結構:特殊的線性表之 棧 & 佇列資料結構佇列
- 資料結構基礎學習之(棧和佇列)資料結構佇列
- 01Javascript資料結構與演算法 之 棧JavaScript資料結構演算法
- 特殊資料結構:單調棧資料結構
- 重學資料結構(二、棧)資料結構
- 資料結構(棧和佇列)資料結構佇列
- 資料結構-棧與佇列資料結構佇列