3.数据结构期末复习之栈和队列

news2025/5/21 20:36:58

1.栈的应用

  1.括号匹配问题(还有确定他们的符号优先级) 
            如 2+((3+2) * 3) /3 
            扫描到左括号入栈,右括号入另外一个栈,如果两个栈数量相同,则是匹配的,不保存,不然去找最少的栈,出来提示报错
  2.十进制转2进制  如 23转二进制10111,需要栈辅助 每次除2的余数倒过来写

在这里插入图片描述

   3.main函数的嵌套调用(函数调用栈) 如

在这里插入图片描述

 4.idea开发工具的 ctr+z撤回上一步  比如我写了 1 2 3代码然后入栈,出来3 2 1可以回到我原来写1的代码

2.什么是栈? 限定一端 插/删 的线性表 特点:后进先出(LIFO)
在这里插入图片描述
3.顺序栈的实现c语言代码

#include <stdio.h>
#include <stdlib.h>
/*将顺序栈的存储结构定义和各个函数定义放到这里*/
#define StackSize 100              /*假定栈元素最多100个*/
typedef int DataType;              /*定义栈元素的数据类型,假设为int型*/
typedef struct {
	DataType data[StackSize];        /*存放栈元素的数组*/
	int top;                        /*栈顶位置,栈顶元素在数组中的下标*/
} SeqStack;
void InitStack(SeqStack *S) { //初始化栈顶为 -1
	S->top = -1;
}
int Push(SeqStack *S, DataType x) { //入栈,就是让top+1非常简单,但是要注意是否超过最大的个数
	if (S->top == StackSize - 1) {
		printf("上溢错误,插入失败\n");
		return 0;
	}
	S->data[++S->top] = x;
	return 1;
}
int Pop(SeqStack *S, DataType *ptr) { //让top-1,如果top<0没有元素了
	if (S->top == -1) {
		printf("下溢错误,删除失败\n");
		return 0;
	}
	*ptr = S->data[S->top--];
	return 1;
}
int GetTop(SeqStack *S, DataType *ptr) {//得到顶部的元素,如果是负数失败
	if (S->top == -1) {
		printf("下溢错误,取栈顶失败\n");
		return 0;
	}
	*ptr = S->data[S->top];
	return 1;
}
int Empty(SeqStack *S) { //判断栈是否为空,top==-1为空
	if (S->top == -1) return 1;                    /*栈空则返回1*/
	else return 0;
}
int main( ) {
	DataType x;
	SeqStack S;                          /*定义结构体变量S为顺序栈类型*/
	InitStack(&S);                                 /*初始化顺序栈S*/
	printf("对15和10执行入栈操作,");
	Push(&S, 15);
	Push(&S, 10);
	if (GetTop(&S, &x) == 1)
		printf("当前栈顶元素为:%d\n", x);             /*输出当前栈顶元素10*/
	if (Pop(&S, &x) == 1)
		printf("执行一次出栈操作,删除元素:%d\n", x);    /*输出出栈元素10*/
	if (GetTop(&S, &x) == 1)
		printf("当前栈顶元素为:%d\n", x);             /*输出当前栈顶元素15*/
	printf("请输入待入栈元素:");
	scanf("%d", &x);
	Push(&S, x);
	if (Empty(&S) == 1)
		printf("栈为空\n");
	else
		printf("栈非空\n");                   /*栈有2个元素,输出栈非空*/
	return 0;
}

