棧(stack)是限定在表尾進(jìn)行插入或刪除操作的線性表。因此,棧的表尾端具有特殊的含義,稱為棧頂(top),相對(duì)應(yīng),表頭端的稱為棧底(bottom)。
為什么稱之為特殊的線性表,它的特殊之處在于只能允許在棧的頂端加入數(shù)據(jù)(push)和輸出數(shù)據(jù)(pop)。由于它是特殊的線性表,所以我們可以實(shí)現(xiàn)順序結(jié)構(gòu)的棧和鏈?zhǔn)浇Y(jié)構(gòu)的棧。
順序棧
順序棧是指利用順序存儲(chǔ)結(jié)構(gòu)實(shí)現(xiàn)的棧,即利用一組地址連續(xù)的存儲(chǔ)單元一次存放自棧底到棧頂?shù)臄?shù)據(jù)元素,同時(shí)設(shè)置 top 指針指向棧頂元素。
#include <stdio.h>
#include <stdlib.h>
#define STACK_INIT_SIZE 100
#define STACK_INCREMENT 2
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -1
#define INFEASIBLE 0
typedef int Status;
typedef int SElemType;
typedef struct {
SElemType *base; //棧底指針
SElemType *top; //棧頂指針
int stackSize;
}SqStack;
Status InitStack(SqStack *S);
Status DestroyStack(SqStack *S);
Status ClearStack(SqStack *S);
Status StackEmpty(SqStack S);
int StackLength(SqStack S);
Status GetTop(SqStack S, SElemType *e);
Status Push(SqStack *S, SElemType e);
Status Pop(SqStack *S, SElemType *e);
Status StackTraverse(SqStack S, void(*vi)(SElemType));
/**
* 操作結(jié)果:構(gòu)造一個(gè)空棧 S。
* @param S
* @return
*/
Status InitStack(SqStack *S) {
S->base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SqStack)); //開辟內(nèi)存空間
if (!S->base) {
exit(OVERFLOW); //開辟失敗
}
S->top = S->base;
S->stackSize = STACK_INIT_SIZE;
return OK;
}
/**
* 初始條件:棧 S 存在
* 操作結(jié)果:棧 S 被銷毀
* @param S
* @return
*/
Status DestroyStack(SqStack *S) {
if (S->base) {
free(S->base); //釋放棧底指針內(nèi)存空間
}
S->top = S->base = NULL; //棧底棧頂指針置為 NULL
S->stackSize = 0;
return OK;
}
/**
* 初始條件:棧 S 存在
* 操作結(jié)果:將棧 S 清為空棧
* @param S
* @return
*/
Status ClearStack(SqStack *S) {
S->top = S->base;
return OK;
}
/**
* 初始條件:棧 S 存在
* 操作結(jié)果:若 S 為空棧,返回 true,否則返回 false
* @param S
* @return
*/
Status StackEmpty(SqStack S) {
if (S.top == S.base) {
return TRUE;
} else {
return FALSE;
}
}
/**
* 初始條件:棧 S 存在
* 操作結(jié)果:返回 S 中元素的個(gè)數(shù),即棧的長(zhǎng)度
* @param S
* @return
*/
int StackLength(SqStack S) {
return (int) (S.top - S.base);
}
/**
* 初始條件:棧 S 存在且非空
* 操作結(jié)果:返回棧頂元素,不修改棧頂指針
* @param S
* @return
*/
Status GetTop(SqStack S, SElemType *e) {
if (S.top != S.base) {
*e = *(S.top - 1);
return OK;
}
return ERROR;
}
/**
* 初始條件:棧 S 存在
* 操作結(jié)果:插入元素 e 為新的棧頂元素
* @param S
* @param e
* @return
*/
Status Push(SqStack *S, SElemType e) {
if ((S->top - S->base) >= S->stackSize) { //判讀棧是否滿
S->base = (SElemType *)realloc(S->base, (S->stackSize + STACK_INCREMENT) * sizeof(SqStack));
if (!S->base) {
return ERROR;
}
S->top = S->base + S->stackSize;
S->stackSize += STACK_INCREMENT;
}
*S->top++ = e;
return OK;
}
/**
* 初始條件:棧 S 存在且非空
* 操作結(jié)果:刪除 S 的棧頂元素,并用 e 返回其值
* @param S
* @param e
* @return
*/
Status Pop(SqStack *S, SElemType *e) {
if (S->top == S->base) { //棧為空
return ERROR;
}
*e = *--S->top;
return OK;
}
/**
* 初始條件:棧 S 存在且非空
* 操作結(jié)果:從棧底到棧頂依次對(duì) S 的每個(gè)元素進(jìn)行訪問
* @param S
* @param vi
*/
Status StackTraverse(SqStack S, void(*vi)(SElemType)) {
while (S.top > S.base) { //遍歷棧中元素
vi(*S.base++);
}
printf("\n");
return OK;
}
/**
* 遍歷函數(shù)
* @param e
*/
void vi(SElemType e) {
printf("%d ", e);
}
/**
* 主函數(shù),測(cè)試程序
* @return
*/
int main() {
SqStack s;
SElemType e;
InitStack(&s);
printf("棧的長(zhǎng)度:%d\n", StackLength(s));
printf("棧是否為空:%d\n", StackEmpty(s));
Push(&s, 3);
Push(&s, 4);
Push(&s, 5);
Push(&s, 6);
StackTraverse(s,vi);
printf("棧的長(zhǎng)度:%d\n", StackLength(s));
printf("棧是否為空:%d\n", StackEmpty(s));
GetTop(s, &e);
printf("棧頂元素:%d\n", e);
printf("棧的長(zhǎng)度:%d\n", StackLength(s));
Pop(&s, &e);
StackTraverse(s, vi);
ClearStack(&s);
printf("棧的長(zhǎng)度:%d\n", StackLength(s));
printf("棧是否為空:%d\n", StackEmpty(s));
DestroyStack(&s);
}
上面測(cè)試代碼在 Clion 下的執(zhí)行結(jié)果如下圖所示。

