什麼是棧

百度百科
上,棧是這麼定義的:
- 棧(stack)又名
,它是一種堆棧
的運算受限
。限定僅在線性表
和表尾進行插入
操作的線性表。這一端被稱為删除
,相對地,把另一端稱為棧頂
。向一個棧插入新元素又稱作棧底
,它是把新元素放到棧頂元素的上面,使之成為新的棧頂元素;從一個棧删除元素又稱作進棧、入棧或壓棧
,它是把棧頂元素删除掉,使其相鄰的元素成為新的棧頂元素。出棧或退棧
稍微介紹一下關鍵名詞:
- 運算受限:也就是這個表你不能随便的删除插入。隻能按照它的規則進行插入删除。比如棧就隻能在一端就行插入和删除。同樣,隊列也是運算受限,隻能在兩天操作。
- 線性表:棧也是一種線性表,前面詳細介紹過線性表,它表達的是一種資料的邏輯關系。也就是在棧内各個元素是相鄰的。當然在具體實作上也分
,他們的實體存儲結構不同。但是邏輯結構(數組和連結清單實作
)相同。實作的目的
- 棧頂棧底: 這個描述是偏向于邏輯上的内容,因為大家知道
更容易,而數組在末尾插入删除
更容易。是以數組可以用末尾做棧頂,而連結清單可以頭做棧頂。單連結清單通常在頭插入删除
棧的應用:
- 棧的應用廣泛,比如你的程式執行檢視調用堆棧、加減運算、甚至在搜尋算法中dfs,替代遞歸等等。是以棧也是必須掌握的一門資料結構。很多規範也是棧,比如上圖放書拿書一樣!
設計與介紹
這裡我們介紹數組實作的棧和連結清單實作的棧。
數組實作
結構設計
- 對于數組來說,我們模拟棧的過程很簡單,因為棧是
,我們很容易在數組的末尾進行插入和删除。是以我們標明後進先出
。是以對于一個棧所需要的基礎元素是 一個data數組和一個top(int)表示棧頂位置。末尾為棧頂
- 那麼初始化以及構造的函數代碼為:
private T data[];
private int top;
public seqStack() {
data=(T[]) new Object[10];
top=-1;
}
public seqStack(int maxsize)
{
data=(T[]) new Object[maxsize];
top=-1;
}
複制
push插入
棧的核心操作之一push:入棧操作。
- 如果top<數組長度-1。入棧。
top++;a[top]=value;
- 如果top==數組長度-1;棧滿。
pop彈出并傳回首位
- 如果top>=0,棧不為空,可以彈出。
return data[top--];
- 如下圖,本來棧為1,2,3,4(棧頂),執行pop操作。top變為3的位置并且傳回4;
其他操作
- 其他例如peek操作時傳回棧頂
.是以隻需滿足題意時候不彈出
即可。return data[top]
連結清單實作
有數組實作,連結清單當然也能實作。對于棧的運算。大緻可以分為兩種思路:
- 像數組那樣在尾部插入删除。大家都知道連結清單效率
。而查詢到尾部效率很低。而我們就算用了尾指針,可以解決尾部插入效率。但是依然無法解決删除效率(删除需要找到前節點).還需要雙向連結清單。前面雖然詳細介紹過雙向連結清單,但是這樣未免太複雜!低在查詢
- 是以我們采用帶頭節點的單連結清單在頭部插入删除,把頭部當中棧頂,這樣精了很多。插入直接在頭節點後插入。而删除也直接删除頭節點後第一個元素即可。
結構設計
長話短說,短話不說
。直接上代碼就懂。
連結清單的節點:
static class node<T>
{
T data;
node next;
public node() {
}
public node(T value)
{
this.data=value;
}
}
複制
基本結構:
public class lisStack <T>{
int length;
node<T> head;//頭節點
public lisStack() {
head=new node<>();
length=0;
}
//其他方法
}
複制
push插入
與單連結清單頭插入一緻,如果不太了解請先看筆者隊線性表介紹的。
和數組形成的棧有個
差別
。就是理論上棧沒有大小限制(不突破記憶體系統限制)。不需要考慮是否越界。
- 節點
入棧team
- 空連結清單入棧
head.next=team;
- 非空入棧
team.next=head.next;head.next=team;
pop彈出
與單連結清單頭删除一緻,如果不太了解請先看筆者隊線性表介紹的。
和數組同樣需要判斷是否為空。
- 節點
出棧team
- head指向team後驅節點。
。如果為1個節點,team.next=null.執行完畢head.next=null。變為空,滿足條件。不需要考慮連結清單是否為1個節點
其他操作
- 其他例如peek操作時傳回棧頂
.是以隻需判空滿足題意時候不彈出
即可。而length你可以周遊連結清單傳回長度,也可以動态設定(本文采取)跟随棧長變化。其他操作直接看api。return head.next.data
實作代碼
數組實作
package 隊棧;
public class seqStack<T> {
private T data[];
private int top;
public seqStack() {
data=(T[]) new Object[10];
top=-1;
}
public seqStack(int maxsize)
{
data=(T[]) new Object[maxsize];
top=-1;
}
boolean isEmpty()
{
return top==-1;
}
int length()
{
return top+1;
}
boolean push(T value) throws Exception//壓入棧
{
if(top+1>data.length-1)
{
throw new Exception("棧已滿");
}
else {
data[++top]=value;
return true;
}
}
T peek() throws Exception//傳回棧頂元素不移除
{
if(!isEmpty())
{
return data[top];
}
else {
throw new Exception("棧為空");
}
}
T pop() throws Exception
{
if(isEmpty())
{
throw new Exception("棧為空");
}
else {
return data[top--];
}
}
public String toString()
{
if(top==-1)
{
return "";
}
else {
String va="";
for(int i=top;i>=0;i--)
{
va+=data[i]+" ";
}
return va;
}
}
}
複制
連結清單實作
package 隊棧;
public class lisStack <T>{
static class node<T>
{
T data;
node next;
public node() {
}
public node(T value)
{
this.data=value;
}
}
int length;
node<T> head;//頭節點
public lisStack() {
head=new node<>();
length=0;
}
boolean isEmpty()
{
return head.next==null;
}
int length()
{
return length;
}
public void push(T value) {//近棧
node<T> team=new node<T>(value);
if(length==0)
{
head.next=team;
}
else {
team.next=head.next;
head.next=team;}
length++;
}
public T peek() throws Exception {
if(length==0) {throw new Exception("連結清單為空");}
else {//删除
return (T) head.next.data;
}
}
public T pop() throws Exception {//出棧
if(length==0) {throw new Exception("連結清單為空");}
else {//删除
T value=(T) head.next.data;
head.next=head.next.next;//va.next
length--;
return value;
}
}
public String toString(){
if(length==0) {return "";}
else {
String va="";
node team=head.next;
while(team!=null)
{
va+=team.data+" ";
team=team.next;
}
return va;
}
}
}
複制
測試
總結
- 棧的邏輯比較
。很容易了解,實作起來也相對容易。但是要注意數組情況的界限問題。簡單
-
,相比棧,隊列内容更豐富一些。難度也稍大一些。後面将介紹隊列
- 如果有
還請不好需要改進
!指出