栈和队列知识点+例题

news2024/9/22 3:41:11

1.栈

1.1栈的概念及结构

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素的操作。进行数据插入和删除操作的一端成为栈顶,另一端成为栈底。遵守后进先出的原则(类似于弹夹)

压栈:栈的插入操作叫做进栈/入栈/压栈,入数据在栈顶

出栈:栈的删除操作叫做出栈,出数据也在栈顶

那如何实现栈呢?

 经过比较,数组栈是最优解,(链式的扩容会很久才会扩容一下)

由于top的位置意义不同,我们分为两种解决方案

1.2基本操作 

1.定义一个栈

typedef int SLDataType;
typedef struct Stack
{
    int *a;
    int top;
    int capacity;
}

2,初始化一个栈

void STInit(ST*pst)
{
     assert(pst);
    pst->a=NULL;
    pst->top=0;
    pst->capacity=0;
}

3压栈

void STPush(ST* pst, SLDataType x)
{
	assert(pst);
	if (pst->top == pst->capacity)
	{
		ST* newcapacity = pst->capacity == 0 ? 4 : capacity * 2;
		SLDataType* tmp = (SLDataType*)realloc((SLDataType)*newcapacity);
		if (newcapacity == NULL)
		{
			return -1;
		}
		else
		{
			pst->a = tmp;
			pst->capacity = newcapacity;
			pst->a[pst->top] = x;
			pst->top++;
		}
	}
}

 4,弹栈

void STPop(ST* pst)
{
    assert(pst);
    assert(pst->top>0);
    pst->top--;
}

5 返回栈顶元素

void STTop(ST* pst)
{
    assert(pst);
    assert(pst->top>0);
    return pst->a[pst->top-1];
}

6 判断是否为空

bool STEmpty(ST* pst)
{
	assert(pst);
	if (pst->top == 0)
	{
		return true;

	}
	else
	{
		return false;
	}
}

7 栈的大小

int STSize(ST* pst)
{
    assert(pst);
    return pst->top;
}

8销毁栈

void STDestory(ST*pst)
{
    assert(pst);
    free(pst->a);
    pst->a=NULL;
    pst->top=pst->capacity=0;
}

让我们看几道例题吧

例题1:

 思路:栈的顺序是后进先出,有题可知,最后一个是E,所以E先出,故选B

例题2:

 我们首先看选项,A选项:1先进,1先出,把2 3 4放进去,把4拿出来,再把3拿出来,最后把2拿出来。同理,我们看C选项,把1 2 3放进去,然后把3拿出来,然后我们会发现,如果想要拿1的话,拿2是必经之路,所以此选项错误

例题3:

 思路:

1,先建立一个栈,初始化一个栈,

2,然后我们把所有的左括号放入栈里面,如果不是左括号,即是有括号;

3,其次我们要知道,本题的关键在于数量匹配和顺序匹配。所以我们要考虑一下栈是否为空(右括号的数量大于左括号的数量),然后考虑顺序匹配的问题

4,最后我们看栈是否为空,如果为空,就返回true,然后把栈毁掉

bool isVaild(char* s)
{
	ST st;// 定义一个栈
	STInit(&st);
	while (*s)
	{
		if (*s == '[' || *s == '{' || *s == '(')
		{
			STPush(&st, *s);
			s++;
		}
		else
		{
			if (STEmpty(&st))
			{
				return false;
			}
			//栈里面取左括号
			char top = STTop(&st);
			STPop(&st);
			//顺序不匹配
			if (*s == ']' && top != '[') || (8s == '}' && top != '{') || (*s == ')' && top == '(')
			{
				return false;
			}
			s++;
		}
	}
	//栈为空,返回真,说明数量都匹配
	bool ret = STEmpty(&st);
	STDestory(&pst);
	return ret;
}

好啦~栈我们就先讲到这里啦,让我们看一下队列的知识点吧

2,队列

