前言
前面說過,棧的本質是操作受限的線性表,也就是說,當我們在實現鏈棧時,其實需要實現的是一個鏈表,只是相比一般的鏈表少了許多操作而已。既然它本質是鏈表,我們在設計結構的時候,就需要考慮是否設置頭結點的問題,假如不設頭結點,那麼頭指針指向的位置就是棧頂;假如設了頭結點,那麼頭指針的next指針指向的結點(即首元結點)就是棧頂。本次採用的是無頭結點的結構。
鏈棧的指針指向問題
鏈式存儲離不開對地址的控制,因此想要掌握好鏈棧,需要對涉及的指針很瞭解。在鏈棧中(鏈表中也是一樣),一般涉及到二重指針,如圖所示。
C語言中有形參和實參的區別,假如我們想在函數裏真正改變某個參數的值,就要傳入該參數的地址。同理,假如想在函數中修改某個結點的值,那麼就不能僅僅傳入(StackNode)這個類型的值,而是需要傳入這個值的地址(StackNode *)。假如在函數中想修改這個地址(StackNode *),那麼就要再傳入這個地址的地址,它是(StackNode **)類型的。
在鏈表中只需要一個頭指針就可以找到整個鏈表,當鏈表爲空時,頭指針的指向爲空,當鏈表非空時,它指向首元結點的地址。因此頭指針設置爲結點的指針類型(StackNode *),爲了方便記錄,又給(StackNode *)取名爲(LinkStack),用來表示整個鏈表。這樣,(StackNode **)又可以寫成(LinkStack *)。
鏈棧的初始化
在主函數中,我們使用(LinkStack st)生成一個鏈棧,也就是生成了一個結點類型的指針變量。但是執行完該條語句之後,st的指向是混亂的。鏈棧的初始化就是將它的指向設置爲空,表示當前是空棧。
//初始化鏈棧
void initStack(LinkStack *s){
//將這個鏈棧初始化爲空棧
*s = NULL;
}
這時候,因爲要修改的是頭指針的指向(也就是值),而頭指針是(LinkStack)類型的,因此需要傳入的是頭指針的地址(LInkStack *)。
鏈棧的入棧
鏈棧的入棧也就是鏈表的頭部插入操作,它的操作可以大致分成兩步:
1.申請一個結點並賦值
2.進行頭部插入
鏈棧的出棧
鏈棧的出棧,也就是鏈表的頭部刪除,它的操作大致可以分成三步:
1.獲取棧頂元素的值
2.棧頂指針指向棧頂元素的下一個結點
3.釋放掉棧頂元素
全部代碼
LinkStack.h
#ifndef LinkStack_h
#define LinkStack_h
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define ElemType int
//結點的類型
typedef struct StackNode{
ElemType data;
struct StackNode *next;
}StackNode;
//棧的頭指針
typedef StackNode* LinkStack;
//初始化鏈棧
void initStack(LinkStack *s);
//入棧
void push(LinkStack *s,ElemType x);
//出棧
void pop(LinkStack *s);
//展示
void show(LinkStack *s);
//void show2(LinkStack s);
#endif /* LinkStack_h */
LinkStack.c
#include "LinkStack.h"
//初始化鏈棧
void initStack(LinkStack *s){
//將這個鏈棧初始化爲空棧
*s = NULL;
}
//入棧->本質就是鏈表的頭部插入
void push(LinkStack *s,ElemType x){
//申請一個結點空間
StackNode *t = (StackNode *)malloc(sizeof(StackNode));
//如果t爲空則警告
assert(t != NULL);
//賦值
t->data = x;
//頭部插入
t->next = *s;
*s = t;
}
//出棧
void pop(LinkStack *s){
//獲取首元結點(即棧頂元素
StackNode *p = *s;
if (p == NULL) {
printf("棧已空\n");
return;
}
//棧頂指針指向棧頂元素的下一個結點
*s = p->next;
//釋放掉棧頂元素
free(p);
}
//展示
void show(LinkStack *s){
StackNode *p = *s;
while (p != NULL) {
printf("%d\n",p->data);
p = p->next;
}
printf("\n");
}
//void show2(LinkStack s){
// StackNode *p = s;
// while (p != NULL) {
// printf("%d\n",p->data);
// p = p->next;
// }
// printf("\n");
//}
main.c
#include "LinkStack.h"
int main(int argc, const char * argv[]) {
LinkStack st;
initStack(&st);
for (int i = 1; i < 6; i ++) {
push(&st, i);
}
show(&st);
pop(&st);
show(&st);
}