数据结构——栈

概念

栈是一种只能在一端进行插入或删除操作的线性表。表中允许进行插入、删除操作的一端称为栈顶。(后进先出)

顺序栈

定义

栈的顺序存储结构(容易产生溢出)
typedef struct{
	SElemType* base;
	SElemType* top;
	int stacksize;//栈可用最大容量
}SqStack;

另外附设top、base指针,指示栈顶元素和栈底元素在顺序栈中的位置,通常top指示真正的栈顶元素之上的下标地址,stacksize表示栈可用的最大容量,指向同一数组的指针相减得到元素个数差。

空栈:base==top

满栈:top-base==stacksize;

栈满时的处理:
1、报错,返回操作系统
2、分配更大的空间(见入栈的算法)

基本操作

1、顺序栈的初始化

Status InitStack(SqStack &S) {
	S.base = (SElemType*)malloc(MAXSIZE * sizeof(SElemType));
	if (!S. base) exit(OVERFLOW);
	S.top = S.base;
	S.stacksize = MAXSIZE;
	return OK;
}

2、顺序栈判断是否为空

Status StackEmpty(SqStack S) {
	if (S.top == S.base)
		return TRUE;
	else
		return FALSE;
}

3、求顺序栈的长度

int StackLength(SqStack S) {
	return S.top - S.base;
}

4、清空顺序栈(清空元素)

Status ClearStack(SqStack& S) {
	if(S.base)
	S.top = S.base;
		return OK;
}

5、销毁顺序栈(清空元素并释放空间)

Status DestroyStack(SqStack& S) {
	if (S.base) {
		free(S.base);
		S.stacksize = 0;
		S.base = S.top = NULL;
	}
	return OK;
}

6、顺序栈入栈

Status push(SqStack& S,SElemType e) {
	if (S.top - S.base == S.stacksize) //栈满
		return ERROR;//处理方法一
		/*处理方法二
		if (S->top - S->base == S->stacksize) {//如果栈蛮,修改原先已经分配的内存的大小
		S->base = (ElemType*)realloc(S->base,(INCREASE+MAXSIZE) * sizeof(ElemType));
	S->top = S->base + S->stacksize;
	S->stacksize +=  INCREASE;
	}
	*/
	*S.top = e;
	S.top++;//可用*S.top++=e;代替这两句
	return OK;
}

7、顺序栈出栈

Status Pop(SqStack& S, SElemType e) {
	if (S.top == S.base)
		return ERROR;
	S.top--;
	e = *S.top;//栈顶在最上面的元素的上个位置,故要先--再取值
	return OK;
}

链栈

规定栈的所有操作都是在单链表的表头进行的,用带头节点的单链表表示链栈,第一个数据节点是栈顶节点,最后一个节点是栈底节点。

注意链栈中的指针指向的是前驱元素,而链表中指向的是后继元素。头指针就是栈顶,不需要头结点。空栈想到与头指针指向空。
在这里插入图片描述

定义

typedef struct StackNode {
	SElemType data;
	struct StackNode* next;
}StackNode,*LinkStack;

基本操作

1、链栈的初始化

void InitStack(LinkStack& S) {
	S = NULL;
}

2、判断是否为空

Status StackEmpty(LinkStack S) {
	if (S == NULL)
		return TRUE;
	else
		return FALSE;
}

3、入栈

Status Push(LinkStack& S, SElemType e) {
	StackNode* p;
	p =(StackNode*)malloc(sizeof(SElemType)) ;
	p->data = e;
	p->next = S;
	S = p;
	return OK;
}

4、出栈

Status Pop(LinkStack& S, SElemType& e) {
	if (S == NULL) return ERROR;
	StackNode* p;
	p = (StackNode*)malloc(sizeof(SElemType));
	e = S->data;
	p = S;
	S = S->next;
	free(p);
	return OK;
}

5、取栈顶元素

SElemType GetTop(LinkStack S) {   
 if (S != NULL)        
 return S->data;
 }

栈的应用

1、括号匹配

算法思想:
1、凡出现左括弧,则进栈;
2、凡出现右括弧,首先检查栈是否空。若栈空,则表明该“右括弧”多余
3、否则和栈顶元素比较,若相匹配,则“左括弧(栈顶元素)出栈”,否则表明不匹配
4、表达式检验结束时,若栈空,则表明表达式中匹配正确,否则表明“左括弧”有余。
在这里插入图片描述在这里插入图片描述

具体代码见NOJ07

2、中缀表达式计算器

算法思想:
1、首先置数据栈为空栈,表达式起始符“#”为算符栈的栈底元素
2、自左向右扫描表达式,读到操作数进OPND栈,读到运算符,则和OPTR栈顶元素比较(栈顶元素为c1,读到的算符为c2)
若c1<c2,则c2进栈继续扫描后面表达式;
若c1=c2,则(“=”),即括号内运算结束,将c1出栈,并且c2放弃,继续扫描后面表达式;
若c1>c2,则将c1出栈,并在操作数栈取出两个元素a和b按c1做运算,运算结果进OPND。
重复直到表达式求值完毕。

![在这里插入图片描述](https://img-blog.csdnimg.cn/2eb35649e6cc4b7785622d36d968f17f.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzU2MDQ2MDky,size_16,color_FFFFFF,t_70

3、表达式转换

算法思想:
1、设计一个操作符存储栈,用来存取当前读取到的操作符,运算数不存入栈,直接输出
2、比较栈顶元素从c1和将要入栈的操作符c2的优先级:
c1<c2:将c2入栈
c1>c2:弹出栈顶元素并输出
c1=c2:读取下一个操作符,并弹出栈顶元素
操作符优先级如下:
在这里插入图片描述在这里插入图片描述具体代码见NOJ08

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值