什麼是棧
棧是一種用來存儲,邏輯關係爲“一對一”的線性存儲結構,棧的存取遵循“先進後出”原則。
棧有以下兩種特性:
- 棧只能從表的一端存取數據,另一端是封閉的
- 棧中,無論是存數據還是取數據,都必須遵循"先進後出"的原則,即最先進棧的元素最後出棧。拿圖 1 的棧來說,從圖中數據的存儲狀態可判斷出,元素 1 是最先進的棧。因此,當需要從棧中取出元素 1 時,根據"先進後出"的原則,需提前將元素 3 和元素 2 從棧中取出,然後才能成功取出元素 1。
棧頂與棧底:
- 棧的開口被稱爲棧頂,封口端被稱爲棧底。
- 棧頂元素是距離棧頂最近的元素
- 棧底元素是距離棧底最近的元素
進棧與出棧:
- 向棧中添加元素,被稱爲“進棧”(入棧或壓棧)
- 向棧中提取出指定元素,被稱爲“出棧”(彈棧)
棧的具體實現:
- 順序棧:採用順序存儲的結構模擬存取數據的特點
- 鏈棧:採用鏈式結構模擬棧
順序棧的代碼實現:
入棧:
//進棧,p爲數組,top值爲當前棧的棧頂位置
int push(int* p,int top,int elem){
++top;
p[top]=elem;
return top;
}
在最開始的時候,棧是空的,所以指針元素top = -1;然後向棧中添加元素1,以數組下標0端表示棧底,1被存儲在a[1]處,top值+1。
出棧:
//出棧
int pop(int * p,int top){
if (top==-1) {
printf("空棧");
return -1;
}
printf("出棧元素:%d\n",p[top]);
top--;
return top;
}
對於元素出棧的實現,top值-1即可
全部代碼:
#include <stdio.h>
//進棧
int push(int* a,int top,int elem){
a[++top]=elem;
return top;
}
//出棧
int pop(int * p,int top){
if (top==-1) {
printf("空棧");
return -1;
}
printf("出棧元素:%d\n",p[top]);
top--;
return top;
}
int main() {
int a[100];
int top=-1;
int i=0;
for(i=1;i<5;i++){
top=push(a, top, i);
}
for(i=4;i>-1;i--){
top=pop(a, top);
}
return 0;
}
鏈棧的基本操作
基本思想:
鏈棧的實現思路同順序棧類似,順序棧是將數順序表(數組)的一端作爲棧底,另一端爲棧頂;鏈棧也如此,通常我們將鏈表的頭部作爲棧頂,尾部作爲棧底。
將鏈表頭部作爲棧頂的一端,可以避免在實現數據 “入棧” 和 “出棧” 操作時做大量遍歷鏈表的耗時操作。但也正因爲此,所以入棧時,必須將數據從鏈表頭部插入,出棧時,也需要刪除鏈表頭部的首元素節點。
所以可以把鏈棧稱之爲:只能採用頭插法插入或刪除數據的鏈表
鏈棧入棧:
//鏈表中的節點結構
typedef struct lineStack{
int data;
struct lineStack * next;
}lineStack;
//stack爲鏈棧,a爲入棧的元素
lineStack* push(lineStack * stack,int a){
//創建存儲新元素的節點
lineStack * line=(lineStack*)malloc(sizeof(lineStack));
line->data=a;
//新節點與頭節點建立邏輯關係
line->next=stack;
//更新頭指針的指向
stack=line;
return stack;
}
鏈棧出棧:
若要讓棧中某元素出棧,則必須要該元素之前的所有元素都出棧,遵循“先進後出”原則。
代碼如下:
lineStack * pop(lineStack * stack){
if (stack) {
//定義一個指針指向棧頂節點
lineStack * p=stack;
//更新頭指針
stack=stack->next;
printf("出棧元素:%d ",p->data);
if (stack) {
printf("新棧頂元素:%d\n",stack->data);
}else{
printf("棧已空\n");
}
free(p);
}else{
printf("棧內沒有元素");
return stack;
}
return stack;
}