2.1队列的概念和结构

 我们可以考虑一个问题

入队之后,出队的时候顺序是唯一一定的吗?

答案是:当然是;

从以上我们可以了解到,栈用数组的方法比较好;而队列用单链表,头删尾插的方式比较好

2.2基本操作

1定义一个队列

typedef int QueueType;
typedef struct QueueNode
{
	QueueType val;
	struct QueueNode* next;

}QNode;

为了解决二级指针以及两个指针的问题,我们可以把两个指针放入一个结构体里面,然后进行一级指针的操作即可

typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;

2.初始化一个队列

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->size = 0;
	pq->phead = pq->ptail = NULL;
}

3.插入到队列

	void QueuePush(Queue* pq, QDataType x)
	{
		QNode* newnode = (QNode*)malloc(sizeof(QNode));
		if (newnode == NULL)
			return -1;
		else
		{
			newnode->val = x;
			newnode->next = NULL;
		}
		if (pq->tail == NULL)
		{
			return -1;

			pq->tail = pq->phead = newnode;
		}
		else
		{
			pq->tail->next = newnode;
			pq->tail = newnode;
		}
		pq->size++;
	}

4. 头删

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	QNode* del = pq->phead;
	pq->phead = pq->phead->next;
	if (pq->phead = NULL)
		pq->tail = NULL;
}

5找头结点的值

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	return pq->phead->val;
}

6队列是否为空

bool QueueEmpty(Queue* pq)
{
    assert(pq);

  return pq->phead=NULL;
}

7队列大小

int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

8销毁队列

void QueueDestory(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->phead;
	while (cur)
	{
		QNode* next = cur->next;
		cur = next;
	}
pq->phead=pq->ptail=NULL;
}

让我们看几道关于队列和栈的例题吧

例题1:

思路: 

 代码实现:

typedef struct
{
	Queue q1;
	Queue q2;

}Stack;

MyStack* CreateStack()
{
	MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
	QueueInit(&pst->q1);
	QueueInit(&pst->q2);

	return pst;
}
void mystackpush(Mystack* obj, int x)
{
	Queue Empty = &obj->q1;
	Queue nonEmpty =&obj->q2;
	if (!Empty(&obj->q1))
	{
		Queue Empty = &obj->q2;
		Queue nonEmpty = &obj->q1;
	}
	//开始到数据
	while (QueueSize(nonempty) > 1)
	{
		QueuePush(Empty, QueueFront(nonempty));
		QueuePop(nonempty);
	}
	int top = QueueFront(nonempty);
	QueuePop(nonempty);
	return top;
}

int mystackTop(Mystack* obj)
{
	if (!Empty(&obj->q1))
	{
		return QueueBack(&obj->q1);
	}
	else
	{
		return QueueBack(&obj->q2);
	}
}
bool mystackEmpty(MyStack* obj)
{
	return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}
void mystackFree(Mystack* obj)
{
	QueueDestory(&obj->q1);
	QueueDestory(&obj->q2);
	free(obj);
}

例题2:

 

 思路:

 代码实现:

 

