栈与队列的故事

​​​​​​​


目录

​编辑​​​​​​​

一、栈

1.1栈的概念及结构

1.2栈的实现

1、实现支持动态增长的栈

2、初始化栈

3、入栈

4、出栈

5、获取栈顶元素

6、检测栈是否为空

7、获取栈中有效元素个数

8、销毁栈

9、测试

1.3源码

二、队列

2.1队列的概念及结构

2.2队列的实现

1、链式结构:表示队列

2、队列的结构

3、初始化队列

4、队尾入队列

5、队头出队列

6、获取队列队头元素

7、获取队列队尾元素

8、获取队列中有效元素个数

9、检测队列是否为空

10、销毁队列

11、测试

2.3源码


一、栈

1.1栈的概念及结构

栈是一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

  • 压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
  • 出栈:栈的删除操作叫做出栈,出数据也在栈顶。

1.2栈的实现

栈的实现一般可以使用数组或者链表实现:

  • 对于链表而言又有双向链表和单链表,如果用双向链表实现,栈顶既可以是尾,也可以是头。如果用单链表实现,栈顶只能是头,因为单链表尾插容易,尾删却比较麻烦;而头插头删都很容易。
  • 相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。

1、实现支持动态增长的栈

typedef int STDataType;typedef struct stack
{STDataType* arr;int top;      //栈顶int capacity; //容量
}ST;

2、初始化栈

因为这个结构体肯定不可能为空,所以我们直接先断言它。然后,这里还有一个要特别注意的点,如果我们初始化时top给0,那top指向的就是栈顶元素的下一个位置;如果top给-1,那top就指向栈顶元素

void STInit(ST* pst)
{assert(pst);pst->arr = NULL;pst->capacity = 0;//表示top指向栈顶元素的下一个位置pst->top = 0;表示top指向栈顶元素//pst->top = -1;
}

3、入栈

入栈时如果空间不够,先扩容;因为top此时是指向栈顶元素的下一个位置,所以我们直接将要入栈的元素x放在top位置,然后让top指向下一个位置就行。

void STPush(ST* pst, STDataType x)
{assert(pst);//扩容if (pst->top == pst->capacity){int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;STDataType* tmp = (STDataType*)realloc(pst->arr, sizeof(STDataType) * newcapacity);if (tmp == NULL){perror("realloc fail");return;}pst->arr = tmp;pst->capacity = newcapacity;}pst->arr[pst->top] = x;pst->top++;//如果top初始化时为-1,入栈时就要top先++,再将元素放进去//pst->top++;//pst->arr[pst->top] = x;
}

4、出栈

在出栈时要注意如果top为0就不能在删除了,所以要断言一下。

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

5、获取栈顶元素

因为top是指向栈顶元素的下一个位置,所以要获取栈顶元素只需要top-1就行。

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

6、检测栈是否为空

如果栈为空,那top就等于0,表达式的结果就为真;如果表达式的结果为假,就代表栈不为空。

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

7、获取栈中有效元素个数

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

8、销毁栈

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

9、测试

int main()
{ST s;STInit(&s);STPush(&s, 1);STPush(&s, 2);STPush(&s, 3);STPush(&s, 4);STPush(&s, 5);while (!STEmpty(&s)){printf("%d ", STTop(&s));STPop(&s);}printf("\n");STDestroy(&s);return 0;
}

1.3源码

🌻Stack.h

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>typedef int STDataType;typedef struct stack
{STDataType* arr;int top;      //栈顶int capacity; //容量
}ST;//初始化
void STInit(ST* pst);
//销毁栈
void STDestroy(ST* pst);
//入栈
void STPush(ST* pst, STDataType x);
//出栈
void STPop(ST* pst);
//获取栈顶元素
STDataType STTop(ST* pst);
//检测栈是否为空,如果为空,返回真;如果不为空,返回假
bool STEmpty(ST* pst);
//获取栈中有效元素个数
int STSize(ST* pst);

🌻Stack.c

#include "stack.h"//初始化
void STInit(ST* pst)
{assert(pst);pst->arr = NULL;pst->capacity = 0;//表示top指向栈顶元素的下一个位置pst->top = 0;//表示top指向栈顶元素//pst->top = -1;
}//销毁栈
void STDestroy(ST* pst)
{assert(pst);free(pst->arr);pst->arr = NULL;pst->top = pst->capacity = 0;
}//入栈
void STPush(ST* pst, STDataType x)
{assert(pst);//扩容if (pst->top == pst->capacity){int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;STDataType* tmp = (STDataType*)realloc(pst->arr, sizeof(STDataType) * newcapacity);if (tmp == NULL){perror("realloc fail");return;}pst->arr = tmp;pst->capacity = newcapacity;}//如果top初始化时为0,入栈时就要先将元素放进去,再将top++pst->arr[pst->top] = x;pst->top++;//如果top初始化时为-1,入栈时就要top先++,再将元素放进去//pst->top++;//pst->arr[pst->top] = x;
}//出栈
void STPop(ST* pst)
{assert(pst);assert(pst->top > 0);pst->top--;
}//获取栈顶元素
STDataType STTop(ST* pst)
{assert(pst);assert(pst->top > 0);return pst->arr[pst->top - 1];
}//检测栈是否为空,如果为空,返回真;如果不为空,返回假
bool STEmpty(ST* pst)
{assert(pst);return pst->top == 0;
}//获取栈中有效元素个数
int STSize(ST* pst)
{assert(pst);return pst->top;
}

二、队列

2.1队列的概念及结构

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out)的特点。

  • 入队列:进行插入操作的一端称为队尾
  • 出队列:进行删除操作的一端称为队头

2.2队列的实现

队列也可以数组和链表的结构实现,但使用链表的结构实现会更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

1、链式结构:表示队列

typedef int QDataType;//链式结构:表示队列
typedef struct QueueNode
{QDataType val;struct QueueNode* next;
}QNode;

2、队列的结构

因为队列需要队头和队尾两个指针,所以为了方便管理,我们可以把它俩放在一个结构体里边。

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

3、初始化队列

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

4、队尾入队列

void QueuePush(Queue* pq, QDataType x)
{assert(pq);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");return;}newnode->val = x;newnode->next = NULL;if (pq->ptail == NULL){pq->ptail = pq->phead = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}

5、队头出队列

出队时得考虑两种情况,一种是队列为空,另一种是队列中只有一个节点;如果队列为空,我们只需断言一下就行。如果队列中只有一个节点,我们先保存当前节点,然后让头指针指向下一个节点,接着free掉保存的节点,这时如果头指针是指向空的,我们就把尾指针也置空。

void QueuePop(Queue* pq)
{assert(pq);//空assert(pq->phead);QNode* del = pq->phead;pq->phead = pq->phead->next;free(del);del = NULL;if (pq->phead == NULL){pq->ptail = NULL;}pq->size--;
}

6、获取队列队头元素

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

7、获取队列队尾元素

QDataType QueueBack(Queue* pq)
{assert(pq);//空assert(pq->ptail);return pq->ptail->val;
}

8、获取队列中有效元素个数

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

9、检测队列是否为空

bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL;
}

10、销毁队列

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

11、测试

int main()
{Queue q;QueueInit(&q);QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);QueuePush(&q, 4);QueuePush(&q, 5);while (!QueueEmpty(&q)){printf("%d ", QueueFront(&q));QueuePop(&q);}printf("\n");QueueDestroy(&q);return 0;
}

2.3源码

🌻Queue.h

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>typedef int QDataType;//链式结构:表示队列
typedef struct QueueNode
{QDataType val;struct QueueNode* next;
}QNode;//队列的结构
typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;//初始化队列
void QueueInit(Queue* pq);
//队尾入队列
void QueuePush(Queue* pq, QDataType x);
//队头出队列
void QueuePop(Queue* pq);
//获取队列队头元素
QDataType QueueFront(Queue* pq);
//获取队列队尾元素
QDataType QueueBack(Queue* pq);
//获取队列中有效元素个数
int QueueSize(Queue* pq);
//检测队列是否为空
bool QueueEmpty(Queue* pq);
//销毁队列
void QueueDestroy(Queue* pq);

🌻Queue.c

#include "queue.h"//初始化队列
void QueueInit(Queue* pq)
{assert(pq);pq->phead = pq->ptail = NULL;pq->size = 0;
}//队尾入队列
void QueuePush(Queue* pq, QDataType x)
{assert(pq);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");return;}newnode->val = x;newnode->next = NULL;if (pq->ptail == NULL){pq->ptail = pq->phead = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}//队头出队列
void QueuePop(Queue* pq)
{assert(pq);//空assert(pq->phead);QNode* del = pq->phead;pq->phead = pq->phead->next;free(del);del = NULL;if (pq->phead == NULL){pq->ptail = NULL;}pq->size--;
}//获取队列队头元素
QDataType QueueFront(Queue* pq)
{assert(pq);//空assert(pq->phead);return pq->phead->val;
}//获取队列队尾元素
QDataType QueueBack(Queue* pq)
{assert(pq);//空assert(pq->ptail);return pq->ptail->val;
}//获取队列中有效元素个数
int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}//检测队列是否为空
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL;
}//销毁队列
void QueueDestroy(Queue* pq)
{assert(pq);QNode* cur = pq->phead;while (cur){QNode* next = cur->next;free(cur);cur = next;}pq->phead = pq->ptail = NULL;pq->size = 0;
}

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

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

相关文章

Python 强大邮件处理库 Imbox

目录 IMAP Mailbox Imbox 安装 特性 提取邮件内容 处理附件 安全性 示例 1&#xff1a;读取收件箱中的邮件 2&#xff1a;搜索并下载附件 3&#xff1a;连接到IMAP服务器获取所有邮件 结论 IMAP Mailbox IMAP&#xff08;Internet Message Access Protocol&#x…

解放生产力,AI加持你也能做这些事!

去年网上流行一个说法叫一人企业或超级IP。一个人就是一家公司&#xff0c;可以更加专注于自身核心技能。既能对工作拥有更大的自主性和控制力&#xff0c;又能舍弃了传统公司管理等繁琐的事务工作&#xff0c;可以全面释放自己的兴趣和潜力。 这个概念给笔者留下了比较深的印…

使用Julia语言和R语言实现K-均值

K-均值算法基础 K-均值聚类算法属于一种无监督学习的方法&#xff0c;通过迭代的方式将数据划分为K个不重叠的子集&#xff08;簇&#xff09;&#xff0c;每个子集由其内部数据点的平均值来表示。计算方法大体如下&#xff1a; 1.初始化簇中心 选择K个数据点作为初始的簇中心…

实用软件分享之自动清理过期备份文件清理文件夹

实用软件分享之自动清理过期备份文件清理文件夹&#xff0c;单文件程序&#xff0c;把程序放在要清理的文件夹内&#xff0c;运行后&#xff0c;可以设置清理指定文件后缀&#xff0c;支持设置保留个数&#xff0c;按文件的修改时候&#xff0c;清理掉最早的文件 初步讲解&am…

【算法面试题】-04

执行时长 def min_execution_time(n, size, tasks):a 0ans sizei 0while i < size:tmp tasks[i]a tmpif a < n:a 0else:a - ni 1ans a // nif a % n ! 0:ans 1return ans# 读取输入 n int(input()) size int(input()) tasks list(map(int, input().split()))…

ElasticSearch之排序,fielddata和docvalue

写在前面 es搜索返回结果的排序默认是按照得分的高低来排的&#xff0c;本文来看下如何按照字段来排序&#xff0c;实现类似于MySQL的order by xxx的效果。 1&#xff1a;什么是fileddata和doc_value 参考ElasticSearch之零碎知识点 和一文带你彻底弄懂ES中的doc_values和fi…

[QT]自定义的QtabWidget

需求 最近有一个需求就是一个QTabWidget要求有四个tab页在左侧用于显示主页面&#xff0c;在右侧有一个关于按钮&#xff0c;点击后用于弹出窗口显示一些程序相关信息。主要是怎么实现右侧按钮 相关代码 #ifndef MYTABWIDGET_H #define MYTABWIDGET_H#include <QWidget&g…

[ROS 系列学习教程] rosbag C++ API

ROS 系列学习教程(总目录) 本文目录 一、rosbag::Bag1.1 常用接口1.2 其他接口 二、rosbag::View2.1 常用接口2.1.1 代码示例 rosbag 的 C API 主要有两个类&#xff0c;用于写bag文件的Bag类&#xff0c;和用于读bag文件的View类。 一、rosbag::Bag 用于写bag文件。 头文件…

集合和数组的相关操作

目录 1.数组转集合(引用类型数组) 2.数组转集合(基础类型数组) 3.集合转数组 4.集合之间是否相交 5.获取两个集合的交集 6.集合转为字符串 1.数组转集合(引用类型数组) (1)Arrays.asList 示例&#xff1a; String[] colArr new String[6];colArr[0] "1";co…

