当前位置: 首页 > news >正文

#数据结构(二)--栈和队列

栈和队列

一栈

1.栈的顺序存储结构

特点:先进后出

栈是一种只能在一端进行插入或删除操作的线性表。

表中允许插入删除操作的一端为栈顶(top),表的另一端为栈底(bottom),

1 结构体的定义
#include <stdio.h>
typedef int ElemType;
#define MAX_SIZE 100typedef struct {int data[MAX_SIZE]; // 用于存储栈中的元素int top; // 栈顶指针,指向栈顶元素的索引
} SqStack;
2 初始化栈

栈顶指针赋值为-1

void InitStack(SqStack *&s) {s = (SqStack *) malloc(sizeof(SqStack));//申请一个顺序栈空间s->top = -1;//栈顶指针赋值为-1
}
3 销毁栈

释放节点空间

void DestroyStack(SqStack *&s) {free(s);
}
4 判断栈是否为空

指针为-1

bool StackEmpty(SqStack *&s) {return (s->top == -1);
}
5 进栈

先判断栈是否为满

注意先将指针++,再对栈顶元素进行赋值

bool PushStack(SqStack *&s, ElemType e) {if (s->top == MAX_SIZE - 1) {//栈满的情况return false;}s->top++;s->data[s->top] = e;//先加再赋值(s-data[++s->top])return true;
}
6 出栈

先对栈元素赋值,再将栈顶指针--

bool Pop(SqStack *&s, ElemType &e) {if (s->top == -1) {//栈空的情况return false;}e=s->data[s->top];s->top--;return true;
}
7 获取栈顶元素
bool GetTop(SqStack *s,ElemType &e){if (s->top==-1)return false;e=s->data[s->top];return true;
}
补充:共享栈
  1. 顺序栈采用一个数组存放栈中的元素。如果需要用到两个类型相同的栈,这时若为它们各自开辟一个数组空间,极有可能出现这样的情况:第一个栈已经满了,再进栈就溢出了,而另一个栈还有许多的空间。
  2. 共享栈是为了更有效地利用存储空间,两个栈的空间相互调节,只有在整个存储空间被占满时才会发生上溢。其存储数据的时间复杂度均为O(1),所以对存取效率没有什么影响。
  3. 栈空条件:栈0空为top==-1;栈1空为top1==MaxSize.
  4. 栈满条件:top==top1-1
  5. 元素进栈操作:进栈0操作为top0++;data[top0]=x;进栈1操作为top1--;data[top1]=x
  6. 元素出栈操作:出栈0操作为x=data[top0];top0--;出栈1操作为x=data[top1];top1++
  7. 在上述操作中,data数组表示共享栈的存储空间,top0和top1分别为两个栈的栈顶指针,这样该共享栈通过data,top0和top1来标识,也可以将他们设计为一个结构体类型。

2.栈的链式存储结构

栈中的数据元素的逻辑关系呈线性关系,所以栈可以像线性表一样采用链式存储结构

链栈通过单链表实现

不存在栈满上溢的情况,可以一直添加。

typedef struct linknode
{//定义链表节点数据ElemType data;//定义指针域,单链表的后继指针域struct linknode *next; 
}LiStack;

栈的四要素:

  • 栈空的条件:

s->next==NULL

bool StackEmpty(LiStack *s)
{return(s->next == NULL);
}
  • 栈满的条件:

链栈不存在满的情况

  • 进栈的条件

将带新元素的节点插入

//定义链表节点指针
LiStack *p;
//为新节点申请空间
p = (LiStack *)malloc(sizeof(LiStack));
//为新节点的数据区赋值
p -> data = e;
//头插法
//将新节点后继指针指向下一个节点 ,下一个节点插入前存放在头结点的后继指针
p -> next = s ->next;
//然后将头结点的后继指针指向新节点
s->next = p;
  • 出栈的条件:

将栈顶节点删除

//传入要出栈的链栈 , 传入要出栈的指针元素
bool Pop(LiStack *&s , ElemType &e)
{//用指针指向要出栈的元素,就是头结点的后继节点LiStack *p;//如果s->next 为空,则表明为空栈 ,无法出栈元素if(s->next == NULL){return false;}//如果经过上面条件的验证,s->next不为空,则接着往下走//先定位要出栈的元素p = s->next;	//头结点的后继节点e = p->data;	//栈顶数据传出//开始删除头结点的后继节点 p,也就是头结点指向要删除节点的下一个节点s->next = p->next;//然后释放 p 空间free(p);return true;
}

二 队列

特点:先进先出

队列只允许在一端进行插入另一端进行删除,允许插入的时队尾,允许删除的时队头

插入元素称为入队,删除元素称为出队。

1 顺序队列

  • 用一组地址连续的存储单元,以此存放从队头到队尾的数据元素,称为顺序队列。
  • 需要附设两个指针,一个队头指针(front)一个队尾指针(rear),分别指向队头队尾。

  • 初始时front和rear均为-1
  • 元素进队rear加1
  • front指向队首元素的前一位置
  • 队满条件:rear==MaxSize-1
  • 队空条件:front==rear
  • 进队操作:元素进队rear++,data[rear]=e
  • 出队操作:元素出队front++,e=data[front]

顺序队中实现队列的基本运算算法

结构体声明

typedef struct {ElemType data[MaxSize];//存放队中元素int front,rear;//队头和队尾指针
}SqQueue;
1 初始化

构造一个空队列q,将front和rear指针均设置为初始状态-1

void InitQueue(SqQueue *&q){q=(sqQueue *)malloc(sizeof(SqQueue));q->front=q->rear=-1;
}
2 入队

在队不满的情况下,先将队尾指针rear++,再将元素添加到该位置

bool enQueue(SqQueue *&q, ElemType e) {if (q->rear == MaxSize - 1)return false;q->rear++;q->data[q->rear] = e;return true;
}
3 出队

在队不空的情况下,将队首元素front++,再将该位置的元素赋值给e

bool deQueue(SqQueue *&q, ElemType &e) {if (q->front == q->rear)return false;q->front++;e = q->data[q->front];return true;
}

2 环形队列:

这是因为采用了rear=MaxSize-1作为队满条件的缘故,当出现这种情况可能会出现还有空间没有填满的情况。这种情况称为假溢出。

解决方案:环形队列

实际上地址一定是连续的不可能是环形的,这里是通过逻辑方式实现环形队列

  • rear=(rear+1)%MaxSize
  • front=(front+1)%MaxSize

  • 队空条件:rear==front
  • 队满条件:(rear+1)%MaxSize==front
  • 进队操作:rear=(rear+1)%MaxSize,并且将e放在rear处
  • 出队操作:front=(front+1)%MaxSize,将front位置e取出
  • 这种情况下会比原先少放一个元素

相关计算:

3 链队

  • 采用链表存储的称为链队。

相关操作:

单链表中数据节点类型DataNode声明如下

typedef struct qnode{ElemType data;struct qnode *next;
}DataNode;

链队节点类型LinkQuNode声明如下

typedef struct {DataNode *front;DataNode *rear;
}LinkQuNode;

链队四要素:

  • 链队为空的判断条件:front=rear=NULL
  • 链队为满的判断条件:不考虑
  • 链队插入的判断条件:将含e的单链表节点插入至链表结尾
  • 链队删除的判断条件:将单链表的首元节点删除

代码实现;

#include <stdio.h>
#include <cstdlib>typedef int ElemType;
typedef struct qnode {ElemType data;//存放元素struct qnode *next;//下一个节点指针
} DataNode;//数据节点的类型typedef struct {DataNode *front;DataNode *rear;
} LinkQuNode;
初始化:
void InitQueue(LinkQuNode *&q) {q = (LinkQuNode *) malloc(sizeof(LinkQuNode));q->front = q->rear = NULL;
}
判断是否为空:
bool QueueEmpty(LinkQuNode *q) {return (q->rear == NULL);
}
进队列
bool enQueue(LinkQuNode *&q, ElemType e) {DataNode *p;p = (DataNode *) malloc(sizeof(DataNode));p->data = e;p->next = NULL;if (q->rear == NULL)q->front = q->rear = p;else {q->rear->next = p;q->rear = p;}return true;
}
出队列
bool deQueue(LinkQuNode *&q, ElemType &e) {DataNode *t;if (q->rear == NULL)return false;t = q->front;if (q->front == q->rear)q->front = q->rear = NULL;elseq->front = q->front->next;e = t->data;free(t);return true;
}

4 双端队列

所谓双端队列是指两端都可以进行进队和出队的操作的队列,将队列的两端分别成为前端和后端,两端都可以进队和出队。

http://www.lryc.cn/news/468614.html

相关文章:

  • react18中的函数组件底层渲染原理分析
  • 提升产品竞争力之--IPD产品成本篇
  • 如何在Debian操作系统上安装Docker
  • ArrayList和Array、LinkedList、Vector 间的区别
  • Linux开发环境配置(下)
  • 系统开发常用命令合集
  • Termius工具在MAC的使用出现的问题:
  • 浅析Android中View的绘制流程
  • pikachu靶场- 文件上传unsafe upfileupload
  • java中this的内存原理是?
  • Matlab 车牌识别技术
  • CUDA-求最大值最小值atomicMaxatomicMin
  • 新的Midjourney就是一个增强版的Photoshop,你现在可以轻松的用它换衣服、换发型了
  • Linux系统安装软件的4种方式【源码配置编译安装、yum安装、rpm包安装、二进制软件包安装(.rpm/.tar.gz/.tgz/.bz2)】
  • 基于Spring Boot的洪涝灾害应急信息管理系统设计与实现
  • 912.排序数组(桶排序)
  • IPC 进程间通信 消息队列
  • opencv 图像翻转- python 实现
  • 使用DolphinScheduler接口实现批量导入工作流并上线
  • pycharm导出环境安装包列表
  • 分体式智能网关在现代电力物联网中的优势有哪些?
  • 第14篇:下一代网络与新兴技术
  • 物联网数据采集网关详细介绍-天拓四方
  • 2024软考网络工程师笔记 - 第10章.组网技术
  • C语言——字符串指针和字符串数组
  • 7-1回文判断(栈和队列PTA)
  • 使用 NCC 和 PKG 打包 Node.js 项目为可执行文件(Linux ,macOS,Windows)
  • LeetCode:2747. 统计没有收到请求的服务器数目(滑动窗口 Java)
  • 项目管理工具--【项目策划任务书】模板
  • 雷池社区版那么火,为什么站长都使用雷池社区版??