typedef struct
{
	int* a;
	int top;
	int capacity;
}ST;
typedef struct
{
	ST pushst;
	ST popst;
}MyQueue;
//初始化
void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;
	pst->top = 0;
	pst->capacity = 0;
}
//压栈
void STPush(ST* pst, SLDataType x)
{
	assert(pst);
	if (pst->top == pst->capacity)
	{
		ST* newcapacity = (SLDataType*)malloc(sizeof(SLDataType);
		SLDataType* tmp = pst->capacity == 0 ? 4 : newcapacity * 2;
		if (newcapacity == 0)
		{
			return -1;
		}
		else
		{
			pst->a = tmp;
			pst->capacity = newcapacity;
			pst->a[pst->top] = x;
			pst->top++;
		}
	}
}
//返回栈顶元素
void STTop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	return pst->a[pst->top - 1];
}
//弹栈
void STPop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	pst->top--;
}
//判断是否为空
bool STEmpty(ST* pst)
{
	assert(pst);
	if (pst->top == 0)
	{
		return true;
	}
	else
	{
		return -1;
	}
}
MyQueue* myQueueCreate()
{
	MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
	STInit(&obj->pushst);
	STInit(&obj->popst);
	return obj;
}
void myQueuePush(MyQueue* obj, int x)
{
	STPush(&obj->pushst, x);
}
返回队列开头的元素(不删除)
void myQueuepeek(MyQueue* obj)
{
	if (!STEmpty(&obj->popst))
	{
		return STTop(&obj->popst);
	}
	else
	{
		while (!STEmpty(&obj->pushst))
		{
			STPush(&obj->popst, STTop(&obj->pushst);
			STPop(&obj->pushst);
		}
		return STTop(&obj->popst);
	}
}
//从队列开头移除并返回元素
void myQueuePop(MyQueue* obj)
{
	int front = myQueuePeek(obj);
	STPop(&obj->popst);
	return front;
}
bool myQueueEmpty(MyQueue* obj)
{
	return  STEmpty(&obj->pushst) && (&obj->popst);
}
void myQueueFree(MyQueue* obj)
{
	STDestory(&obj->popst);
	STDestory(&obj->pushst);
	free(obj);
}

接下来我们看一下循环队列吧

1.判断循环队列是否为空:front==back(front指向对头,back指向队尾的下一个)

 

 如何判断队列是否为满

1.前提:front==back(当size=0时,为空,size!=0则为满)

2,再增加一个地方)

数组实现(back+1)%(k+1)==front则为满,其中,k+1指的是开辟空间的个数,k指的是有效数据数 数组实现&(k+1)是为了防止溢出

链表实现,即把上面式子去掉  %(k+1)

链表实现:

 

 数组实现:

 单链表缺陷以及找尾的办法:

 如何计算循环中元素的个数

typedef struct {
	int* a;
	int front;
	int back;
	int k;
}MyCircularQueue;
//初始化
MyCircularQueue* myCircularQueueCreate(int k) {
	MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
	obj->a = (int*)malloc(sizeof(int) * (k + 1));
	obj->front = 0;
	obj->back = 0;
	obj->k = 0;
	return obj;
}
//是否为空
bool myCircularQueueEmpty(MyCircularQueue* obj)
{
	return obj->front = obj - back;

}
//是否为满
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
	return (obj->front) % (obj->k + 1) == obj->front;

}
//插入
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
	if (myCircularQueueIsFull(obj))
	{
		return false;
	}
	obj->a[obj->back] = value;
	obj->back++;
	obj->back % (obj->k + 1) = obj->back;
	return true;
}
//删除
bool myCircularQueueDeQueue(MyCircularQueue* obj, int value)
{

	if (myCircularQueueIsFull(obj))
	{
		return false;
	}
	++obj->front;
	obj->front % (obj->k + 1) = obj->front;
	return true;
}
//返回队头
int myCircularQueueFront(MyCircularQueue* obj)
{
	if (myCircularQueueIsFull(obj))
	{
		return false;
	}
	return obj->a[obj->front];
}
//返回队尾
int myCircularQueueRear(MyCircularQueue* obj)
{
	if (myCircularQueueIsFull(obj))
	{
		return false;
	}
	return obj->a[obj->back - 1];
}
//清空
void myCircularQueueFree(MyCircularQueue* obj)
{
	free(obj->a);
	free(obj);
}

好啦~关于栈和队列的知识点就这些啦~谢谢大家观看~

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

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

相关文章

Linux搭建服务器环境,挂载SpringBoot+VUE项目

本地环境 Ubuntu20.04 服务器环境 CentOS7.6 购买服务器 以阿里云轻量服务器(适合初学者)为例,自行选择规格进行购买 购买完成后,获取服务器公网IP,同时重置密码,设置服务器密码 配置防火墙 点击实例ID&am…

