数据结构-栈与队列篇(已完结)


寻寻寻寻20.12.2更新
1、加入栈的PTA例题;
2、加入队列定义;
3、加入队列代码,并将所有分块代码合为一体,进行main函数检验;
4、更新了栈的代码,代码块合为一体,进行main检验。


寻寻寻寻20.12.3更新
1、加入队列PTA例题。
2、更新栈的括号匹配。


1、栈

(1)定义和特点

1、定义:只能在表的一端进行插入和删除的特殊线性表。
2、储存结构:可使用顺序栈或者链栈。
3、先进后出(FILO)后进先出(LIFO)。
4、一定要预设栈底指针(base)栈顶指针(top) 栈容量(stacksize)。
5、栈空标志极为top== base,栈满标志即为top == base+stacksize

(2)代码示例

以顺序栈为例
适时使用“引用”(&)能合理保护栈的不被破化;

#include <stdio.h>
#include <stdlib.h>
#define ElemType int
#define Status int 
#define ERROR 0
#define OK 1
#define OVERFLOW -1
#define MAXSIZE 3 
typedef struct{
	ElemType *base;
	ElemType *top;
	int stacksize;
}SqStack;
Status InitStack(SqStack &S){	//用malloc创建一个空栈,base指向栈底;
	//初始情况是top== base; 
	S.base=(ElemType*)malloc(sizeof(ElemType));
	if(!S.base) return OVERFLOW;
	S.stacksize = MAXSIZE;
	S.top=S.base;
	return OK;
}
bool StackEmpty(SqStack S){	//判断栈是否为空; 
	if(S.base==S.top)return true;
	else return false;
}
bool StackFull(SqStack S){	//判断栈是否为满 
	if(S.top-S.base==S.stacksize)return true;
	else return false;
}
int StackLength(SqStack S){	//返回此栈目前的长度(元素个数) 
		return S.top-S.base; 
} 
Status ClearStack(SqStack &S){	//清空栈 
	if(S.base)//这一句判断主要为防止栈S已经销毁增加程序鲁棒性。 
	S.top=S.base;
	return OK;
}
Status DestroyStack(SqStack &S){	//销毁栈 
	if (S.base)//同理上 
	{
		free(S.base);
		S.stacksize=0;
		S.base=S.top=NULL; 
	} 
	return OK; 
}
Status Push(SqStack &S,ElemType e){	//入栈 ,元素为e传入 
	if(StackFull(S))
		return ERROR;
	*S.top++=e;
	return OK;
}
Status Pop(SqStack &S,ElemType &e){	//出栈,元素用e传出 
	if(StackEmpty(S))
		return ERROR;
	e ==*--S.top;
	return OK; 
}
Status GetTop(SqStack S,ElemType &e){//返回栈顶元素 
	if(StackEmpty(S))
		return ERROR;
	e = *(S.top-1);
	return OK;
}
void StackTraverse(SqStack S){//遍历栈 
	for(ElemType i=0;S.base+i!=S.top;i++){
		printf("%d",S.base[i]);
	}
	putchar('\n');	
}
int main(){
	//栈的检验
	SqStack S;
	ElemType q;
	InitStack(S);
	Push(S,1); 
	Push(S,2);
	Push(S,3);
	if(StackFull(S))printf("%d个\n",StackLength(S));
	GetTop(S,q)
	printf("%d",q);Pop(S,q);printf("%d",q);
	StackTraverse(S);
	ClearStack(S);
	if(StackEmpty(S))printf("kong\n");
 	StackTraverse(S);
	DestroyStack(S);
}


(3)常见例题

1、前缀、中缀、后缀表达式表达式

