数据结构-顺序栈、链栈
一、堆棧的基本概念:
堆棧(也簡稱作棧)是一種特殊的線性表,堆棧的數據元素以及數據元素間的邏輯關系和線性表完全相同,其差別是線性表允許在任意位置進行插入和刪除操作,而堆棧只允許在固定一端進行插入和刪除操作。
先進后出:堆棧中允許進行插入和刪除操作的一端稱為棧頂,另一端稱為棧底。堆棧的插入和刪除操作通常稱為進棧或入棧,堆棧的刪除操作通常稱為出棧或退棧。
備注:棧本身就是一個線性表,所以我們之前討論過線性表的順序存儲和鏈式存儲,對于棧來說,同樣適用。
二、堆棧的抽象數據類型:
數據集合:
堆棧的數據集合可以表示為a0,a1,…,an-1,每個數據元素的數據類型可以是任意的類類型。
操作集合:
(1)入棧push(obj):把數據元素obj插入堆棧。(2)出棧pop():出棧, 刪除的數據元素由函數返回。(3)取棧頂數據元素getTop():取堆棧當前棧頂的數據元素并由函數返回。(4)非空否notEmpty():若堆棧非空則函數返回true,否則函數返回false。三、順序棧:
順序存儲結構的堆棧稱作順序堆棧。其存儲結構示意圖如下圖所示:
1、順序棧的實現:
(1)設計Stack接口
(2)實現SequenceStack類
**注:**棧是線性表的特例,線性表本身就是用數組來實現的。于是,順序棧也是用數組實現的。
代碼實現:
(1)Stack.java:(Stack接口)
1 public interface Stack {2 3 //入棧4 public void push(Object obj) throws Exception;5 6 //出棧7 public Object pop() throws Exception;8 9 //獲取棧頂元素 10 public Object getTop() throws Exception; 11 12 //判斷棧是否為空 13 public boolean isEmpty(); 14 }(2)SequenceStack.java
1 //順序棧2 public class SequenceStack implements Stack {3 4 Object[] stack; //對象數組(棧用數組來實現)5 final int defaultSize = 10; //默認最大長度6 int top; //棧頂位置(的一個下標):其實可以理解成棧的實際長度7 int maxSize; //最大長度8 9 //如果用無參構造的話,就設置默認長度 10 public SequenceStack() { 11 init(defaultSize); 12 } 13 14 //如果使用帶參構造的話,就調用指定的最大長度 15 public SequenceStack(int size) { 16 init(size); 17 } 18 19 public void init(int size) { 20 this.maxSize = size; 21 top = 0; 22 stack = new Object[size]; 23 } 24 25 //獲取棧頂元素 26 @Override 27 public Object getTop() throws Exception { 28 // TODO Auto-generated method stub 29 if (isEmpty()) { 30 throw new Exception("堆棧為空!"); 31 } 32 33 return stack[top - 1]; 34 } 35 36 //判斷棧是否為空 37 @Override 38 public boolean isEmpty() { 39 // TODO Auto-generated method stub 40 return top == 0; 41 } 42 43 //出棧操作 44 @Override 45 public Object pop() throws Exception { 46 // TODO Auto-generated method stub 47 if (isEmpty()) { 48 throw new Exception("堆棧為空!"); 49 } 50 top--; 51 52 return stack[top]; 53 } 54 55 //入棧操作 56 @Override 57 public void push(Object obj) throws Exception { 58 // TODO Auto-generated method stub 59 //首先判斷棧是否已滿 60 if (top == maxSize) { 61 throw new Exception("堆棧已滿!"); 62 } 63 stack[top] = obj; 64 top++; 65 } 66 }2、測試類:
設計一個順序棧,從鍵盤輸入十個整數壓進棧,然后再彈出棧,并打印出棧序列。
代碼實現:
(3)Test.java
1 import java.util.Scanner;2 3 public class Test {4 public static void main(String[] args) throws Exception {5 SequenceStack stack = new SequenceStack(10);6 7 Scanner in = new Scanner(System.in);8 int temp;9 for (int i = 0; i < 10; i++) { 10 System.out.println("請輸入第" + (i + 1) + "個整數:"); 11 temp = in.nextInt(); 12 stack.push(temp); 13 } 14 15 //遍歷輸出 16 while (!stack.isEmpty()) { 17 System.out.println(stack.pop()); 18 } 19 } 20 }運行效果:
四、棧應用
1、括號匹配問題
假設算術表達式中包含圓括號,方括號,和花括號三種類型。使用棧數據結構編寫一個算法判斷表達式中括號是否正確匹配,并設計一個主函數測試。
比如:
{a+[b+(ca)/(d-e)]} 正確
([a+b)-(ce)]+{a+b} 錯誤,中括號的次序不對
括號匹配有四種情況:
1.左右括號匹配次序不正確2.右括號多于左括號3.左括號多于右括號4.匹配正確下面我們就通過代碼把這四種情況列舉出來。
代碼實現
1 public class Test {2 3 //方法:將字符串轉化為字符串數組4 public static String[] expToStringArray(String exp) {5 int n = exp.length();6 String[] arr = new String[n];7 for (int i = 0; i < arr.length; i++) {8 arr[i] = exp.substring(i, i + 1);9 } 10 return arr; 11 } 12 13 //方法:括號匹配問題的檢測 14 public static void signCheck(String exp) throws Exception { 15 SequenceStack stack = new SequenceStack(); 16 String[] arr = Test.expToStringArray(exp); 17 for (int i = 0; i < arr.length; i++) { 18 if (arr[i].equals("(") || arr[i].equals("[") || arr[i].equals("{")) { //當碰到都是左邊的括號的時候,統統壓進棧 19 stack.push(arr[i]); 20 } else if (arr[i].equals(")") && !stack.isEmpty() && stack.getTop().equals("(")) { //當碰到了右小括號時,如果匹配正確,就將左小括號出棧 21 stack.pop(); 22 } else if (arr[i].equals(")") && !stack.isEmpty() && !stack.getTop().equals("(")) { 23 System.out.println("左右括號匹配次序不正確!"); 24 return; 25 } else if (arr[i].equals("]") && !stack.isEmpty() && stack.getTop().equals("[")) { 26 stack.pop(); 27 } else if (arr[i].equals("]") && !stack.isEmpty() && !stack.getTop().equals("[")) { 28 System.out.println("左右括號匹配次序不正確!"); 29 return; 30 } else if (arr[i].equals("}") && !stack.isEmpty() && stack.getTop().equals("{")) { 31 stack.pop(); 32 } else if (arr[i].equals("}") && !stack.isEmpty() && !stack.getTop().equals("{")) { 33 System.out.println("左右括號匹配次序不正確!"); 34 return; 35 } else if (arr[i].equals(")") || arr[i].equals("]") || arr[i].equals("}") && stack.isEmpty()) { 36 System.out.println("右括號多于左括號!"); 37 return; 38 } 39 } 40 if (!stack.isEmpty()) { 41 System.out.println("左括號多于右括號!"); 42 } else { 43 System.out.println("括號匹配正確!"); 44 } 45 } 46 47 48 public static void main(String[] args) throws Exception { 49 50 String str = "([(a+b)-(c*e)]+{a+b}"; 51 //括號匹配的檢測 52 Test.signCheck(str); 53 } 54 }運行效果:
四、鏈式堆棧:
棧的鏈式存儲結構稱為鏈棧。
在算法中要用到多個棧時,最好用鏈表作為棧的存儲結構,即用指針來實現棧。用這種方式實現的棧也稱為鏈棧。由于棧的插人和刪除操作只在表頭進行,因此用指針實現棧時沒有必要像單鏈表那樣設置一個表頭單元。
1、鏈棧結構及數據類型
棧的鏈式存貯結構,也稱為鏈棧,它是一種限制運算的鏈表,即規定鏈表中的插入和刪除運算只能在鏈表開頭進行。鏈棧結構見圖。
2、代碼實現
鏈表結點LinearNode.java
public class LinearNode<T> {private LinearNode<T> next;private T elem;public LinearNode(){next=null;elem=null;}public LinearNode(T ele){next=null;this.elem=ele;}public LinearNode<T> getNext(){return next;}public void setNext(LinearNode<T> node) {this.next = node;}public T getElem() {return elem;}public void setElem(T elem) {this.elem = elem;}}鏈表結點LinkedStack.java
public class LinkedStack<T> implements StackADT<T> {private int count;// 指向棧頂的指針private LinearNode<T> top;public LinkedStack() {count = 0;top = null;}/*** 創建一個新的結點,該結點含有一個引用,指向要放置到戰中的對象 把新結點的next設置為top 把top引用設置指向當前新結點 遞增棧的元素計數*/@Overridepublic void push(T elem) {// /結點的創建 和 引用聲明LinearNode<T> temp = new LinearNode<T>(elem);temp.setNext(top);top = temp;count++;}@Overridepublic T pop() throws EmptyCollectionException {if (isEmpty()) {throw new EmptyCollectionException("LinkedStack");}T result = top.getElem();top = top.getNext();count--;return result;}@Overridepublic T peek() {if (isEmpty()) {throw new EmptyCollectionException("LinkedStack");}T result = top.getElem();return result;}@Overridepublic boolean isEmpty() {return (count == 0);}@Overridepublic int size() {return count;}@Overridepublic String toString() {StringBuilder result = new StringBuilder();result.append("");LinearNode<T> temp = top;while(temp!=null){result.append(temp.getElem()+"\n");temp = temp.getNext();}return result.toString();}}輔助類實現
EmptyCollectionException.java
public class EmptyCollectionException extends RuntimeException {public EmptyCollectionException(String collection) {super("the " + collection + "is Empty!");} }二、鏈棧應用
1、表達式計算
比如:
3+(6-4/2)*5=23
其后綴表達式為:3642/-5*+# (#符號為結束符)
現在要做的是:
使用鏈式堆棧,設計一個算法計算表達式,當我們輸入后綴表達式后,能輸出運行結果。
代碼實現:
1 public class Test {2 3 //方法:使用鏈式堆棧,設計一個算法計算表達式4 public static void expCaculate(LinkStack stack) throws Exception {5 char ch; //掃描每次輸入的字符。6 int x1, x2, b = 0; //x1,x2:兩個操作數 ,b字符的ASCII碼7 System.out.println("輸入后綴表達式并以#符號結束:");8 while ((ch = (char) (b = System.in.read())) != '#') {9 //如果是數字,說明是操作數則壓入堆棧 10 if (Character.isDigit(ch)) { 11 stack.push(new Integer(Character.toString(ch))); 12 } 13 //如果不是數字,說明是運算符 14 else { 15 x2 = ((Integer) stack.pop()).intValue(); 16 x1 = ((Integer) stack.pop()).intValue(); 17 switch (ch) { 18 case '+': 19 x1 += x2; 20 break; 21 case '-': 22 x1 -= x2; 23 break; 24 case '*': 25 x1 *= x2; 26 break; 27 case '/': 28 if (x2 == 0) { 29 throw new Exception("分母不能為零!"); 30 } else { 31 x1 /= x2; 32 } 33 break; 34 } 35 stack.push(new Integer(x1)); 36 } 37 } 38 System.out.println("后綴表達式計算結果是:" + stack.getTop()); 39 } 40 41 public static void main(String[] args) throws Exception { 42 LinkStack stack = new LinkStack(); 43 //(2+3)*(3-1)/2=5的后綴表達式為:23+31-*2/ 44 //方法:鍵盤輸入后綴表達式,輸出的得到計算結果 45 Test.expCaculate(stack); 46 47 } 48 }運行效果:
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的数据结构-顺序栈、链栈的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构-单向循环链表、双向循环链表、仿
- 下一篇: “面试不败计划”:集合总结