棧是一種後進先出的線性表數據結構,分爲棧頂和棧底兩端,僅容許在表的一端插入元素,這一端被稱爲棧頂,另一端稱之爲棧底。棧,只有兩種操做,分爲入棧(壓棧)和出棧(退棧);向棧中添加元素的操做叫作入棧,相反從棧中刪除元素叫作出棧。java
爲了你們更好的形象瞭解咱們經過示意圖來看一下棧的入棧
和出棧
操做git
void push(E e) 複製代碼
E pop() 複製代碼
E peek() 複製代碼
int getSize() 複製代碼
boolean isEmpty() 複製代碼
實現棧的方式,實際上底層有多種實現方式,好比:動態數組等,這裏咱們使用Java語言自己爲咱們提供的集合LinkedList
github
public interface Stack<E> {
/** * 向棧中添加元素 * * @param e */
void push(E e);
/** * 從棧中刪除元素 */
void pop();
/** * 獲取棧頂元素 * * @return */
E peek();
/** * 獲取棧中元素個數 * * @return */
int getSize();
/** * 判斷棧中是否爲空 * * @return */
boolean isEmpty();
}
複製代碼
public class LinkedListStack<E> implements Stack<E> {
/** * 存放棧元素 */
LinkedList<E> list;
/** * 構造棧結構 */
public LinkedListStack() {
list = new LinkedList<>();
}
@Override
public void push(E e) {
list.addLast(e);
}
@Override
public void pop() {
list.removeLast();
}
@Override
public E peek() {
return list.getLast();
}
@Override
public int getSize() {
return list.size();
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public String toString() {
return "LinkedListStack{" +
"list=" + list +
'}';
}
}
複製代碼
@Test
public void testLinkedListStack() {
// 棧
Stack<String> stack = new LinkedListStack<>();
// 準備入棧元素
List<String> prepareElements = Arrays.asList("A", "B", "C", "D", "E");
// 入棧
prepareElements.forEach(x -> {
stack.push(x);
System.out.println("入棧操做:" + stack);
});
// 出棧
stack.pop();
System.out.println("出棧操做:" + stack);
// 獲取棧頂元素
String peekElement = stack.peek();
System.out.println("棧頂元素:" + peekElement);
// 獲取棧中元素的個數
int stackSize = stack.getSize();
System.out.println("棧中元素個數:" + stackSize);
}
複製代碼
入棧操做:LinkedListStack{list=[A]}
入棧操做:LinkedListStack{list=[A, B]}
入棧操做:LinkedListStack{list=[A, B, C]}
入棧操做:LinkedListStack{list=[A, B, C, D]}
入棧操做:LinkedListStack{list=[A, B, C, D, E]}
出棧操做:LinkedListStack{list=[A, B, C, D]}
棧頂元素:D
棧中元素個數:4
複製代碼
在Java虛擬機運行時數據區有一塊被稱之爲:虛擬機棧
,它是線程私有的,聲明週期與線程相同。數組
咱們編寫的每一個Java方法,每一個方法都會在執行的時候同時都會建立一個棧幀
(Stack Frame)用於存儲局部變量表、操做數棧、動態連接、方法出口等信息。每個方法從調用直至執行完成的過程,就對應這一個棧幀
在虛擬機棧中入棧
到出棧
的過程。數據結構
如今咱們假設有A、B、C三個方法,在A方法中調用B方法(A->B),在B方法中調用C方法(B->C),C方法執行本方法業務邏輯。ide
當程序執行到A()
方法的中的第二行時,此時程序會中斷A()
方法並開始調用B()
方法,而後會在虛擬機棧中記錄調用B()方法的棧幀,我這裏暫且稱之爲A2
(實際存儲的並非O(∩_∩)O哈!)示意圖以下:測試
同理,當程序執行到B()
方法中第二行時,此時程序也會中斷B()
方法開始調用C()
方法,而後一樣地會在虛擬機棧中生成調用C()
方法的棧幀並記錄,我這裏暫且稱之爲B2
,示意圖以下:spa
當程序開始執行到C()
方法時,直到執行完C()
方法時,這時候,程序該如何執行呢?線程
此時就要查看一下虛擬機棧了,發現虛擬機棧,棧中棧頂的元素是B2
,咱們的程序就知道了,它是執行到B()
方法的B2
位置就中斷了,去執行C()
方法了;如今C()
方法執行完成以後,它就能夠跳回到B2
的位置繼續執行了,當B()
方法執行完以後,虛擬機棧中的B2
棧幀也就能夠出棧了,依次類推....code
若是一個方法,使用遞歸調用,若遞歸臨界點判斷有誤,則方法就會一直的被進行入棧操做,若是超過虛擬機棧的默認容量大小,則會出現咱們常見的
StackOverflowError
異常
完整版代碼GitHub倉庫地址:Java版數據結構-棧 歡迎你們【關注】和【Star】
本次咱們完成的是基於Java自身自帶的集合LinkedList
來實現棧,有興趣的童鞋,可使用動態數組方式來實現;接下來,筆者還會一一的實現其它常見的數組結構。
持續更新中,歡迎你們關注公衆號:小白程序之路(whiteontheroad),第一時間獲取最新信息!!!