在这里插入图片描述
优先级概念
在这里插入图片描述
后缀表达式求值伪代码
在这里插入图片描述在这里插入图片描述
原表达式转化为后缀表达式,
文字描述:

  1. 设立操作符栈;
  2. 设表达式的结束符为“#”,预设运算符栈的栈底为“#”;
  3. 若当前字符是操作数,则直接发送给后缀式。
    4)若当前运算符的优先数高于栈顶运算符,则进栈;否则,退 出栈顶运算符发送给后缀式;
    5)若当前字符是结束符,则自栈顶至栈底依次将栈中所有运算符发送给后缀式;
  4. “(”对它之前后的运算符起隔离作用,则若当前运算符为“(”时进栈;
  5. “)”可视为自相应左括弧开始的表达式的结束符,则从栈顶起,依次退出栈顶运算符发送给后缀
    式直至栈顶字符为"("止。
2、数制的转换

以十进制到8进制为例

void conversion(int N)
{//对于任意一个非负十进制数,打印输出与其等值的八进制数
   InitStack(S);	//初始化空栈S
   while(N)	//当N非零时,循环
   {
      Push(S,N%8);	//把N与8求余得到的八进制数压入栈S
      N=N/8;		//N更新为N与8的商
   }
   while(!StackEmpty(S))//当栈S非空时,循环
   {
      Pop(S,e);		//弹出栈顶元素e
      cout<<e;		//输出e
   }
}

3、括号的匹配

①初始化一个空栈S。
② 设置一标记性变量flag,用来标记匹配结果以控制循环及返回结果,1表示正确匹配,0表示错误匹配,flag初值为1。
③ 扫描表达式,依次读入字符ch,如果表达式没有扫描完毕或flag非零,则循环执行以下操作:
若ch是左括号“[”或“(”,则将其压入栈;
若ch是右括号“)”,则根据当前栈顶元素的值分情况考虑:若栈非空且栈顶元素是“(”,则正确匹配,否则错误匹配,flag置为0;
若ch是右括号“]”,则根据当前栈顶元素的值分情况考虑:若栈非空且栈顶元素是“[”,则正确匹配,否则错误匹配,flag置为0。
④ 退出循环后,如果栈空且flag值为1,则匹配成功,返回true,否则返回false。

(4)PTA例题

1、
若一个栈的输入序列为{1, 2, 3, 4, 5},则不可能得到{3, 4, 1, 2, 5}这样的出栈序列。

解释:3先出现,则1不可能到2前面,由栈的规则。

2、设一个堆栈的入栈顺序是1、2、3、4、5。若第一个出栈的元素是4,则最后一个出栈的元素必定是:

解释:由栈的规则可判断,1和5都是可能的。

3、将5个字母ooops按此顺序入栈,则有多少种不同的出栈顺序可以仍然得到ooops?

解释:标号123,则顺序可列出,123,132,213,231,321,因为还有一种312不合法,所以有五种。

2、队列

(1)定义及特点

1、限定在表的一端插入、另一端删除。 插入的那头就是队尾,删除的那头就是队头。也就是说只能在线性表的表头删除元素,在表尾插入元素。
2、先进先出 (FIFO结构)。
3、常使用循环队列,定义头指针front,rear,进行标记,以便进行操作。队空:frontrear ;队满 :(rear+1)%MAXfront;

4、链队列操作灵活,记住出队前后都要判空。

(2)代码示例

#include<stdio.h>
#include<stdlib.h>
#define ElemType int 
#define OK 1
#define Status int 
#define ERROR 0
#define MAXSIZE 100
#define OVERFLOW -1
typedef struct{
	ElemType *base;
	int front;
	int rear;
}SqQueue;
//循环线性储存队列 
void InitQueue(SqQueue &Q){//初始化队列 
 	Q.base=(ElemType*)malloc(MAXSIZE*sizeof(ElemType));
 	if(!Q.base)exit (OVERFLOW);
 	Q.front=Q.rear=0;
}
void DestroyQueue(SqQueue &Q){//销毁队列 
 	free(Q.base);
 	Q.base=NULL;
 	Q.front=Q.rear=0;
}
Status ClearQueue(SqQueue &Q ){//清空队列 
 	Q.front=Q.rear=0;
 	return 1;
}
bool QueueEmpty(SqQueue &Q ){//队列判满 
 	return Q.front==Q.rear?true:false; 
}
Status QueueLength( SqQueue &Q){//求队列长度 
	return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
}
ElemType GetHead(SqQueue Q ){//返回队首的元素 
	return Q.base[Q.front]; 
}
Status EnQueue( SqQueue &Q,ElemType e){//入队操作! 
	if((Q.rear+1)%MAXSIZE==Q.rear )return ERROR;
	Q.base[Q.rear]=e;
	Q.rear=(Q.rear+1)%MAXSIZE;
	return OK;
} 
Status DeQueue(SqQueue &Q,ElemType &e){//出队操作!
	 if(Q.front==Q.rear)return ERROR;
	 e=Q.base[Q.front];
	 Q.front=(Q.front+1)%MAXSIZE;
	 return OK;	
}
Status QueueTraverse(SqQueue Q){
	if(Q.base==NULL)return ERROR;
	for(int i=Q.front;i!=Q.rear;){
		printf("%d",Q.base[i]);
		i=(i+1)%MAXSIZE;
	}
	putchar('\n');
	return 1;
}
int main(){
	//队列的检验 
	SqQueue que;
	int q;
	InitQueue(que);
	EnQueue(que,1);
	EnQueue(que,2);
	EnQueue(que,3);
	EnQueue(que,4);
	QueueTraverse(que);
	DeQueue(que,q);
	printf("%d\n",q);
	QueueTraverse(que);
	if(QueueEmpty(que))printf("Queue is empty.\n");
	printf("%d\n%d\n",QueueLength(que),GetHead(que));
	QueueTraverse(que);
	ClearQueue(que);printf("Queue is empty.\n");
	QueueTraverse(que);
	DestroyQueue(que);
	QueueTraverse(que);
	return 0;
}

(3)PTA例题

1、在一个链队列中,front和rear分别为头指针和尾指针,则插入一个结点s的操作为
rear->next=s;rear=s;
2、若用大小为6的数组来实现循环队列,且当前front和rear的值分别为0和4。当从队列中删除两个元素,再加入两个元素后,front和rear的值分别为多少?

注意,头指针指向第一个要出队的元素,尾指针指向第最后一个元素的位置。

3、如果循环队列用大小为m的数组表示,队头位置为front、队列元素个数为size,那么队尾元素位置rear为:
(front+size-1)%m

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值