极智嘉(Geek+)官宣重磅合作伙伴,再度赋能仓储自动化解决方案落地

近日,全球仓储机器人引领者极智嘉(Geek)再度官宣重磅合作伙伴,其与全球先进的物流自动化和软件公司FORTNA达成了战略合作。 当前,电商领域发展迅速,高效、可拓展的订单履行方案需求急剧增长。基于这一形势,极智嘉与FO…

OpenCV [c++](图像处理基础示例小程序汇总)

OpenCV [c++](图像处理基础示例小程序汇总) 推荐 原创 NCUTer 2023-04-04 14:18:49 文章标签 Image 图像处理 文章分类 计算机视觉 人工智能 在51CTO的第一篇博文 阅读数1467 一、图像读取与显示 #include<opencv2/opencv.hpp> #include<iostream>using…

git问题: git@10.18.*.*: Permission denied (publickey,password)

遇到的问题&#xff1a; openSSH版本太高&#xff0c;openssh高版本默认禁止ssh-rsa加密算法&#xff0c;直接换ed25519 执行以下命令&#xff1a; 在.ssh目录下执行&#xff1a;ssh-keygen -t ed25519 -C “youremail.com” ssh-add ~/.ssh/id_ed25519 将id_ed25519.pub添加…

文章解读与仿真程序复现思路——电力自动化设备EI\CSCD\北大核心《考虑多重不确定性和潜在博弈的楼宇群电能优化调度策略》

这个标题涉及到楼宇群电能的优化调度策略&#xff0c;并强调了两个重要的方面&#xff1a;多重不确定性和潜在博弈。 楼宇群电能优化调度策略&#xff1a; 这指的是在一个涉及多个楼宇&#xff08;建筑物&#xff09;的群体中&#xff0c;对电能的使用进行优化调度的策略。这可…

深度学习(小土堆)

self代表当前类的实例&#xff0c;并用于访问实例的属性和方法,主要方便后面访问属性或者方法。 启动事件文件夹 进行上一步需要在pycharm中设置当打开Terminal终端时&#xff0c;自动进入虚拟环境 防止与别人冲突可以修改端口号 将图像的数据类型转为numpy trans…

微信小程序配置企业微信的在线客服

