目录
栈
一. 栈的概念及结构
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。
栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。
二. 栈的实现
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。
1. 静态栈
// 下面是定长的静态栈的结构,实际中一般不实用,所以我们主要实现下面的支持动态增长的栈
typedef int STDataType;
#define N 10
typedef struct Stack
{
STDataType _a[N];
int _top; // 栈顶
}Stack;
2. 动态栈的实现
2.1 要实现的功能
// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{
STDataType* _a;
int _top; // 栈顶
int _capacity; // 容量
}Stack;
// 初始化栈
void StackInit(Stack* ps);
// 入栈
void StackPush(Stack* ps, STDataType data);
// 出栈
void StackPop(Stack* ps);
// 获取栈顶元素
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps);
// 销毁栈
void StackDestroy(Stack* ps);
2.2 具体实现
本次栈的实现我们基于顺序表,实现了动态扩容。
2.2.1 结构体
为了适配多种数据类型,这里使用typedef对数据类型进行重命名,便于进行统一修改。
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
2.2.2 初始化
由于涉及到操作数组的下标,top就有了两种表示方式,这里让top指向栈顶数据的下一位,否则无法分辨栈内是否有一个元素。或者让top最开始指向-1。
void STInit(ST* pst)
{
assert(pst);
pst->a = NULL;
pst->capacity = 0;
// top指向栈顶数据的下一个位置
pst->top = 0;
top指向栈顶数据
//pst->top = -1;
}
2.2.3 销毁
释放动态申请的空间,将top和容量置空即可。
void STDestroy(ST* pst)
{
assert(pst);
free(pst->a);
pst->a = NULL;
pst->capacity = 0;
pst->top = 0;
}
2.2.4 入栈
入栈应当将数据插入到数组尾部,然后top增加。
void STPush(ST* pst, STDataType x)
{
assert(pst);
//扩容
if (pst->top == pst->capacity)
{
int newcapacity = (pst->capacity == 0) ? 4 : (2 * pst->capacity);
STDataType* tmp = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc failed");
exit(1);
}
pst->a = tmp;
pst->capacity = newcapacity;
}
//存放数据
pst->a[pst->top] = x;
pst->top++;
}
2.2.5 出栈
出栈应当将数组尾部的数据删除,具体就是top前移。
void STPop(ST* pst)
{
assert(pst);
assert(pst->top > 0);
pst->top--;
}
2.2.6 返回栈顶元素
返回数组的top位置的前一个元素即可。如果top初始为-1,返回下标为top位置的数据即可。
STDataType STTop(ST* pst)
{
assert(pst);
assert(pst->top > 0);
return pst->a[pst->top - 1];
}
2.2.7 判空
返回top是否为0。如果top初始为-1,返回top是否为-1即可。
_Bool STEmpty(ST* pst)
{
assert(pst);
return pst->top == 0;
}
2.2.8 栈元素个数
返回top即可。如果top初始为-1,返回top+1即可。
int STSize(ST* pst)
{
assert(pst);
return pst->top;
}
三. 栈相关OJ题
有效的括号
题目链接:有效的括号
typedef char STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
//初始化
void STInit(ST* pst);
//销毁
void STDestroy(ST* pst);
//插入数据(入栈)
void STPush(ST* pst, STDataType x);
//删除数据(出栈)
void STPop(ST* pst);
//获取栈顶数据
STDataType STTop(ST* pst);
//判空
_Bool STEmpty(ST* pst);
//获取数据个数
int STSize(ST* pst);
void STInit(ST* pst)
{
assert(pst);
pst->a = NULL;
pst->capacity = 0;
// top指向栈顶数据的下一个位置
pst->top = 0;
top指向栈顶数据
//pst->top = -1;
}
void STDestroy(ST* pst)
{
assert(pst);
free(pst->a);
pst->a = NULL;
pst->capacity = 0;
pst->top = 0;
}
void STPush(ST* pst, STDataType x)
{
assert(pst);
//扩容
if (pst->top == pst->capacity)
{
int newcapacity = (pst->capacity == 0) ? 4 : (2 * pst->capacity);
STDataType* tmp = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc failed");
exit(1);
}
pst->a = tmp;
pst->capacity = newcapacity;
}
//存放数据
pst->a[pst->top] = x;
pst->top++;
}
void STPop(ST* pst)
{
assert(pst);
assert(pst->top > 0);
pst->top--;
}
STDataType STTop(ST* pst)
{
assert(pst);
assert(pst->top > 0);
return pst->a[pst->top - 1];
}
_Bool STEmpty(ST* pst)
{
assert(pst);
return pst->top == 0;
}
int STSize(ST* pst)
{
assert(pst);
return pst->top;
}
bool isValid(char* s)
{
ST st;
STInit(&st);
while(*s)
{
//左括号入栈
if(*s == '(' || *s == '[' || *s == '{')
{
STPush(&st, *s);
}
//右括号取栈顶匹配
else
{
if(STEmpty(&st))
{
STDestroy(&st);
return false;
}
char top = STTop(&st);
STPop(&st);
//判断不匹配
if(top == '(' && *s != ')' \
|| top == '[' && *s != ']' \
|| top == '{' && *s != '}')
{
STDestroy(&st);
return false;
}
}
++s;
}
bool ret = (STEmpty(&st));
STDestroy(&st);
return ret;
}
四. 概念选择题
- 一个栈的初始状态为空。现将元素1、2、3、4、5、A、B、C、D、E依次入栈,然后再依次出栈,则元素出栈的顺序是( )。
A 12345ABCDE
B EDCBA54321
C ABCDE12345
D 54321EDCBA - 若进栈序列为 1,2,3,4 ,进栈过程中可以出栈,则下列不可能的一个出栈序列是()
A 1,4,3,2
B 2,3,4,1
C 3,1,4,2
D 3,4,2,1
答案:
- B
- C
五. 参考代码
Stack.h
#pragma once
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
//初始化
void STInit(ST* pst);
//销毁
void STDestroy(ST* pst);
//插入数据(入栈)
void STPush(ST* pst, STDataType x);
//删除数据(出栈)
void STPop(ST* pst);
//获取栈顶数据
STDataType STTop(ST* pst);
//判空
_Bool STEmpty(ST* pst);
//获取数据个数
int STSize(ST* pst);
Stack.c
#include "Stack.h"
void STInit(ST* pst)
{
assert(pst);
pst->a = NULL;
pst->capacity = 0;
// top指向栈顶数据的下一个位置
pst->top = 0;
top指向栈顶数据
//pst->top = -1;
}
void STDestroy(ST* pst)
{
assert(pst);
free(pst->a);
pst->a = NULL;
pst->capacity = 0;
pst->top = 0;
}
void STPush(ST* pst, STDataType x)
{
assert(pst);
//扩容
if (pst->top == pst->capacity)
{
int newcapacity = (pst->capacity == 0) ? 4 : (2 * pst->capacity);
STDataType* tmp = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc failed");
exit(1);
}
pst->a = tmp;
pst->capacity = newcapacity;
}
//存放数据
pst->a[pst->top] = x;
pst->top++;
}
void STPop(ST* pst)
{
assert(pst);
assert(pst->top > 0);
pst->top--;
}
STDataType STTop(ST* pst)
{
assert(pst);
assert(pst->top > 0);
return pst->a[pst->top - 1];
}
_Bool STEmpty(ST* pst)
{
assert(pst);
return pst->top == 0;
}
int STSize(ST* pst)
{
assert(pst);
return pst->top;
}
test.c
#include "Stack.h"
int main()
{
ST s;
STInit(&s);
STPush(&s, 1);
printf("%d ", STTop(&s));
STPush(&s, 2);
printf("%d ", STTop(&s));
STPush(&s, 3);
printf("%d ", STTop(&s));
STPush(&s, 4);
printf("%d ", STTop(&s));
STPush(&s, 5);
printf("%d ", STTop(&s));
//printf("%d ", STTop(&s));
//STPop(&s);
//printf("%d ", STTop(&s));
//STPop(&s);
//printf("%d ", STTop(&s));
//STPop(&s);
//printf("%d ", STTop(&s));
//STPop(&s);
//printf("%d ", STTop(&s));
//STPop(&s);
while (!STEmpty(&s))
{
printf("%d ", STTop(&s));
STPop(&s);
}
STDestroy(&s);
return 0;
}