目录
1.1 定义
一种特殊的线性表,只允许在固定的一端进行插入和删除元素的操作 。进行插入和删除的一端称为栈顶,另一端称为栈底。
栈中的元素遵循后进先出的原则。
例:若4个元素(1,2,3,4)入栈顺序为 1,2,3,4
则出栈顺序不可能为:
A. 4 3 2 1
B. 1 4 3 2
C. 3 1 4 2
D. 3 4 2 1
我们可以直接看出A选项是正确的一种出栈顺序,但是,对于其余的三个选项却感到摸不着头脑。
这是因为我们的思维受到了限制,要注意,“后进先出”不一定要所有的元素都入栈之后才能出栈,可以边进边出。
下面,我们以B选项为例分析:
故B成立!
经分析,易知,C选项错误!
1.2 创建动态数组
typedef int STDataType;
typedef struct Stack
{
int* a;
int top;
int capacity;
}ST;
1.3 栈初始化
void STInit(ST* ps) {
assert(ps);
ps->a = (STDataType)malloc(sizeof(STDataType) * 4);
ps->capacity = 4;
ps->top = 0;//栈顶元素的下一个位置
//ps->top=-1; 栈顶元素的位置
}
1.4 栈的删除
void STDestroy(ST* ps) {
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = 0;
ps->top = 0;
}
1.5 向栈中插入元素(压栈)
void STPush(ST* ps, STDataType x) {
assert(ps);
//若需要扩容
if (ps->top == ps->capacity) {
if (ps == NULL) {
perror("malloc fail");
return;
}
STDataType* tmp = (STDataType*)realloc(ps->a,sizeof(STDataType) * 2);
if (tmp == NULL) {
perror("realloc fail");
return;
}
ps->a = tmp;
ps->capacity *= 2;
}
//存放数据
ps->a[ps->top] = x;
ps->top++;
}
1.6 从栈中删除元素(出栈)
void STPop(ST* ps) {
assert(ps);
assert(!STEmpty(ps));
ps->top--;
}
1.7 判断栈是否为空
bool STEmpty(ST* ps) {
assert(ps);
return ps->top == 0;
}
1.8 返回栈顶元素
STDataType STTop(ST* ps) {
assert(ps);
assert(!STEmpty(ps));
return ps->a[ps->top - 1];
}
1.9 进行测试(在 Visual Studio 上运行)
头文件(Stack.h)
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
//构建动态数组
typedef int STDataType;
typedef struct Stack
{
int* a;
int top;
int capacity;
}ST;
void STInit(ST* ps);
void STPush(ST* ps, STDataType x);
void STPop(ST* ps);
int STsize(ST* ps);
bool STEmpty(ST* ps);
void STDestroy(ST* ps);
STDataType STTop(ST* ps);
源文件1(Stack.c)
#include"Stack.h"
void STInit(ST* ps) {
assert(ps);
if (ps == NULL) {
perror("malloc fail");
return;
}
ps->a =(STDataType*) malloc(sizeof(STDataType) * 4);
ps->capacity = 4;
ps->top = 0;//栈顶元素的下一个位置
//ps->top=-1; 栈顶元素的位置
}
void STDestroy(ST* ps) {
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = 0;
ps->top = 0;
}
void STPush(ST* ps, STDataType x) {
assert(ps);
//若需要扩容
if (ps->top == ps->capacity) {
if (ps == NULL) {
perror("malloc fail");
return;
}
STDataType* tmp = (STDataType*)realloc(ps->a,sizeof(STDataType) * 2);
if (tmp == NULL) {
perror("realloc fail");
return;
}
ps->a = tmp;
ps->capacity *= 2;
}
//存放数据
ps->a[ps->top] = x;
ps->top++;
}
void STPop(ST* ps) {
assert(ps);
assert(!STEmpty(ps));
ps->top--;
}
int STsize(ST* ps) {
assert(ps);
return ps->top;//此时,ps->top=0(初始时top指向栈顶元素的下一个位置)
}
bool STEmpty(ST* ps) {
assert(ps);
return ps->top == 0;
}
STDataType STTop(ST* ps) {
assert(ps);
assert(!STEmpty(ps));
return ps->a[ps->top - 1];
}
源文件2(Test.c)
#include"Stack.h"
int main() {
ST st;
STInit(&st);
STPush(&st,1);
STPush(&st,2);
STPush(&st,3);
STPush(&st,4);
while (!STEmpty(&st)) {
printf("%d ", STTop(&st));
STPop(&st);
}
STDestroy(&st);
return 0;
}
注意!栈的打印与线性表不同,由于后进先出的原则,栈在打印时,每打印一个必须将该元素出栈。
运行结果:
如果需要打印出其他结果,可以将源文件2作以修改:
#include"Stack.h"
int main() {
ST st;
STInit(&st);
STPush(&st,1);
STPush(&st,2);
printf("%d ", STTop(&st));
STPop(&st);
STPush(&st,3);
STPush(&st,4);
printf("%d ", STTop(&st));
STPop(&st);
while (!STEmpty(&st)) {
printf("%d ", STTop(&st));
STPop(&st);
}
STDestroy(&st);
return 0;
}
可以看出,元素2和元素4边进边出。
运行结果:
1.10 应用
习题:【数制转换】
输入一个正十进制数,输出与其等值的八进制数。
void STConversion() {
//定义栈
ST st;
//对栈进行初始化
STInit(&st);
//输入十进制数字N
int N;
scanf("%d", &N);
//将 N%8 压栈,之后将N/=8
while (N) {
STPush(&st, N % 8);
N /= 8;
}
//依次打印八进制数字
while (!STEmpty(&st)) {
printf("%d ", STTop(&st));
STPop(&st);
}
//毁栈
STDestroy(&st);
}
运行测试:
源文件2(Test.c)
#define _CRT_SECURE_NO_WARNINGS
#include"Stack.h"
void STConversion() {
ST st;
STInit(&st);
int N;
scanf("%d", &N);
while (N) {
STPush(&st, N % 8);
N /= 8;
}
while (!STEmpty(&st)) {
printf("%d ", STTop(&st));
STPop(&st);
}
STDestroy(&st);
}
int main() {
STConversion();
return 0;
}
注意!VS编译器认为scanf不安全,所以需要在文件头部添加
#define _CRT_SECURE_NO_WARNINGS
运行结果: