栈是什么呢?下个定义:栈是一种特殊的线性表
进行数据插入和删除操作的一端 称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。
栈的具体实现有两种选择:用顺序表(顺序栈)或者链表(链栈)。相对链表而言,顺序表的结构实现更优一些:数组在尾上插入数据的代价比较小。
顺序栈
声明
typedef int STDataType;
typedef struct Stack
{
int* a;
int top; //栈顶
int capacity; //容量
}ST;
初始化栈
此时需要明确top的含义,是指向栈顶元素还是指向栈顶元素的下一个元素,若指向栈顶元素,则初始化不开辟空间时应把top置为-1,若指向栈顶元素的下一个元素,则将top初始化为0。此处以top指向栈顶元素的下一个元素为例:
void STInit(ST* pst)
{
assert(pst);
pst->a = NULL;
pst->capacity = 0;
pst->top =0; //指向栈顶元素的下一个元素
//pst->top = -1; //指向栈顶元素
}
入栈
void STPush(ST* pst,STDataType x)
{
assert(pst);
if (pst->top == pst->capacity)
{
int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
STDataType* tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newcapacity);
if (tmp == NULL)
{
perror("realloc fail");
}
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;
}
销毁栈
void STDestroy(ST* pst)
{
assert(pst);
free(pst->a);
pst->a = NULL;
pst->top = pst->capacity = 0;
}
完整代码(顺序栈)
Stack.h
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int STDataType;
typedef struct Stack
{
int* 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;
pst->top =0; //指向栈顶元素的下一个元素
//pst->top = -1; //指向栈顶元素
}
void STDestroy(ST* pst)
{
assert(pst);
free(pst->a);
pst->a = NULL;
pst->top = pst->capacity = 0;
}
void STPush(ST* pst,STDataType x)
{
assert(pst);
if (pst->top == pst->capacity)
{
int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
STDataType* tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newcapacity);
if (tmp == NULL)
{
perror("realloc fail");
}
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);
STPush(&s, 2);
STPush(&s, 3);
STPush(&s, 4);
STPush(&s, 5);
printf("%d\n", STSize(&s));
while (!STEmpty(&s))
{
printf("%d ", STTop(&s));
STPop(&s);
}
//一种入栈顺序对应多种出栈顺序
printf("\n%d\n", STSize(&s));
STDestroy(&s);
return 0;
}
链栈
声明
typedef int STDataType;
typedef struct Stack
{
STDataType data;
struct Stack* next;
}ST;
初始化栈
基于单向不循环带头链表实现,链表首元素为有效元素个数
ST* initStack()
{
ST* s = (ST*)malloc(sizeof(ST));
s->data = 0;
s->next = NULL;
return s;
}
入栈
void push(ST* s, int data)
{
ST* st = (ST*)malloc(sizeof(ST));
st->data = data;
st->next = s->next;
s->next = st;
s->data++;
}
出栈
STDataType pop(ST* s)
{
if (isempty(s))
{
return -1;
}
else
{
ST* st = s->next;
STDataType data = st->data;
s->next = st->next;
free(st);
st = NULL;
s->data--;
return data;
}
}
栈中有效元素个数
STDataType gettop(ST* s)
{
if (isempty(s))
{
return -1;
}
else
{
return s->data;
}
}
判断栈空
bool isempty(ST* s)
{
if (s->data == 0 || s->next == NULL)
{
return true;
}
else
{
return false;
}
}
打印链栈
void printstack(ST* s)
{
ST* st = s->next;
while (st)
{
printf("%d->", st->data);
st = st->next;
}
printf("NULL\n");
}
销毁栈
void destroyStack(ST* s)
{
if (isempty(s))
{
return;
}
else
{
ST* st = s->next;
while (s&&st)
{
free(s);
s = st;
st = st->next;
}
free(s);
s = NULL;
return;
}
}
完整代码(链栈)
Stack.h
#pragma once
#include<stdbool.h>
#include<stdio.h>
#include<stdlib.h>
typedef int STDataType;
typedef struct Stack
{
STDataType data;
struct Stack* next;
}ST;
ST* initStack();
bool isempty(ST* s);
STDataType gettop(ST* s);
STDataType pop(ST* s);
void push(ST* s, int data);
void printstack(ST* s);
void destroyStack(ST* s);
Stack.c
#include"Stack.h"
ST* initStack()
{
ST* s = (ST*)malloc(sizeof(ST));
s->data = 0;
s->next = NULL;
return s;
}
bool isempty(ST* s)
{
if (s->data == 0 || s->next == NULL)
{
return true;
}
else
{
return false;
}
}
STDataType gettop(ST* s)
{
if (isempty(s))
{
return -1;
}
else
{
return s->data;
}
}
STDataType pop(ST* s)
{
if (isempty(s))
{
return -1;
}
else
{
ST* st = s->next;
STDataType data = st->data;
s->next = st->next;
free(st);
st = NULL;
s->data--;
return data;
}
}
void push(ST* s, int data)
{
ST* st = (ST*)malloc(sizeof(ST));
st->data = data;
st->next = s->next;
s->next = st;
s->data++;
}
void printstack(ST* s)
{
ST* st = s->next;
while (st)
{
printf("%d->", st->data);
st = st->next;
}
printf("NULL\n");
}
void destroyStack(ST* s)
{
if (isempty(s))
{
return;
}
else
{
ST* st = s->next;
while (s&&st)
{
free(s);
s = st;
st = st->next;
}
free(s);
s = NULL;
return;
}
}
test.c
#include"Stack.h"
int main()
{
ST* s = initStack();
push(s, 1);
push(s, 2);
push(s, 3);
push(s, 4);
printstack(s);
pop(s);
pop(s);
printstack(s);
if (isempty(s)==0)
{
printf("%d ", gettop(s));
}
destroyStack(s);
return 0;
}
练习题
看到这道题,大家可能第一想法是计算左右括号个数是否相等,但是题意不仅要我们满足数量匹配,还要满足顺序匹配,所以此路不通。那这题怎么解决呢?答案就是:用刚学的栈!
思路:
1.遇到左括号入栈
2.遇到有括号将栈顶左括号出栈看是否匹配
代码(真的很需要一个库,不想当小丑了):
typedef char STDataType;
typedef struct Stack
{
char* a;
int top;
int capacity;
}ST;
void STInit(ST* pst)
{
assert(pst);
pst->a = NULL;
pst->capacity = 0;
pst->top =0;
}
void STPush(ST* pst,STDataType x)
{
if (pst->top == pst->capacity)
{
int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
STDataType* tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newcapacity);
if (tmp == NULL)
{
perror("realloc fail");
}
pst->a = tmp;
pst->capacity = newcapacity;
}
pst->a[pst->top] = x;
pst->top++;
}
STDataType STTop(ST* pst)
{
assert(pst);
assert(pst->top > 0);
return pst->a[pst->top - 1];
}
void STPop(ST* pst)
{
assert(pst);
assert(pst->top > 0);
pst->top--;
}
bool STEmpty(ST* pst)
{
assert(pst);
return pst->top == 0;
}
bool isValid(char* s)
{
ST S;
STInit(&S);
while(*s)
{
if(*s=='['||*s=='('||*s=='{')
{
STPush(&S,*s);
s++;
}
else
{
if(STEmpty(&S))
{
return false;
}
char top=STTop(&S);
if(*s==']'&&top=='[')
{
STPop(&S);
s++;
}
else if(*s=='}'&&top=='{')
{
STPop(&S);
s++;
}
else if(*s==')'&&top=='(')
{
STPop(&S);
s++;
}
else
{
return false;
}
}
}
if(STEmpty(&S))
{
return true;
}
return false;
}
碎碎念总结
你所看见的栈一定是你以为的栈吗(我在云什么(◎_◎;)),上面提到的栈是数据结构中的栈,还有一个“栈”是语言/操作系统中的栈,指一块内存区域。那么栈溢出是哪个概念呢?是操作系统中的栈,栈溢出指空间不够,在递归程序返回条件有问题的时候会出现栈溢出。