数据结构之栈和队列

这里是嬉皮小河马的博客,你的目光就是我的兴奋剂,大家好,我是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;
}

本章到此就结束啦,但是学习的脚步并不会就此停止哦。今日分享:“追风赶月莫停留,平芙尽处是春山”

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值