概念
- 栈的概念:栈是一种只能在一端进行数据的删除或增加的一种线性表,它的物理结构不一定是线性的。进入数据或删除数据的一端称为栈顶,另一端称为栈底。增加(进入)数据的过程称为进栈(压栈),删除数据的过程称为出栈。如图所示:
什么数据也没有就称为空栈,如图所示:
结构
- 栈的中文解释:存储货物或供旅客住宿的房屋。我们知道存储货物的箱子或旅馆只能从一端进出(取出),所以栈的数据也是如此特性。如图所示:
- 特点:因为栈只能从一端进行数据的存储或删除,所以栈是一种受限运算。因为栈是一种数据结构,是数据结构就要存储数据。所以,这就要想一个问题了——它的底层逻辑是以什么方式去存储数据呢?在数据结构中,我们用单链表或顺序表进行底层的数据存储,所以,上面咱们提到过——栈的物理空间不一定是。如果是以单链表为底层逻辑的话,物理空间就不是连续的,如果是以顺序表为底层逻辑的话,物理空间就是连续的。我们最常以顺序表为底层逻辑进行数据的存储。进行原因的解释:栈只能从一端进行数据的存储或删除,如果我们以单链表为底层的话,我们进行尾插数据就需要遍历每个结点,时间复杂度就会增加。我们进行数据删除的时候,也需要遍历每个结点,然后再释放结点空间,时间复杂度也较大。以顺序表为底层的话,我们进行尾插数据时,可以直接找到size位置进行数据的插入,时间复杂度为
O(1)
。相比于用单链表,时间复杂度降低了不少。综上所述:选择以顺序表为底层。
栈的实现
我们和单链表一样,也是给大家展示三个文件,通过代码给大家进行讲解,进行代码展示,
- 1:stack.h文件:
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int STDatatype;
//栈的结构形式
typedef struct stack
{
STDatatype* arr;
int top;
int capacity;
}ST;
//初始化
void STinit(ST* ps);
//判断是否为空栈
bool STcheck(ST*ps);
//栈的销毁
void STdestroy(ST*ps);
//进栈
void STpushback(ST* ps, STDatatype x);
//出栈
void STpop(ST*ps);
//栈取元素
STDatatype getdata(ST* ps); //每取一个数据就要出栈一个数据
//获取栈中的有效数据个数
int getyouxiaodata(ST* ps);
- 2:stack.c文件:
#include "stack.h"
//栈的初始化
void STinit(ST* ps)
{
assert(ps); //判断是否为空
ps->arr = NULL;
ps->capacity = ps->top = 0;
}
//判断是否为空栈
bool STcheck(ST* ps)
{
assert(ps); //判断是否为空
return ps->top == 0; //空栈返回 true ,否则false
}
//栈的销毁
void STdestroy(ST* ps)
{
assert(ps); //判断是否为空
if (ps->arr != NULL)
{
free(ps->arr);
ps->capacity = ps->top = 0;
}
}
//进栈
void STpushback(ST* ps, STDatatype x)
{
assert(ps); //判断是否为空
if (ps->top == ps->capacity)
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDatatype* temp = (STDatatype*)realloc(ps->arr, newcapacity * sizeof(STDatatype));
if (temp == NULL)
{
perror("realloc fail!");
exit(1);
}
ps->arr = temp;
ps->capacity = newcapacity;
}
ps->arr[ps->top] = x;
ps->top++;
}
//出栈
void STpop(ST* ps)
{
assert(ps); //判断是否为空
assert(!STcheck(ps)); //空栈报错
ps->top--;
}
//栈取元素
STDatatype getdata(ST* ps)
{
assert(ps); //判断是否为空
assert(!STcheck(ps));
return ps->arr[ps->top - 1]; //ps->top-1只是计算最终的结果,ps->top的值不会改变
}
//获取栈中的有效数据个数
int getyouxiaodata(ST* ps)
{
assert(ps); //判断是否为空
return ps->top;
}
- 3:test.c文件:
#define _CRT_SECURE_NO_WARNINGS 1
#include "stack.h"
void test()
{
ST st;
STinit(&st);
STpushback(&st,1);
STpushback(&st,2);
STpushback(&st,3);
STpushback(&st,4);
printf("%d\n", getyouxiaodata(&st));
STdestroy(&st);
/* STpop(&st);
STpop(&st);
STpop(&st);*/
//STpop(&st);
//STpop(&st);
}
int main()
{
test();
return 0;
}
算法题
LeetCode:有效的括号
先给大家看一下题目描述:
- 题目解读:这数组的元素全是一个个括号字符,只有对应的括号才能算是有效的括号。比如,[ { } ]这是个有效的括号,[ { ) ]为非有效的括号。我们可以运行用栈的思想,把左括号作为入栈元素,先进的元素后出。然后,再进行出栈,与其右括号进行匹配,就可以进行是否有效的括号的匹配。进行代码展示:
typedef char STDatatype;
// 栈的结构形式
typedef struct stack {
STDatatype* arr;
int top;
int capacity;
} ST;
// 栈的初始化
void STinit(ST* ps) {
assert(ps);
ps->arr = NULL;
ps->capacity = ps->top = 0;
}
// 判断是否为空栈
bool STcheck(ST* ps) {
assert(ps);
return ps->top == 0; // 空栈返回 true ,否则false
}
// 栈的销毁
void STdestroy(ST* ps) {
assert(ps);
if (ps->arr != NULL) {
free(ps->arr);
ps->capacity = ps->top = 0;
}
}
// 进栈
void STpushback(ST* ps, STDatatype x) {
assert(ps);
if (ps->top == ps->capacity) {
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDatatype* temp =
(STDatatype*)realloc(ps->arr, newcapacity * sizeof(STDatatype));
if (temp == NULL) {
perror("realloc fail!");
exit(1);
}
ps->arr = temp;
ps->capacity = newcapacity;
}
ps->arr[ps->top] = x;
ps->top++;
}
// 出栈
void STpop(ST* ps) {
assert(ps);
assert(!STcheck(ps)); // 空栈报错
ps->top--;
}
// 栈取元素
STDatatype getdata(ST* ps) {
assert(ps);
assert(!STcheck(ps));
return ps
->arr[ps->top - 1]; // ps->top-1只是计算最终的结果,ps->top的值不会改变
}
bool isValid(char* s) {
assert(s);
STDatatype* pi = s;
ST st;
STinit(&st);
while (*pi != '\0') {
if (*pi == '(' || *pi == '{' || *pi == '[')
STpushback(&st, *pi);
else {
if(STcheck(&st))
{
STdestroy(&st);
return false;
}
char ppt = getdata(&st);
if((*pi==']'&&ppt!='[')||(*pi=='}'&&ppt!='{')||(*pi==')'&&ppt!='('))
{
STdestroy(&st);
return false;
}
STpop(&st);
}
pi++;
}
if(STcheck(&st))
{
STdestroy(&st);
return true;
}
else
{
STdestroy(&st);
return false;
}
}
我们可以不用再写栈,直接把我们的代码进行copy就OK了。等我们学习了C++的STL库的时候,就可以不用自己手写栈了,可以直接调用STL库里面的栈,大大节省了时间。
彩蛋时刻!!!
歌曲:《Uncover 》
每章一句:别忘了,每一次的跌倒都是为了明天的自己更强!
感谢你能看到这里,点赞+关注+收藏+转发是对我最大的鼓励,咱们下期见!!!