@
1、棧的定義和特點
棧(Stack)又稱堆疊, 是限制在表的一端進行插入和刪除運算的線性表。
如果要拿一個東西對比,羽毛球筒比較合適。
棧遵循後進先出( Last-in-first-out,LIFO)的原則。
比如上面的羽毛球筒,只能將最頂端的羽毛球移出,也只能將新的羽毛球放到最頂端——這兩種操作分別稱作入棧( Push)和出棧( Pop)。入棧和出棧的示意圖如下:
最頂端的羽毛球叫棧頂棧頂 (top),最底端的羽毛球稱為棧底 (bottom)。
2、棧的基本操作
棧的基本操作除了入棧和出棧外, 還有棧的初始化、 棧空的判定, 以及取棧頂元素等。
根據這些操作,我們定義一個介面:
/**
* @Author 三分惡
* @Date 2020/8/26
* @Description 棧介面
*/
public interface Stack {
public int getSize(); //返回棧中元素數目
public boolean isEmpty(); //判空
public Object top(); //取棧頂元素但不刪除
public void push(Object element); //入棧
public Object pop(); //出棧
}
線性表有順序和鏈式兩種實現,棧同樣有兩種實現。
3、順序棧
這裡我們通過一個可擴容的陣列來實現。
/**
* @Author 三分惡
* @Date 2020/8/26
* @Description 順序棧--陣列實現
*/
public class ArrayStack implements Stack{
private static int defaultSize=15; //預設容量
private int size; //實際容量:實際儲存元素個數
private Object[] data; //存放元素的陣列
/**
* 無參構造方法:按預設容量構造元素陣列
*/
public ArrayStack() {
data=new Object[defaultSize];
size=0;
}
/**
* 有參構造方法:指定元素陣列容量
* @param size
*/
public ArrayStack(int size){
data=new Object[size];
}
public int getSize() {
return size;
}
public boolean isEmpty() {
return size==0;
}
/**
* 取棧頂元素:不刪除棧頂元素
* @return
*/
public Object top() {
if (isEmpty())
throw new RuntimeException("棧空");
size--;
return data[size-1];
}
/**
* 入棧
* @param element
*/
public void push(Object element) {
//陣列已滿,擴容
if (size==data.length){
//擴容兩倍的新陣列
Object [] newData=new Object[size<<1];
//拷貝陣列
System.arraycopy(data,0,newData,0,size);
data=newData;
}
//棧頂上插入新元素
data[size]=element;
size++;
}
/**
* 出棧
* @return
*/
public Object pop() {
if (isEmpty())
throw new RuntimeException("棧空");
Object top=data[size-1];
data[size-1]=null;
size--;
return top;
}
}
時間複雜度分析:
- getSize():O(1)
- isEmpty():O(1)
- top():O(1)
- push():平均O(1),最壞(擴容)O(n)
- pop(): O(1)
3、鏈棧
鏈棧指的是鏈式儲存結構實現的棧。在前面的學習中,我們已經完成了單向連結串列的實現,程式碼如下,具體說明可檢視上一篇內容:
現在我們通過單向連結串列來實現鏈棧:
/**
* @Author 三分惡
* @Date 2020/8/26
* @Description
*/
public class ListStack implements Stack{
//單向連結串列
private SinglyLinkedList list;
/**
* 建構函式:初始化單向連結串列
*/
public ListStack(){
list=new SinglyLinkedList();
}
/**
* 獲取棧的容量
* @return
*/
public int getSize() {
return list.getSize();
}
public boolean isEmpty() {
return list.getSize()==0;
}
/**
* 取棧頂元素
* @return
*/
public Object top() {
//取列表的尾節點
return list.get(list.getSize()-1);
}
/**
* 入棧
* @param element
*/
public void push(Object element) {
//佇列尾插入
list.addTail(element);
}
/**
* 出棧
* @return
*/
public Object pop() {
int topIndex=list.getSize()-1;
//列表為節點
Object top=list.get(topIndex);
//刪除尾結點
list.remove(topIndex);
return top;
}
}
時間複雜度分析:
- getSize():O(1)
- isEmpty():O(1)
- top():O(1)
- push():O(1)
- pop(): O(1)
4、java中的棧
在Java中有一個java.util.Stack類,它實現了棧的結構。
它是Vector的子類,也自定義了一些作為棧的方法。
java.util.Stack類是Vector的子類,實際上並不建議使用它。
在Java中還有另外一個集合,可以作為棧使用,它就是LinkedList。LinkedList中實現了push、pop方法。具體可以檢視LinkedList原始碼閱讀筆記。
原始碼地址:https://gitee.com/LaughterYoung/data-structure-learn.git
上一篇:重學資料結構(一、線性表)
本文為學習筆記類部落格,主要資料來源如下!
參考:
【1】:鄧俊輝 編著. 《資料結構與演算法》
【2】:王世民 等編著 . 《資料結構與演算法分析》
【3】: Michael T. Goodrich 等編著.《Data-Structures-and-Algorithms-in-Java-6th-Edition》
【4】:嚴蔚敏、吳偉民 編著 . 《資料結構》
【5】:程傑 編著 . 《大話資料結構》
【6】:Java Stack 類