数据结构【栈】

1、栈的概念

是一种特殊的线性表,只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
在这里插入图片描述
普通的线性表实现是有两个端口可以访问的,但是如果作为栈就要封闭一端,只能访问另一端。换言之,栈是一种抽象数据结构,是对现实世界对象的模拟。例如,像是餐厅中的一叠盘子,新的盘子总是会放在这一叠盘子的最上面,取得时候也是从最上面取,这种形式将其抽象出来就是栈,这是最合适的抽象方式。
所以,基于栈的操作非常简单:
1)将数据压入栈顶-push
2)将栈顶数据弹出-pop
3)查看栈顶数据-top
栈属于常见的一种线性结构,对于进栈和退栈而言,时间复杂度都为 O(1)。

借用他人描述的一个举例:
函数调用栈:A(B(C(D()))): 即 A 函数中调用 B,B 调用 C,C 调用 D;在 A 执行的过程中会将 A 压入栈,随后 B 执行时 B 也被压入栈,函数 C 和 D 执行时也会被压入栈。所以当前栈的顺序为:A->B->C->D(栈顶);函数 D 执行完之后,会弹出栈被释放,弹出栈的顺序为 D->C->B->A;
递归: 为什么没有停止条件的递归会造成栈溢出?比如函数 A 为递归函数,不断地调用自己(因为函数还没有执行完,不会把函数弹出栈),不停地把相同的函数 A 压入栈,最后造成栈溢出(Queue Overfloat)。

栈的ADT定义

栈的简单结构体定义:

typedef int ElemType
typedef struct Stack
{
    ElemType data[MAXSIZE];
    int top; //栈顶指针
}Stack;

栈的基本操作

1)InitStack(&S):初始化空栈S

2)StackEmpty(S):判断一个栈是否为空

3)Push(&S,x):进栈,若栈未满,则将x加入使之成为新栈顶

4)Pop(&S,&x):出栈,若栈非空,则将栈顶元素,并用x返回

5GetTop(S,&x):读栈顶元素,若栈顶元素非空,则用x返回栈顶元素

6DestroyStack(&S):销毁栈,并释放栈S占用的存储空间

2、顺序栈的结构体定义

采用顺序存储方式的栈称为顺序栈,是由一组地址连续的存储单元来存放自栈底至栈顶的数据元素,同时会有一个指针(top)指示当前栈顶的位置,并由一个maxsize指定容量即栈中元素额最大个数。

#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100
typedef int SElemType;

typedef  struct{
    SElemType *base;
    SElemType *top;
    int stacksize;//栈的最大容量
}SqStack;

其中,栈顶指针:top,初始时设置top = -1;
栈顶元素:data[top];
进栈操作:栈不满时,栈指针加1,再送值到栈顶元素;
出栈操作:栈非空时,先去栈顶元素值,再将栈顶指针减1;
栈空条件:top == -1;
栈满条件:top == MAXSIZE - 1;
栈长:top + 1;

2.1、栈的初始化

void init(SqStack &S){
	//定义一个数组,长度为MAXSIZE
    S.base=new SElemType[MAXSIZE];
    if(!S.base) exit; //如果不存在就退出
    S.top=S.base; //栈顶和栈底指向相等
    S.stacksize=MAXSIZE;  //栈的长度
}

2.2、入栈

void push(SqStack &S,SElemType e){
    if(S.top-S.base==S.stacksize) printf("该栈已满");
    *S.top=e;
    S.top++;
    printf("入栈成功");
}

2.3、出栈

void pop(SqStack &S,SElemType e){
    if(S.top==S.base) printf("该栈为空");
    S.top--;
    e=*S.top;
    printf("出栈成功");
}

2.4、取栈顶的值

SElemType  getTop(SqStack S){
    //栈非空时返回
    if(S.top!=S.base){
        return *(S.top-1);
    }
}

2.5、遍历栈内的所有元素

//从栈顶开始遍历
void printStackTop(SqStack S){
	printf("栈顶:");
	while(S.top!=S.base){
    	printf("%d ",*(S.top-1));   
    	S.top--;
	}
	printf("\n");
}

//从栈底开始遍历
void printStackBottom(SqStack S){
	printf("栈底:");
	SElemType *p=S.base;
	while(p!=S.top){
		printf("%d  ",*p);
		p++;
    }
    printf("\n");

}

3、栈与一般线性表的区别

在这里插入图片描述

4、栈的应用

应用场景:括号的匹配、递归运算、进制的转换等;
括号检测:
class Solution:
def isValid(self, s: str) -> bool:
stack = [“hh”]
for i in s:
if i in [“(”, “{”, “[”]:
stack.append(i)
elif (i == “)” and stack[-1] == “(”) or (i == “}” and stack[-1] == “{”) or (i == “]” and stack[-1] == “[”):
stack.pop()
else:
return False
return len(stack) == 1
代码说明:
首先我们使用栈来保存读取过的字符串中的括号,如果括号为"(“、”{“、”[“这三种则将其压入栈中,如果为”)“、”}“、”]"则需要与栈顶元素对比,如果括号匹配上了,则执行下一个循环,如果匹配错误,则直接返回无效。

参考资料:数据结构与算法基础-王卓老师

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值