微信搜尋:碼農StayUp
主頁地址:https://gozhuyinglong.github.io
原始碼分享:https://github.com/gozhuyinglong/blog-demos
1. 棧(Stack)
棧又叫堆疊,是一種運算受限制的線性表,限定只能在一端進行插入和刪除操作,該端稱為棧頂(Top),相對的另一端叫棧底(Bottom)。
根據棧的定義可知,最先進入棧的元素在棧底,最後進入棧的元素在棧頂。而刪除元素剛好相反,即刪除順序從棧頂到棧底
對棧的操作只有兩種:
- 入棧(push):又叫進棧或壓棧,即向棧插入一條新的元素,該元素為新的棧頂元素。
- 出棧(pop):又叫退棧,即從棧頂刪除(取出)最後入棧的元素,而其相鄰元素成為新的棧頂元素。
棧是一個先進後出(FILO - First In Last Out)的有序列表。在上圖中描述了棧的模型,我們對棧的操作只有push
和pop
,棧頂元素是該棧唯一可見的元素。
2. 程式碼實現
由於棧是一個表,因此任何實現表的方法都能實現棧。顯然我們之前用到的《 陣列 》和《 連結串列 》都可以實現棧。下面程式碼是使用陣列實現的一個棧。
size
表示棧內元素的大小,棧頂元素為 elementData[size - 1],棧底元素為 elementData[0]。入棧時執行 size++,出站時執行 size--
public class StackDemo {
public static void main(String[] args) {
System.out.println("-------------------入站");
Stack<String> stack = new Stack<>(10);
stack.push("a");
stack.push("b");
stack.push("c");
stack.push("d");
stack.push("e");
stack.print();
System.out.println("元素大小: " + stack.size());
System.out.println("棧容量: " + stack.capacity());
System.out.println("-------------------出站");
System.out.println("出站元素: " + stack.pop());
System.out.println("出站元素: " + stack.pop());
stack.print();
System.out.println("元素大小: " + stack.size());
System.out.println("棧容量: " + stack.capacity());
}
private static class Stack<E> {
private int size; // 元素大小
private final int capacity; // 棧的容量
transient Object[] elementData; // 元素資料
public Stack(int capacity) {
if (capacity <= 0) {
throw new IllegalArgumentException("Illegal Capacity: " + capacity);
} else {
this.capacity = capacity;
elementData = new Object[capacity];
}
}
/**
* 獲取棧的元素大小
*
* @return
*/
public int size() {
return size;
}
/**
* 獲取棧的容量
*
* @return
*/
public int capacity() {
return capacity;
}
/**
* 入棧
*
* @param e
* @return
*/
public boolean push(E e) {
if (size >= capacity) {
return false;
}
elementData[size++] = e;
return true;
}
/**
* 出棧
*
* @return
*/
public E pop() {
if (size <= 0) {
return null;
}
return (E) elementData[--size];
}
/**
* 列印元素資料
*/
public void print() {
System.out.print("站內元素: ");
for (int i = 0; i < size; i++) {
System.out.printf("%s\t", elementData[i]);
}
System.out.println();
}
}
}
輸出結果:
-------------------入站
站內元素: a b c d e
元素大小: 5
棧容量: 10
-------------------出站
出站元素: e
出站元素: d
站內元素: a b c
元素大小: 3
棧容量: 10
3. 棧的應用 - 平衡符號
編譯器檢查程式的語法錯誤時,常常會因為缺少一個符號(如遺漏一個花括號等)引起編譯器上列出上百行的診斷,而真正的錯誤並沒有找出。在這種情況下,如果能有一個工具能夠檢測括號必須成對出現那就好了,這便可以使用棧進行解決。
下面程式碼使用了Java自帶的Stack
類進行實現。字串[ ( ) ]
是合法的,而[ ( ] )
是錯誤的。
程式碼實現:
public class StackDemoBalancedChar {
public static void main(String[] args) {
BalancedChar balancedChar = new BalancedChar();
String str = "[()][{}][][((()))]";
boolean ok = balancedChar.isOk(str);
System.out.printf("字串:%s\t----> %s", str, ok);
}
private static class BalancedChar {
private final char[] openArray = {'(', '[', '{'}; // 左括號
private final char[] closeArray = {')', ']', '}'}; // 右括號
/**
* 判斷字串是否正確
*
* @param str
* @return
*/
public boolean isOk(String str) {
// 使用 Java 自帶的 Stack 類
Stack<Character> stack = new Stack<>();
boolean ok = true; // 判斷字串是否正確
for (char c : str.toCharArray()) {
// 若不是平衡符則忽略
if (!isBalancedChar(c)) {
continue;
}
// 如果是左括號,則入棧
if (isOpen(c)) {
stack.push(c);
continue;
}
// 如果是右括號,而棧為空則報錯
if (stack.empty()) {
ok = false;
break;
}
// 如果是右括號,從棧中取出一個元素,並與當前元素判斷是否是一對,若不是一對則報錯
Character open = stack.pop();
if (!isTwain(open, c)) {
ok = false;
}
}
return ok && stack.empty();
}
/**
* 是否為左括號
*
* @param c
* @return
*/
public boolean isOpen(char c) {
return inArray(openArray, c);
}
/**
* 是否為右括號
*
* @param c
* @return
*/
public boolean isClose(char c) {
return inArray(closeArray, c);
}
/**
* 是否是平衡符
*/
public boolean isBalancedChar(char c) {
return isOpen(c) || isClose(c);
}
/**
* 是否在陣列中
*
* @param charArray
* @param c
* @return
*/
public boolean inArray(char[] charArray, char c) {
for (char c1 : charArray) {
if (c1 == c) {
return true;
}
}
return false;
}
/**
* 是否一對平衡符
*
* @param open
* @param close
* @return
*/
public boolean isTwain(char open, char close) {
switch (open) {
case '(':
if (close == ')') {
return true;
}
case '[':
if (close == ']') {
return true;
}
case '{':
if (close == '}') {
return true;
}
default:
return false;
}
}
}
}
輸出結果:
字串:[()][{}][][((()))] ----> true