4.链栈实现代码
//原理解析,先设计一个空的top 放栈顶元素,然后
在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
/*将单链表的结点结构定义和链栈的各个函数定义放到这里*/
typedef int DataType;          /*定义线性表的数据类型,假设为int型*/
typedef struct Node {          /*定义单链表的结点类型*/
	DataType data;
	struct Node *next;
	//struct Node *top;
} Node;
Node *InitStack( ) {   //初始化栈, new一个节点,然后->next指向NULL
	Node *top = NULL;
	top = (Node*)malloc(sizeof(Node));
	top->next = NULL;
	return top;
}
void DestroyStack(Node *top) {  //临时指针p指向top,top不为null移动到下一个,删除p节点,p又指向top
	Node *p = top;
	while (top != NULL) {             /*依次释放链栈的每一个结点*/
		top = top->next;
		free(p);
		p = top;
	}
}
void Push(Node *top, DataType x) { //入栈 new一个节点然后放数据, 新节点指向top->next,top->next指向新节点
	Node *s = (Node *)malloc(sizeof(Node));          /*申请一个结点s*/
	s->data = x;
	s->next = top->next;
	top->next = s;                          /*将结点s插在栈顶*/
}
int Pop(Node *top, DataType *ptr) { //出栈,p节点保存top->next,top->next=top->next->next,free(p)
	Node *p = top->next;
	if (top->next == NULL) {
		printf("下溢错误,删除失败\n");
		return 0;
	}
	*ptr = top->next->data;                              /*存储栈顶元素*/
	top->next = p->next;                               /*将栈顶结点摘链*/
	free(p);
	return 1;
}
int GetTop(Node *top, DataType *ptr) { //得到顶部元素,返回 top->next->data即可,注意判空
	if (top->next == NULL) {
		printf("下溢错误,取栈顶失败\n");
		return 0;
	}
	*ptr = top->next->data;
	return 1;
}

int Empty(Node *top) { //判断栈是否为空 top->next为空 栈就为空
	if (top->next == NULL) return 1;                     /*栈空则返回1*/
	else return 0;
}
int main( ) {
	DataType x;
	Node *top = NULL;                 /*定义链栈的栈顶指针并初始化*/
	top = InitStack();                               /*初始化链栈*/
	printf("对15和10执行入栈操作,");
	Push(top, 15);
	Push(top, 10);
	if (GetTop(top, &x) == 1)
		printf("当前栈顶元素为:%d\n", x);            /*输出当前栈顶元素10*/
	if (Pop(top, &x) == 1)
		printf("执行一次出栈操作,删除元素:%d\n ", x);    /*输出出栈元素10*/
	if (GetTop(top, &x) == 1)
		printf("当前栈顶元素为:%d\n", x);           /*输出当前栈顶元素15*/
	printf("请输入待插入元素:");
	scanf("%d", &x);                            //输入17
	Push(top, x);
	if (Pop(top, &x) == 1)
			printf("执行一次出栈操作,删除元素:%d\n ", x);    /*输出出栈元素17*/
	if (GetTop(top, &x) == 1)
		printf("当前栈顶元素为:%d\n", x);           /*输出当前栈顶元素15*/
	if (Empty(top) == 1)
		printf("栈为空\n");
	else
		printf("栈非空\n");                  /*栈有1个元素,输出栈非空*/
	DestroyStack(top);
	return 0;
}

5.队列的应用场景

    1.银行排队拿号
    2.打印机的缓冲区(多台电脑共享一台打印机)
    3.网卡
    4.rabbitMQ 消息队列,可以解决消息延迟处理,以防高并发宕机的问题,还可以设置优先队列指定哪些消息优先被处理

6.什么是队列?(线性表+限制)

   1.只允许一端 插入,另外一端删除的结构 如图: 队头1出队 队列就变成了 5 4 3 2;2变成队头

在这里插入图片描述

2.特点先进先出(FIFO) 入队序列=出队序列,而栈 入队序列!=出队序列
3.双端队列(deque) 队首和队尾都可以出(不符合队列定义)

7.顺序队列

1.定义rear插入 O(1)
2.出队 删队头,移动后面的队列元素 O(n)   需要提高到O(1)[改为循环队列!!!工作常用]
3.优化队头 队尾指针假溢出问题(底端有空间没有被使用)(使用循环队列)

顺序队列如图:

在这里插入图片描述
循环队列如图:设队列长度为3 队尾下标=队尾下标%3(队列长度) 放入元素 1和2过程

在这里插入图片描述
在这里插入图片描述
我要出队头元素
在这里插入图片描述
//我要入队3元素
在这里插入图片描述
//然后 rear=(++rear)%3 即rear=(3)%3 0 ha还要判空,rearfront队列满在这里插入图片描述

8.循环队列c语言代码实现

#include <stdio.h>
#include <stdlib.h>
/*将循环队列的存储结构定义和各个函数定义放到这里*/
#define QueueSize 100            /*定义数组的最大长度*/
typedef int DataType;             /*定义队列元素的数据类型,假设为int型*/
typedef struct {
	DataType data[QueueSize];      /*存放队列元素的数组*/
	int front, rear;                 /*下标,队头元素和队尾元素的位置*/
} CirQueue;
void InitQueue(CirQueue *Q) { 
 //队头和队尾都指向最后一个元素 也可以为 -1,为了后续+1后队满做准备
	Q->front = Q->rear = QueueSize - 1;
}
int EnQueue(CirQueue *Q, DataType x) {    //O(1)
	if ((Q->rear + 1) % QueueSize == Q->front) { 
	//如果rear+1等于队头说明队满,不能写(Q->rear) % QueueSize == Q->front 因为一开始就rear==front
		printf("上溢错误,插入失败\n");
		return 0;
	}
	Q->rear = (Q->rear + 1) % QueueSize;      /*队尾位置在循环意义下加1*/
	Q->data[Q->rear] = x;                   /*在队尾处插入元素*/
	return 1;
}
int DeQueue(CirQueue *Q, DataType *ptr) { //O(1) //这里可以rear==front队空,队满和队空判断时机不一样
	if (Q->rear == Q->front) {
		printf("下溢错误,删除失败\n");
		return 0;
	}
	 //出队也是加1
	Q->front = (Q->front + 1) % QueueSize;    /*队头位置在循环意义下加1*/
	*ptr = Q->data[Q->front];                /*读取出队前的队头元素*/
	return 1;
}
int GetHead(CirQueue *Q, DataType *ptr) { //得到队头就是得到front指向的值,和判空一样
	int i;
	if (Q->rear == Q->front) {
		printf("下溢错误,取队头失败\n");
		return 0;
	}
	i = (Q->front + 1) % QueueSize;                /*注意不改变队头位置*/
	*ptr = Q->data[i];
	return 1;
}
int Empty(CirQueue *Q) { //判断队列是否为空,就是判断 rear==front
	if (Q->rear == Q->front) return 1;              /*队列为空返回1*/
	else return 0;
}
int main( ) {
	DataType x;
	CirQueue Q;                     /*定义结构体变量Q为循环队列类型*/
	InitQueue(&Q);                   /*初始化循环队列Q*/
	printf("对5和8执行入队操作,");
	EnQueue(&Q, 5);
	EnQueue(&Q, 8);
	if (GetHead(&Q, &x) == 1)
		printf("当前队头元素为:%d\n", x);              /*输出当前队头元素5*/
	if (DeQueue(&Q, &x) == 1)
		printf("执行一次出队操作,出队元素是:%d\n ", x);    /*输出出队元素5*/
	if (GetHead(&Q, &x) == 1)
		printf("当前队头元素为:%d\n", x);              /*输出当前队头元素8*/
	printf("请输入入队元素:");
	scanf("%d", &x);
	EnQueue(&Q, x);
	if (Empty(&Q) == 1)
		printf("队列为空\n");
	else
		printf("队列非空\n");               /*队列有2个元素,输出队列非空*/
	return 0;
}