鏈?zhǔn)綏?/h2>
鏈棧是采用鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)實(shí)現(xiàn)的棧。
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -1
#define INFEASIBLE 0
typedef int Status;
typedef int SElemType;
typedef struct StackNode {
SElemType data; //數(shù)據(jù)域
struct StackNode *next; //指針域
}StackNode, *LinkStack;
Status InitStack(LinkStack *S);
Status DestroyStack(LinkStack *S);
Status ClearStack(LinkStack *S);
Status StackEmpty(LinkStack S);
int StackLength(LinkStack S);
Status GetTop(LinkStack S, SElemType *e);
Status Push(LinkStack *S, SElemType e);
Status Pop(LinkStack *S, SElemType *e);
void StackTraverse(LinkStack S, void(*vi)(SElemType));
/**
* 操作結(jié)果:構(gòu)造一個(gè)空棧 S
* @param L
* @return
*/
Status InitStack(LinkStack *S) {
S = NULL; //構(gòu)造一個(gè)空棧,棧頂指針置空
return OK;
}
/**
* 初始條件:棧 S 存在
* 操作結(jié)果:棧 S 被銷毀
* @param S
* @return
*/
Status DestroyStack(LinkStack *S) {
LinkStack p;
while (*S) { //未到棧底
p = (*S)->next;
free(*S); //釋放棧頂空間
*S = p;
}
return OK;
}
/**
* 初始條件:棧 S 存在
* 操作結(jié)果:將棧 S 清空
* @param S
*/
Status ClearStack(LinkStack *S) {
LinkStack q, p = (*S)->next; // p 指向棧頂元素
while (p) { //未到棧底
q = p->next;
free(p);
p = q;
}
(*S) = NULL;
return OK;
}
/**
* 初始條件:棧 S 存在
* 操作結(jié)果:若 S 是空棧,返回 true,否則返回 false
* @param S
* @return
*/
Status StackEmpty(LinkStack S) {
if (S == NULL) {
return TRUE;
} else {
return FALSE;
}
}
/**
* 初始條件:棧 S 存在
* 操作結(jié)果:返回棧 S 長(zhǎng)度
* @param S
* @return
*/
int StackLength(LinkStack S) {
int i = 0; //計(jì)數(shù)器
LinkStack p = S; //p指向棧頂元素
while (p) { //未到棧底
i++;
p = p->next;
}
return i;
}
/**
* 初始條件:棧 S 存在且非空
* 操作結(jié)果;用 e 返回棧 S 的棧頂元素,不修改棧頂指針
* @param S
* @return
*/
Status GetTop(LinkStack S, SElemType *e) {
if (S) { //S 非空
*e = S->data;
return OK;
}
return ERROR;
}
/**
* 初始條件:棧 S 存在
* 操作結(jié)果:插入元素 e 為新的棧頂元素
* @param L
* @param e
* @return
*/
Status Push(LinkStack *S, SElemType e) {
LinkStack p;
p = (LinkStack)malloc(sizeof(struct StackNode)); //生成新結(jié)點(diǎn)
p->data = e;
p->next = *S; //將新結(jié)點(diǎn)插入棧頂
*S = p; //修改棧頂指針
return OK;
}
/**
* 初始條件:棧 S 存在且非空
* 操作結(jié)果:刪除棧頂元素,并用 e 返回且值
* @param S
* @param e
* @return
*/
Status Pop(LinkStack *S, SElemType *e) {
LinkStack p;
if (!S) {
return ERROR;
}
*e = (*S)->data; //返回棧頂元素
p = *S; //p 臨時(shí)保存棧頂空間,以備釋放
*S = (*S)->next; //修改棧頂指針
free(p); //釋放原棧棧頂空間
return OK;
}
/**
* 初始條件:棧 S 存在且非空
* 操作結(jié)果:從棧底到棧頂依次對(duì) S 中的每個(gè)元素進(jìn)行訪問
* @param S
* @param vi
*/
void StackTraverse(LinkStack S, void(*vi)(SElemType)) {
LinkStack p = S; //p 指向棧頂
while (p) {
vi(p->data);
p = p->next;
}
printf("\n");
}
void vi(SElemType e) {
printf("%d ", e);
}
/**
* 主函數(shù),測(cè)試程序
* @return
*/
int main() {
LinkStack s = NULL;
SElemType e;
InitStack(&s);
printf("棧的長(zhǎng)度:%d\n", StackLength(s));
printf("棧是否為空:%d\n", StackEmpty(s));
Push(&s, 3);
Push(&s, 4);
Push(&s, 5);
Push(&s, 6);
StackTraverse(s,vi);
printf("棧的長(zhǎng)度:%d\n", StackLength(s));
printf("棧是否為空:%d\n", StackEmpty(s));
GetTop(s, &e);
printf("棧頂元素:%d\n", e);
printf("棧的長(zhǎng)度:%d\n", StackLength(s));
Pop(&s, &e);
StackTraverse(s, vi);
ClearStack(&s);
printf("棧的長(zhǎng)度:%d\n", StackLength(s));
printf("棧是否為空:%d\n", StackEmpty(s));
DestroyStack(&s);
}
具體運(yùn)行效果和順序棧運(yùn)行效果一樣。
想要查看源碼可以訪問下面 github 鏈接,如果覺得不錯(cuò),請(qǐng)給個(gè) Star。
本文屬數(shù)據(jù)結(jié)構(gòu)系列持續(xù)更新中。