配置企业微信后台 代码实现 <button tap"openCustomerServiceChat">打开企业微信客服</button>methods: {openCustomerServiceChat(){wx.openCustomerServiceChat({extInfo: {url: 你刚才的客服地址},corpId: 企业微信的id,showMessageCard: true,});} …

【小黑嵌入式系统第九课】PSoC 5LP第一个实验——LED、字符型LCD显示实验

上一课&#xff1a; 【小黑嵌入式系统第八课】初识PSoC Creator™开发——关于PSoC Creator&下载、创建项目、单片机中的hello world&#xff08;点亮一个led) 文章目录 1 实验目的2 实验要求3 实验设备4 实验原理1. 基于 PWM 原理的 LED 亮度控制2. 时间的计量3. 按键抖动…

FPGA_IIC代码-正点原子 野火 小梅哥 特权同学对比写法(2)

FPGA_IIC代码-正点原子 野火 小梅哥 特权同学对比写法&#xff08;2&#xff09; 工程目的I2C 单字节写操作I2C 随机读操作EEPROM 字节读写整体框图模块功能简介I2C 驱动模块模块框图跨时钟域处理状态转移图 波形分析单字节写操作局部波形图&#xff08;一&#xff09;单字节写…

IP地址的分包与组包:网络通信的关键技术解析

在计算机网络中&#xff0c;IP地址的分包与组包是网络通信过程中关键的技术环节&#xff0c;分别涉及将数据拆分为适当大小的包以及在接收端重新组装这些包的过程。这两个过程对于确保高效、可靠的数据传输至关重要。以下将深入探讨IP地址的分包与组包的概念、原理以及在网络通…

进程管理(三)

生产者—消费者问题及初步解决方案 放了数据后,有通知消费者的义务。 空缓冲区、满缓冲区作为资源,设计为信号量 关于生产者—消费者初步解决方案的反思 秘诀:资源信号量wait在前,互斥信号量wait在后 关于生产者—消费者初步解决方案的改进

Linux常见命令手册

目录 文件命令 文件和目录命令 文件的权限命令 文件搜索命令 进程命令 查看进程命令 关闭进程命令 用户和群组命令 网络命令 firewall-cmd 网络应用命令 高级网络命令 网络测试命令 网络安全命令 网络配置命令 软件管理命令 系统信息命令 vi编辑器 关机命令…

2023年中国位置服务(LBS)产业链及市场规模分析[图]

卫星导航系统的高技术、高成本、高效益属性使其成为国家经济实力与科技实力的标志之一。卫星导航系统由空间段、地面段和用户段三个部分组成&#xff0c;已广泛用于交通运输、农林牧渔、航空航海等领域&#xff0c;服务载体包括手机、汽车、无人机、导弹等&#xff0c;对人们生…

Dubbo快速实践

文章目录 架构相关概念集群和分布式架构演进 Dubbo概述Dubbo快速入门前置准备配置服务接口配置Provider配置Consumer Dubbo基本使用总结 本文参考https://www.bilibili.com/video/BV1VE411q7dX 架构相关概念 集群和分布式 集群&#xff1a;很多“人”一起 &#xff0c;干一样…

数据结构与算法-生成树与最小生成树

生成树与最小生成树 &#x1f388;1.生成树与最小生成树&#x1f52d;1.1生成树与最小生成树的概念&#x1f52d;1.2最小生成树的生成准则&#x1f52d;1.3两种最小生成树算法&#x1f3c6;1.3.1Kruskal算法&#x1f3c6;1.3.2Prim算法 &#x1f388;2.有向无环图及其应用&…

unity 打包exe设置分辨率

unity在2019以上版本不支持在打开的时候弹出分辨率设置的窗口&#xff0c;但是因为有些需求需要可以设置分辨率进行操作&#xff0c;我在查了好多办法后找到了解决方案&#xff0c;废话不多说开始干货。 1.先去百度云上下载这个文件 链接&#xff1a;https://pan.baidu.com/s/1…

MATLAB常用绘图函数的使用

文章目录 绘制一图一线绘制一图多线用法一&#xff1a;plot用法二&#xff1a;hold on 绘制一图多图其他形式的坐标图分段函数绘制方法一&#xff1a;分段写函数的定义域值域方法二&#xff1a;判断定义域方法三&#xff1a;if else 判断 横纵坐标范围设置标题、轴标签、图例、…

如何去云服务器申请环境跑深度学习模型

我的研究方向是显著性目标检测&#xff0c;虽然对比目标检测来说&#xff0c;数据集和模型的尺寸已经降低很多了&#xff0c;然后我们实验室也有一台公用服务器&#xff0c;但是那台服务器好多人使用&#xff0c;每个人能分配到的容量就很小&#xff0c;而且有时候会宕机&#…

测试和验证有什么区别,怎么划分测试集和验证集

测试集和验证集是在机器学习中用于评估模型性能的两个不同的数据集。它们有不同的目的和使用方式。 验证集&#xff08;Validation Set&#xff09;&#xff1a; 目的&#xff1a; 用于调整模型的超参数&#xff08;例如&#xff0c;学习率、正则化参数等&#xff09;和进行模型…

软件工程第十一周

面向对象 面向对象编程&#xff08;Object-Oriented Programming, OOP&#xff09;不仅仅是一种程序设计方法&#xff0c;它更是一种深刻的软件工程开发思想。这种思想的核心在于通过抽象和封装来模拟现实世界中的对象和概念&#xff0c;以便更好地管理和解决复杂的软件工程问…