9.链队列c语言代码

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
/*将链队列的存储结构定义和各个函数定义放到这里*/
typedef int DataType;               /*定义队列元素的数据类型,假设为int型*/
typedef struct Node                 /*定义链队列的结点结构*/
{
	DataType data;
	struct Node *next;  
} Node;
typedef struct                       /*定义链队列*/  //定义队头和队尾
{
	Node *front, *rear;
} LinkQueue;
void InitQueue(LinkQueue *Q)  //初始化队列,队头队尾指向新建立节点
{
	Node *s = (Node *)malloc(sizeof(Node)); s->next = NULL; 
	Q->front = Q->rear = s;            /*队头指针和队尾指针均指向头结点*/
}

void DestroyQueue(LinkQueue *Q) //队头一一出队也可以,下面是free
{
	Node *p = Q->front,*ptrtemp; 
	while (p != NULL)                     /*依次释放链队列的结点*/
	{
		ptrtemp = p->next;
		free(p); 
		p = ptrtemp;
	}                
}
void EnQueue(LinkQueue *Q, DataType x)
{
	Node *s = (Node *)malloc(sizeof(Node)); 
	s->data = x; s->next = NULL;        /*申请一个数据域为x的结点s*/
	Q->rear->next = s; Q->rear = s;       /*将结点s插入到队尾*/
}
int DeQueue(LinkQueue *Q, DataType *ptr)   //
{
	Node *p;
	//因为我们多了一个不存值的节点,所以如果出队 rear==front的话就出列失败
	if (Q->rear == Q->front) {printf("下溢错误,删除失败\n"); return 0; }
	p = Q->front->next; *ptr = p->data;        /*存储队头元素*/
	Q->front->next = p->next;               /*将队头元素所在结点摘链*/
	if (p->next == NULL) //  改的不是front指针而是他的next      /*判断出队前队列长度是否为1*/
		Q->rear = Q->front;      //主要还是处理 队列有没有元素的时候的情况
	free(p); return 1;
}
int GetHead(LinkQueue *Q, DataType *ptr)
{
	Node *p = NULL;
	if (Q->rear == Q->front) {printf("下溢错误,取队头失败\n"); return 0; }
	p = Q->front->next;
	*ptr = p->data; return 1;
}
int Empty(LinkQueue *Q)  //也可以判断 front->next!=NULL实现
{
	if (Q->rear == Q->front) return 1;              /*队列为空返回1*/
	else return 0;
}
void PrintQueue(LinkQueue * Q){  //定义p指针,先打印后next
	printf("遍历输出队列:\n");
	Node * p = Q->front->next;
	while(p!=NULL){
		printf("data: %d, next: %p\n",p->data, p->next);
		p = p->next;
	}
}

int main( )
{    
    DataType x;
	LinkQueue Q;                   /*定义结构体变量Q为链队列类型*/
	InitQueue(&Q);                  /*初始化链队列Q*/
	PrintQueue(&Q);
	
    printf("对5和8执行入队操作,");
	EnQueue(&Q, 5);
	PrintQueue(&Q);
	EnQueue(&Q, 8);
	PrintQueue(&Q);
	
	if (GetHead(&Q, &x) == 1)
		printf("当前队头元素为:%d\n", x);              /*输出当前队头元素5*/
		
	if (DeQueue(&Q, &x) == 1)
		printf("执行一次出队操作,出队元素是:%d\n", x);   /*输出出队元素5*/
		
	if (GetHead(&Q, &x) == 1)
		printf("当前队头元素为:%d\n", x);             /*输出当前队头元素8*/
		
	printf("请输入入队元素:");
	scanf("%d", &x);
	EnQueue(&Q, x);
	
	if (Empty(&Q) == 1)
		printf("队列为空\n");
	else
		printf("队列非空\n");             /*队列有2个元素,输出队列非空*/
		
    DestroyQueue(&Q);
	return 0;
}

总结: 出队(判断有没有下一个元素,front->next出队,改指针) 入队 (new新节点 然后改原rear和后rear指向新节点)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/568639.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue3(一):创建vue3工程、setup、vue3响应式原理、computed和watch

