資料結構第三章,棧、佇列、陣列,期末不掛科指南,第3篇
學習目標
自考重點、期末考試必過指南,這篇文章讓你理解什麼是棧、什麼是佇列、什麼是陣列
掌握棧、佇列的順序儲存結構和鏈式儲存結構
掌握棧、佇列的基本操作在順序儲存結構和鏈式儲存結構上的實現
掌握矩陣的壓縮儲存
今天核心我們們先把棧搞清楚
棧和佇列可以看做是特殊的
線性表
。它們的特殊性表現在它們的基本運算是線性表運算的子集,它們是運算受限
的線性表
棧
棧(Stack)是運算受限的線性表,這種線性表上的插入和刪除操作限定在表的一端進行
基本概念
棧頂:允許插入和刪除的一端
棧尾:另一端
空棧:不含任何資料元素的棧
棧頂元素:處於棧頂位置的資料元素
書中的例子比較形象
洗盤子,放盤子,每次只能從這一摞盤子的最上面拿走,這就是棧的基本操作
看重點:棧—> ==後進先出(Last In First Out) LIFO 原則 ==
所以棧被稱作 後進先出線性表 (後進先出表)
棧的插入和刪除運算 分為成為 進棧和 出棧
棧的基本運算
- 初始化 InitStack(S) 構造一個空棧S
- 判斷棧空 EmptyStack(S) 若棧為空,返回1,否則返回0
- 進棧Push(S,x) 將元素x插入棧S中
- 出棧Pop(S) 刪除棧頂元素
- 取棧頂GetTop(S) 返回棧頂元素
棧的順序實現
這裡面有兩個小知識點在寫程式碼之前需要掌握
空棧做出棧操作,會出現問題,叫做“下溢”
滿棧做進棧操作,會出現問題,叫做“上溢”
接下來我們就用C語言實現一下
初始化一個空棧
#include <stdio.h>
#include <stdlib.h>
// 宣告順序棧的容量
const int maxsize = 6;
struct seqtack{
int *data; //儲存棧中元素的陣列
int top; // 棧頂下標
};
typedef struct seqtack Seq;
// 初始化操作
Seq init(Seq s){
printf("初始化函式執行\n");
s.data = (int*)malloc(maxsize*sizeof(int));//動態分配儲存空間
if(!s.data){
printf("初始化失敗");
exit(0);
}
s.top = 0;
return s;
}
注意事項
初始化需要動態分配空間,並且需要讓top值等於0
判斷棧空
//判斷棧空
int empty(Seq s){
printf("判斷棧空\n");
if(s.top == 0){
return 1;
}
return 0;
}
這個比較簡單了,只需要判斷s.top值就可以了
進棧操作
//進棧操作
Seq push(Seq s,int x){
printf("進棧操作\n");
// 判斷棧是否滿了
if(s.top==maxsize-1){
printf("棧滿");
return s;
}
else{
printf("正在插入資料%d\n",x);
s.data[s.top] = x;
s.top++;
return s;
}
}
出棧操作
//出棧操作
Seq pop(Seq s,int *e){
if(empty(s)){
printf("棧空\n");
exit(0);
}
else{
*e = s.data[s.top-1];
s.top--;
return s;
}
}
進棧和出棧,這部分內容一定要好好的理解,其實也是比較簡單的,就是新增元素和刪除元素
列印棧中元素與獲取棧頂元素
// 列印棧中元素
void display(Seq s){
if(empty(s)){
printf("棧空\n");
exit(0);
}
else{
printf("開始列印\n");
int num = 0;
while(num < s.top){
printf("現在的元素是:%d\n",s.data[num++]);
}
}
}
// 獲取棧頂元素
int gettop(Seq s){
if(empty(s)){
exit("棧空\n");
}
else{
return s.data[s.top-1];
}
}
主函式測試程式碼
int main()
{
printf("程式碼執行中\n");
Seq s ;
s = init(s);
//插入兩個元素
s = push(s,1);
s = push(s,2);
display(s);
int e;
s = pop(s,&e);
printf("刪除的元素是:%d\n",e);
display(s);
return 0;
}
雙棧
書中還提到了雙棧,不過這個不是重點了,你要知道的是,雙棧的兩個棧底分別設定在陣列的兩端,棧頂分為是top1,top2
兩個棧頂在中間相遇,條件為 (top1+1=top2)發生上溢
判斷棧空條件呢?
一個是 top=0 另一個是top = maxsize -1 這個要注意一下即可
棧的連結實現
棧的連結實現稱為鏈棧。鏈棧 可以用帶頭結點的單連結串列來實現,鏈棧不用預先考慮容量的大小
鏈棧將連結串列頭部作為棧頂的一端,可以避免在實現資料“入棧”和“出棧”操作時做大量遍歷連結串列的耗時操作
連結串列的頭部作為棧頂,有如下的好處
- 入棧 操作時,只需要將資料從連結串列的頭部插入即可
- 出棧 操作時,只需要刪除連結串列頭部的首結點即可
結論:連結串列實際上就是一個只能採用頭插法插入或刪除的連結串列
例子:將元素1,2,3,4依次入棧,等價於將各元素採用頭插法依次新增到連結串列中
圖片來源網路
完整程式碼如下
由於比較簡單,直接貼上了
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int data; //資料域
struct node *next; //鏈域
} LkStk;
//初始化
void init(LkStk *ls){
printf("初始化操作\n");
ls = (LkStk *)malloc(sizeof(LkStk));
ls->next = NULL;
}
// 進棧
void push(LkStk *ls,int x){
printf("進棧操作\n");
LkStk *temp;
temp = (LkStk*)malloc(sizeof(LkStk));//給temp新申請一塊空間
temp->data = x;
temp->next = ls->next;
ls->next = temp;
printf("%d進棧成功\n",x);
}
int empty(LkStk *ls){
if(ls->next ==NULL){
return 1;
}
else return 0;
}
// 出棧
int pop(LkStk *ls){
LkStk *temp;
//判斷棧是否為空
if(!empty(ls)){
temp= ls->next; // 準備出棧的元素指向ls的下一結點
ls->next = temp->next; // 原棧頂的下一個結點稱為新的棧頂
printf("棧頂元素:%d\n",temp->data);
free(temp); //釋放原棧頂的結點空間
return 1;
}
return 0;
}
int main()
{
LkStk ls;
init(&ls);
push(&ls,1);
push(&ls,2);
pop(&ls);
pop(&ls);
return 0;
}
這就是鏈棧的基本進棧和出棧了,當然,我們還可以獲取一下棧頂元素
考試要點
在自考或者期末考試中,容易出現的一種題是手寫入棧和出棧
例如
設一個鏈棧的輸入序列為A、B、C,試寫出所得到的所有可能的輸出序列,即輸出出棧操作的資料元素序列
寫答案的時候,記住先進後出原則
從A開始寫
A進,A出,B進,B出,C進,C出
A進,B進,B出,C進,C出,A出
… …
繼續寫下去就可以了,一定不要出現A進,B進,B出,C進,A出 注意,A出不去,A前面有C呢
在來一個例題
如圖所示,在棧的輸入端元素的輸入順序為A,B,C,D,進棧過程中可以退棧,寫出在棧的輸出端以A開頭和以B開頭的所有輸出序列。
這個就是把A開頭和B開頭的都寫出來
- ABCD、ABDC、ACBD、ACDB、ADCB
- BACD、BADC、BCAD、BCDA、BDCA
主要仔細,就能寫對,套路就是,先進後出
小結
棧是隻能在一端(棧頂)進行插入和刪除運算的線性表,具有後進先出特徵。
以順序儲存結構實現的棧稱為順序棧,以鏈式儲存結構實現的棧稱為鏈棧。
順序棧需要預先定義棧的大小,在難以估計棧的大小時,可以採用鏈棧,鏈棧是用單連結串列實現。一般地,將棧頂設在連結串列的表頭一端,棧底設定在連結串列的表尾。棧適合與具有後進先出特徵的問題。
如程式實現遞迴,函式呼叫等。
關注我吧
相關文章
- JavaScript資料結構之陣列棧佇列JavaScript資料結構陣列佇列
- 資料結構—棧/佇列資料結構佇列
- 資料結構-佇列、棧資料結構佇列
- Java版-資料結構-佇列(陣列佇列)Java資料結構佇列陣列
- 資料結構-棧與佇列資料結構佇列
- 資料結構—棧和佇列資料結構佇列
- 資料結構(棧和佇列)資料結構佇列
- 【資料結構】--棧和佇列資料結構佇列
- 資料結構:棧與佇列資料結構佇列
- 資料結構之棧和佇列資料結構佇列
- 三、資料結構演算法-棧、佇列、優先佇列、雙端佇列資料結構演算法佇列
- 【資料結構】棧(Stack)和佇列(Queue)資料結構佇列
- 資料結構二之棧和佇列資料結構佇列
- 【資料結構】回顧表、棧、佇列資料結構佇列
- 畫江湖之資料結構【第二話:佇列和棧】佇列資料結構佇列
- 畫江湖之資料結構 [第二話:佇列和棧] 佇列資料結構佇列
- 資料結構-js實現棧和佇列資料結構JS佇列
- 重溫四大基礎資料結構:陣列、連結串列、佇列和棧資料結構陣列佇列
- 聊聊陣列與連結串列,棧與佇列陣列佇列
- 資料結構-佇列資料結構佇列
- 【資料結構-----佇列】資料結構佇列
- 資料結構 - 佇列資料結構佇列
- 【資料結構】棧和佇列的總結對比資料結構佇列
- 資料結構與演算法—稀疏陣列和佇列資料結構演算法陣列佇列
- python資料結構與演算法——棧、佇列與雙端佇列Python資料結構演算法佇列
- 學習JavaScript資料結構(一)——棧和佇列JavaScript資料結構佇列
- 資料結構與演算法-棧與佇列資料結構演算法佇列
- javascript的資料結構快速學-棧和佇列JavaScript資料結構佇列
- 資料結構-棧&佇列&Deque實現比較資料結構佇列
- php實現基本資料結構之棧、佇列PHP資料結構佇列
- 常見的線性列表結構---【陣列、連結串列、棧、佇列、堆】陣列佇列
- 畫江湖之資料結構【第二話:佇列和棧】棧資料結構佇列
- 畫江湖之資料結構 [第二話:佇列和棧] 棧資料結構佇列
- Java版-資料結構-佇列(迴圈佇列)Java資料結構佇列
- 線性結構 佇列與棧佇列
- 資料結構之「佇列」資料結構佇列
- 資料結構-佇列-樹資料結構佇列
- 資料結構基礎學習之(棧和佇列)資料結構佇列