代码随想录刷题笔记 DAY 42 | 最后一块石头的重量 II No.1049 | 目标和 No.494 | 一和零 No.474

文章目录 Day 4301. 最后一块石头的重量 II&#xff08;No. 1049&#xff09;<1> 题目<2> 笔记<3> 代码 02. 目标和&#xff08;No. 494&#xff09;<1> 题目<2> 笔记<3> 代码 03. 一和零&#xff08;No. 474&#xff09;<1> 题目&l…

[C/C++]string类常用接口介绍及模拟实现string类

一&#xff1a;Cstring类的由来 在C语言中&#xff0c;字符串是以\0结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C标准库中提供了一些str系列的库函数&#xff0c;但是这些库函数与字符串是分离开的&#xff0c;不太符合OOP的思想&#xff0c;而且底层空间需要用…

字节跳动的 SDXL-LIGHTNING : 体验飞一般的文生图

TikTok 的母公司字节跳动推出了最新的文本到图像生成人工智能模型&#xff0c;名为SDXL-Lightning。顾名思义&#xff0c;这个新模型只需很轻量的推理步骤&#xff08;1&#xff0c;4 或 8 步&#xff09;即可实现极其快速且高质量的文本到图像生成功能。与原始 SDXL 模型相比&…

uniapp开发小程序实现-获取手机号码(二)

一共3篇文章,共同描述,看序号进行寻找。 真机效果图 1.前提 获取手机号码,一定要企业账号,不是企业账号会出现下面提示 所以没有企业账号的,就可以不用看了,申请企业账号去官网申请就行了,申请成功了后,我们接着看。 2.代码 代码参考文章 获取手机号 | 微信开放文…

AI PC:重塑未来办公与生活方式的革命性工具

随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;已经渗透到我们生活的方方面面。而在PC领域&#xff0c;一场由AI引领的变革也正在悄然发生。从硬件到软件&#xff0c;从云端到终端&#xff0c;AI正在重塑我们的办公和生活方式。 AI工具网 | 人工智能工具推…

简单银行管理系统(C# winform SQL Server)

一、任务描述 1.使用Asp.NET技术&#xff0c;完成银行管理系统 2.开发工具&#xff1a;VS2010 3.数据库&#xff1a;SQL Server 2008 功能模块&#xff1a;登录、开户、存款、取款、转账、挂失等功能 运行界面&#xff1a; 1.登录界面&#xff08;Login.aspx&#xff09; 在…

数据分析-Pandas两种分组箱线图比较

数据分析-Pandas两种分组箱线图比较 数据分析和处理中&#xff0c;难免会遇到各种数据&#xff0c;那么数据呈现怎样的规律呢&#xff1f;不管金融数据&#xff0c;风控数据&#xff0c;营销数据等等&#xff0c;莫不如此。如何通过图示展示数据的规律&#xff1f; 数据表&am…

牛客周赛 Round 36

赛况 C题可惜&#xff0c;比赛时模拟没有想明白&#xff0c;只对了一半&#xff0c;赛后看了大佬们的题解后恍然大悟&#xff0c;而F题是压根没思路&#xff0c;况且F题部分分也比较难拿。 题目列表 A-小红的数位删除 思路 将读入的数字整除10做三次后输出即可 参考代码 #inc…

高效管理百万级数据:MySQL备份与恢复实战指南

简介 在当今数字化时代&#xff0c;数据是企业不可或缺的核心资产之一&#xff0c;而MySQL作为一种流行的关系型数据库管理系统&#xff0c;其百万级数据的高效管理显得尤为重要。本实战指南将深入探讨MySQL备份与恢复的关键策略&#xff0c;为您提供全面而实用的解决方案。通…

streamlit学习-如何修改css样式

streamlit学习-如何修改css样式 效果图代码(srv.py)运行 streamlit默认的样式有时并不符合自己的要求。比如手机上的布局太浪费空间,我们希望一屏能放下所有的元素,本文演示了如何操作 效果图 代码(srv.py) import streamlit as st #1.31.1 import cv2 import numpy as np im…

实验二(二)OSPF路由协议基础实验

1.实验介绍 1.1关于本实验 开放式最短路径优先 OSPF(Open Shortest Path First)是IETF 组织开发的一个基于链路状态的内部网关协议(Interior Gateway Protocol)。目前针对 IPv4 协议使用的是 OSPF Version 2(RFC2328);OSPF 作为基于链路状态的协议&#xff0c;OSPF 具有以下优…