Vue3&#xff1a;第一章 一、创建Vue3.0工程1.使用vue-cli创建2.使用vite创建 二、Vue3中的响应式1.拉开序幕的setup2.ref函数3.reactive函数4.vue3中响应式的原理&#xff08;1&#xff09;vue2中响应式原理&#xff08;2&#xff09;Vue3中的Proxy 5.reactive和ref的对比6.se…

性能测试如何做?超详细性能测试-测试策略总结,新人进阶之路...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能测试出现的初…

YOLOv5【训练train.py逐行源码及参数调参解析】超详细解读!!!建议收藏✨✨!

之前的文章介绍了YOLOv5的网络结构&#x1f680;与目录结构源码&#x1f680;以及detect.py&#x1f680;的详细解读&#xff0c;今天带来的是YOLOv5的 train.py 代码参数逐行解读以及注释&#xff0c;废话不多说&#xff0c;让我们一起学习YOLOv5的 train.py 源码吧&#xff0…

功能测试和自动化测试的差距在哪里?

一直以来&#xff0c;软件的测试主要是以手工测试为主&#xff0c;但是随着现代软件的复杂程度的加深&#xff0c;人们对使用手工方式来完成软件测试感到的越来越力不从心&#xff0c;同时因为在软件测试中存在着大量的重复性工作&#xff0c;而这种工作是比较适合机器而不是人…

rsync

配置rsync源服务器&#xff1a; #建立/etc/rsyncd.conf 配置文件 vim /etc/rsyncd.conf #添加以下配置项 uid root gid root use chroot yes #禁锢在源目录 address 192.168.80.10 …

​Kali-linux无线网络嗅探工具Kismet​

如果要进行无线网络渗透测试&#xff0c;则必须先扫描所有有效的无线接入点。刚好在Kali Linux中&#xff0c;提供了一款嗅探无线网络工具Kismet。使用该工具可以测量周围的无线信号&#xff0c;并查看所有可用的无线接入点。本节将介绍使用Kismet工具嗅探无线网络。 &#xf…

MySQL_6 自连接和外连接

目录 一、自连接 1.概述 : 2.语法 : 3.演示 : 二、外连接 1.为什么需要外连接&#xff1f; 2.外连接的定义 : 3.外连接的演示 : 1 左外连接 2 右外连接 3 对部门表问题的解决 一、自连接 1.概述 : 自连接是指在同一张表上的连接查询&#xff08;将同一张看做两张表)&a…

R语言实践——rWCVP:按照物种的原生分布区清洗坐标点

rWCVP&#xff1a;按照物种的原生分布区清洗坐标点 加载库工作流&#xff08;单个物种&#xff09;1. 下载发现记录数据&#xff08;rgbif&#xff09;2. 发现记录的预备3. 获取原生区范围4. 清除非原生分布记录 加载库 library(rWCVP) library(rgbif) library(tidyverse) lib…

产品Backlog和需求管理

产品Backlog 产品backlog是一个按照价值排序的需求清单。为了达成产品目标&#xff0c;所有的需求都需要放到产品backlog中进行管理和规划。由产品负责人负责管理和维护。Leangoo为每一个里程碑建立了一个产品Backlog看板, 通过这个产品backlog看板来进行需求管理和规划。 里…

搭建服务器的主流中间件有哪些?如何在外网访问内网的服务?

计算机业内人士对于搭建服务器的中间件并不陌生&#xff0c;apache、tomcat、IIS、nginx 都是比较常用的搭建服务器的中间件&#xff0c;它们之间还是有一些区别差异的。今天就说说这些中间件之间有哪些区别&#xff0c;以及如何利用快解析实现内网主机应用让外网访问。 首先说…

大数据入门(六)- UCloud创建云服务器

一.注册UCloud账户 使用UCloud的服务&#xff0c;首先需要注册账户 账户注册非常简单&#xff0c;在UCloud网站首页&#xff08;https://www.ucloud.cn/&#xff09;右上角点击快速注册 二.创建VPC 1.注册成功后&#xff0c;选择全部产品 2.选择私有网络UVPC 3.区域选择华北…

