这里是嬉皮小河马的博客,你的目光就是我的兴奋剂,大家好,我是AKA河马龙。 今天和大家分享一些有关栈和队列的相关知识点,如果有错误,欢迎大家在评论区指出。那就请和我一起学习吧。
1.栈
1>.栈的定义和特点
栈是仅在表尾进行插入删除操作的线性表。表尾端称为栈顶,表头端称为栈底。
后进先出是栈最大的特点(可以想象枪里面的弹壳)。
2>.栈的类型定义
常见的栈的数据类型定义:
构建一个空栈:Initstack(*S)
栈S被销毁:DestroyStack(*S)
返回S的栈顶元素:GetTop(S)
插入元素e为新的栈顶元素:Push(*S,e)
删除元素S的栈顶元素,用e返回值:Pop(*S,e)
判断是否为空栈:StackEmpty(S)
3>.顺序栈的表示和实现
顺序栈是顺序存储结构的栈。
#define MAXSIZE 100
typedef struct
{
ElemType *base;//栈底指针
ElemType *top;//栈顶指针
int stacksize;//最大容量
}SqStack;
1>>.初始化
当S.top=-1的时候也可视为空栈。
Status InitStack(Sqstack &S)
{
S.base=new ElemType[MAXSIZE];
if(!S.base)
return 0;
S.top=S.base;//top初始为base,空栈
S.stacksize=MAXSIZE;
return 1;
}
2>>.入栈
Status Push(Sqstack *S,ElemType e)
{//插入元素e为新的栈顶元素
if(S.top-S.base==S.stacksize)//栈已满
return 0;
*S.top++=e;//将元素e压入栈顶,栈顶指针加1
return 1;
}
3>>.出栈
Status Pop(Sqstack *S,ElemType e)
{//删除S的栈顶元素,用e返回
if(S.top==S.base)//栈空
return 0;
e=*--S.top;//栈顶指针减1,将栈顶元素赋给e
return 1;
}
4>>.取栈顶元素
ElemType GetTop(Sqstack S)
{
if(S.top!=S.base)//栈不为空
return *(S.top-1);//返回栈顶元素的值,栈顶指针不变
}
顺序栈和顺序表一样受最大容量的限制,工作量大,因此在无法预估栈可能达到的最大容量时,我们选择使用下面的链栈。
4>.链栈的表示和实现
链栈是采用链式存储结构实现的栈。
由于栈的主要操作是栈顶插入删除,以链表的头部为栈顶最方便,不需要和单链表一样为了操作方便加一个头结点。
下面是链栈的存储结构:
typedef struct StackNode
{
ElemType data;
strcut StackNode *next;
}StackNode,*LinkStack;
1>>.初始化
Status InitStack(LinkStack *S)
{
S=NULL;//栈顶指针置空
return 1;
}
2>>.入栈
在入栈前不需要判断栈是否满,只要给入栈元素动态分配一个结点空间。
Status Push(LinkStack *S,ElemType e)
{
p=new StackNode;//生成新的结点
p->data=e;//将结点的数据域赋值为e
p->next=s;//新结点插入栈顶
S=p;//修改栈顶指针为p
return 1;
}
3>>.出栈
Status Pop(LinkStack *S,ElemType *e)
{//删除S的栈顶元素,用e返回
if(S==NULL)//栈为空
return 0;
e=S->data;//将栈顶元素赋给e
p=S;//用p临时保存栈顶元素空间,方便后面释放空间
S=S->next;//修改栈顶指针,指向下一位
delete p;//释放原栈顶元素的空间
return 1;
}
4>>.取栈顶元素
ElemType GetTop(LinkStack S)
{
if(S!=NULL)
return S->data;//返回栈顶元素的值,栈顶指针不变
}
2.队列
1>.队列的定义和特点
队列只允许在表的一端插入,另一端删除。允许插入的一端叫队尾,删除的一端叫队头。
先进先出是队列最大的特点(可以想象一下生活中排队)。
上厕所得排队,先到先上,队列就是这个道理。
2>.队列的类型定义
InitQueue(*Q):构建空队列Q
GetHead(Q):返回Q的队头元素
EnQueue(*Q,e):插入元素e为Q新的队尾元素
DeQueue(*Q,e):删除Q的队头元素,e返回其值
3>.循环队列的表示和实现
在非空队列中,头指针始终指向队头元素,尾指针始终指向队尾元素的下一个位置。
当如上图d所示状态不可以再插入新的元素,不然会溢出,由于队列“队尾入队,队头出队”受限操作,导致此时队列的实际可用空间并没有占满,称为“假溢出”, 我们用循环队列解决这种问题。
在循环队列中,头尾指针“依环状增1”操作用“模”运算实现。
Q.rear=(Q.rear+1)%MAXSIZE;//队尾指针加1
Q.front=(Q.front+1)%MAXSIZE;//队头指针加1
队列的顺序存储结构:
#define MAXSIZE 100
typedef struct
{
ElemType *base;//存储空间的基地址
int front;//头指针
int rear;//尾指针
}SqQueue;
1>>.初始化
Status InitQueue(SqQueue *Q)
{
Q.base=new ElemType[MAXSIZE];//分配一个最大容量MAXSIZE的数组空间
if(!Q.base)
return 0;
Q.front=Q.rear=0;//头指针和尾指针都为0,队列为空
return 1;
}
2>>.求队列长度
int QueueLength(SqQueue Q)
{
return(Q.rear-Q.front+MAXSIZE)%MAXSIZE;//返回Q的元素个数=队列长度
}
3>>.入队
Status EnQueue(SqQueue *Q,ElemType e)
{
if((Q.rear+1)%MAXSIZE==Q.front)//尾指针在循环意义加1==头指针,表面队满
return 0;
Q.base[Q.rear]=e;//新元素插入队尾
Q.rear=(Q.rear+1)%MAXSIZE;//队尾指针加1
return 1;
}
4>>.出队
Status DeQueue(SqQueue *Q,ElemType *e)
{//删掉Q的队头元素,用e返回其值
if(Q.front==Q.rear)//队空
return 0;
e=Q.base[Q.front];//保存队头元素
Q.front=(Q.front+1)%MAXSIZE;//队头指针加1
return 1;
}
5>>.取队头元素
ElemType GetHead(SqQueue Q)
{
if(Q.front!=Q.rear)//队非空
return Q.base[Q.front];//返回队头元素的值,队头指针不变
}
4>.链队列的链式表示和现实
1>>.初始化
Status InitQueue(LinkQueue *Q)
{
Q.front=Q.rear=new QNode;//生成新的结点为头结点,队头队尾指针都指向该结点
Q.front->next=NULL;//头结点的指针域置空
return 1;
}
2>>.入队
Status EnQueue(LinkQueue *Q,ElemType e)
{
p=new QNode;//入队元素分配结点空间,指针p指向
p->data=e;//将新结点数据域赋为e
p->next=NULL;
Q.rear->next=p;//将新结点插入队尾
Q.rear=p;//修改队尾指针
return 1;
}
3>>.出队
Status DeQueue(LinkQueue *Q,ElemType *e)
{
if(Q.front==Q.rear)//队空
return 0;
p=Q.front->next;//p指向队头元素
e=p->data;//e保存队头元素的值
Q.front->next=p->next;//修改头结点的指针域
if(Q.rear==p)//最后一个元素被删的话,队尾指针指向头结点
Q.rear=Q.front;
delete p;//释放原队头元素的空间
return 1;
}
4>>.取队头元素
ElemType GetHead(LinkQueue Q)
{
if(Q.front!=Q.rear)
return Q.front->next->data;//返回队头元素的值,队头指针不变
}
3.案例
1. 表达式括号匹配
题目描述:
假设一个表达式有英文字母(小写)、运算符(`+`、`-`、`*`、`/`)和左右小(圆)括号构成,以 `@` 作为表达式的结束符。请编写一个程序检查表达式中的左右圆括号是否匹配,若匹配,则输出 `YES`;否则输出 `NO`。表达式长度小于 $255$,左圆括号少于 $20$ 个。
## 输入格式
一行:表达式。
## 输出格式
一行:`YES` 或 `NO`。
## 提示
表达式长度小于 255个,左圆括号少于 20 个。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define Status int
#define MAXSIZE 255
typedef char ElemType;
typedef struct
{
ElemType* base;
ElemType* top;
int stacksize;
}Sqstack;
Status InitStack(Sqstack* S)
{
S->base = (ElemType*)malloc(MAXSIZE * sizeof(ElemType));
if (!S->base)
exit(1);
S->top = S->base;
S->stacksize = MAXSIZE;
return 1;
}
Status Push(Sqstack* S, ElemType e)
{
if (S->top - S->base == S->stacksize)
return 0;
*(S->top) = e;
S->top++;
return 1;
}
ElemType Pop(Sqstack* S, ElemType e)
{
if (S->top == S->base)
perror("Stack is empty!!!\n");
e = *S->top;
S->top--;
return e;
}
ElemType poll(Sqstack* S)
{
if (S->top != S->base)
return *(S->top - 1);
}
Status StackEmpty(Sqstack* S)
{
if (S->top == S->base)
return 1;
return 0;
}
Status Matching()
{
Sqstack S;
char ch;
InitStack(&S);
int flag = 1;
scanf("%c", &ch);
while (ch != '@' && flag)
{
switch (ch)
{
case'(':
Push(&S, ch);
break;
case')':
if (!StackEmpty(&S) && poll(&S) == '(')
Pop(&S, ch);
else flag = 0;
break;
}
scanf(" %c", &ch);
}
if (StackEmpty(&S) && flag == 1)
printf("YES");
else printf("NO");
free(S.base);
}
int main()
{
ElemType e;
Matching();
return 0;
}
2.约瑟夫问题
我现在还不会用栈和队列写题目
题目描述:
n个人围成一圈,从第一个人开始报数,数到 m的人出列,再由下一个人重新从 1 开始报数,数到 m 的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。
**注意:本题和《深入浅出-基础篇》上例题的表述稍有不同。书上表述是给出淘汰n-1名小朋友,而该题是全部出圈。**
## 输入格式
输入两个整数 $n,m$。
## 输出格式
输出一行 $n$ 个整数,按顺序输出每个出圈人的编号。
#include <stdio.h>
int main()
{
int i , n , m , a[10000] = {0} , count = 0 , count1 = 0 ;
scanf("%d %d", &n, &m);
for(i = 1 ; i <= n ; i++)
a[i] = i ;
for(i = 1 ; ; i++)
{
if(i > n) i = i % n ;
if(a[i] != 0)
count++;
if(count == m)
{
printf("%d ",a[i]);
a[i] = 0 ;
count = 0 ;
count1++;
}
if(count1==n-1)
break;
}
for(i = 1 ; i <= n ; i++)
{
if(a[i]!=0)
printf("%d\n", i);
}
return 0;
}
本章到此就结束啦,但是学习的脚步并不会就此停止哦。今日分享:“追风赶月莫停留,平芙尽处是春山”