uni-app开发小程序使用uni.chooseMedia选择图片,安卓手机无法选择图片

uni-app开发小程序时&#xff0c;使用uni.chooseMedia选择图片&#xff0c;苹果手机是正常的&#xff0c;安卓手机无法打开手机选择图片 问题复现解决方法&#xff01;&#xff01;我的反思与总结 问题复现 一、在小程序中&#xff0c;选择图片并上传&#xff0c;是一个很常见…

[Python报错] ImportError: cannot import name ‘timer’ from ‘timer’

[Python报错] ImportError: cannot import name ‘timer’ from ‘timer’ 前言 我最近遇到这个报错&#xff0c;卡了我好长时间去解决&#xff0c;我在互联网上找了很多资料&#xff0c;遗憾的是&#xff0c;我没找到有其他人遇到的类似的问题。所以在这里做一下记录。事实上…

两年外包,从4K涨到了15K....

我18年毕业于一个普通二本学校&#xff0c;电子信息工程学院&#xff0c;是一个很不出名的小本科。大学期间专业知识也没有去认真的学习&#xff0c;所以毕业的时候就随便找了一份工作&#xff0c;在一个外包公司做功能测试。 记得那时候薪资大概是4k左右&#xff0c;因为是以…

神经网络实验---人工神经网络(2)

本实验目的主要是掌握梯度下降法的优化算法&#xff1b;能够使用tf.keras构建Sequential模型&#xff0c;完成多分类任务。 1. 实验目的 ①掌握梯度下降法的优化算法&#xff1b; ②能够使用tf.keras构建Sequential模型&#xff0c;完成多分类任务。 2. 实验内容 ①下载MNIS…

架构设计之复用性概谈

作为开发人员&#xff0c;你对复用这个概念一定不陌生。在开发过程中&#xff0c;我们把系统中通用的代码逻辑抽取出来&#xff0c;变成公共方法或公共类&#xff0c;然后在多个地方调用&#xff0c;这就是最简单的技术上的复用。 但一开始&#xff0c;我们不会过多地考虑复用&…

迭代后首波实测!360智脑一键联网,代码超强,AI诈骗一眼看穿

360大模型&#xff08;又&#xff09;交卷了&#xff01;作为国内首个能联网的大模型&#xff0c;360智脑给了我们怎样的惊喜&#xff1f;话不多说&#xff0c;新鲜出炉的第一手实测来了。 不得不说&#xff0c;自从GPT大模型混战开赛之后&#xff0c;教主周鸿祎可谓是存在感十…

易观分析:消费金融机构以APP为触点,创新消费场景,激发消费活力

易观&#xff1a;随着“用好消费金融、释放消费潜力”等金融支持扩内需的持续深入&#xff0c;消费金融APP活跃用户规模将保持稳健增长的态势&#xff0c;进而在拉动内需、促进消费升级、服务实体经济中扮演更重要的角色。 一、疫情防控较快平稳转段&#xff0c;激发消费市场活…

总结button,input type=“button“,input type=“text“中:[在value添加值] 和 [标签内添加值]的区别

1.如果是需要一个 普通文本框 <input></input>和<input type"text"></input>外观相同 都是 2.对比button,input type"button",input type"text"中&#xff1a;在value添加值 和 标签内 添加值 html中&#xff1a; &l…

第十三章 常用类(Math 类、Arrays 类、System类、Biglnteger 和BigDecimal 类、日期类)

一、Math 类&#xff08;P481&#xff09; Math类包含&#xff0c;用于执行基本数学运算的方法&#xff0c;如初等指数、对数、平方根和三角函数 &#xff08;1&#xff09;abs&#xff1a;绝对值 &#xff08;2&#xff09;pow&#xff1a;求幂 double pow Math.pow(2, 4); /…