数据结构(4)—栈和队列

一、概念

1.栈只允许在栈顶位置入栈和出栈元素,链表可以在任意位置插入和删除元素,栈和队列只允许在指定位置插入和删除元素

2.链表、栈和队列都是一种线性结构(一对一),栈和队列是一种特殊的表状结构

二、栈

1.基础概念

先进后出,后进先出

栈顶:允许入栈和出栈的一端称为栈顶

栈底:不允许入栈和出栈的一端称为栈底

入栈(压栈):将元素放入栈顶位置

出栈(弹栈):将栈顶元素取出

栈针:记录栈顶位置的标记

2.分类:

(1)顺序栈:

增栈:栈的方向自低向高增长    减栈:栈的方向自高向低增长

空栈:栈针指向要入栈的位置    满栈:栈针指向栈顶元素的位置

常见顺序栈: 空增栈、空减栈、满增栈、满减栈

此图为空减栈

①顺序栈的实现

#ifndef __SEQSTACK_H__
#define __SEQSTACK_H__
typedef int datatype;                 //存放数据的类型
typedef struct stack
{
datatype *pdata;               //存放数据空间首地址
int top;                              //栈顶元素位置
int tlen;                             //最多存放元素个数
}seqstack;
#endif

②顺序栈的创建

申请存放标签的空间,申请存放数据的空间

seqstack *create_seqstack(int len)
{
seqstack *ptmpstack = NULL;
//申请标签空间
ptmpstack = malloc(sizeof(seqstack));
if (NULL == ptmpstack)
{
perror("fail to malloc");
return NULL;
}
//申请存放数据的空间
ptmpstack->pdata = malloc(sizeof(datatype) * len);
if (NULL == ptmpstack->pdata)
{
perror("fail to malloc");
return NULL;
}
ptmpstack->top = 0;
ptmpstack->tlen = len;
return ptmpstack;
}

③ 顺序栈的销毁:

销毁存放数据的空间,销毁存放标签的空间

int destroy_seqstack(seqstack **pptmpstack)
{
free((*pptmpstack)->pdata);
free((*pptmpstack));
*pptmpstack = NULL;
return 0;
}

(注意先后顺序)

④是否为空栈:栈针为0即为空栈

int is_empty_seqstack(seqstack *ptmpstack)
{
return 0 == ptmpstack->top;
}

⑤是否为满栈:栈针与tlen相同即为满栈

int is_full_seqstack(seqstack *ptmpstack)
{
return ptmpstack->tlen == ptmpstack->top;
}

⑥ 压栈:将元素放入栈顶位置,栈针位置++

int push_seqstack(seqstack *ptmpstack, datatype tmpdata)
{
if (is_full_seqstack(ptmpstack))
{
return -1;
}
ptmpstack->pdata[ptmpstack->top++] = tmpdata;
return 0;
}

⑦出栈:栈针位置--,将栈顶元素出栈

datatype pop_seqstack(seqstack *ptmpstack)
{
if (is_empty_seqstack(ptmpstack))
{
return -1;
}
return ptmpstack->pdata[--ptmpstack->top];
}

(2)链式栈

使用链表的思想实现链式栈,参考单向链表节点定义,压栈使用头插法,出栈返回链表第一个有效节点的值,并删除该节点,在主函数循环出栈,销毁栈参考单向链表的销毁

linknode *create_empty_linkstack(void)
{
linknode *ptmpnode = NULL;
//创建空白节点
ptmpnode = malloc(sizeof(linknode));
if (NULL == ptmpnode)
{
perror("fail to malloc");
return NULL;
}

        //初始化节点中的值
ptmpnode->pnext = NULL;
//返回空白节点地址
return ptmpnode;
}
/* 判断顺序栈是否为空 */
int is_empty_linkstack(linknode *phead)
{
//判断空白节点后面还有没有节点
return NULL == phead->pnext;
}

/* 压栈 */
int push_linkstack(linknode *phead, datatype tmpdata)
{
linknode *ptmpnode = NULL;
//头插法
ptmpnode = malloc(sizeof(linknode));
if (NULL == ptmpnode)
{
perror("fail to malloc");
return -1;
}
ptmpnode->data = tmpdata;
ptmpnode->pnext = phead->pnext;
phead->pnext = ptmpnode;
return 0;
}

/* 出栈 */
datatype pop_linkstack(linknode *phead)
{

        datatype retval;
linknode *ptmpnode = NULL;
if (is_empty_linkstack(phead))
{
return -1;
}

        //删除第一个有效元素
ptmpnode = phead->pnext;
phead->pnext = ptmpnode->pnext;
retval = ptmpnode->data;
free(ptmpnode);
//返回数据
return retval;

}
/* 销毁栈 */
int destroy_linkstack(linknode **pphead)
{
linknode *ptmpnode = NULL;
linknode *pfreenode = NULL;
ptmpnode = pfreenode = *pphead;
while (ptmpnode != NULL)
{
ptmpnode = ptmpnode->pnext;
free(pfreenode);
pfreenode = ptmpnode;
}
*pphead = NULL;
return 0;
}

三、队列

1.基础概念

先进先出,后进后出

队头:出队的一端

队尾:入队的一端

入队:将元素放入队列末尾

 出队:将元素从队头中取出

2.分类

(1)循环队列

①定义

typedef int datatype;

typedef struct queue
{
datatype *pdata;         //存放数据空间的首地址
int head;                     //头下标
int tail;                        //尾下标
int tlen;                      //最多存放元素个数
}seqqueuee

②循环队列创建

seqqueue *create_seqqueue(int len)
{
seqqueue *ptmpqueue = NULL;
ptmpqueue = malloc(sizeof(seqqueue));
if (NULL == ptmpqueue)
{
perror("fail to malloc");
return NULL;
}
ptmpqueue->pdata = malloc(sizeof(datatype) * len);
if (NULL == ptmpqueue->pdata)
{
perror("fail to malloc");
return NULL;
}

        ptmpqueue->head = 0;
ptmpqueue->tail = 0;
ptmpqueue->tlen = len;
return ptmpqueue;
}

③ 循环队列销毁

int destroy_seqqueue(seqqueue **pptmpqueue)
{
free((*pptmpqueue)->pdata);
free(*pptmpqueue);
*pptmpqueue = NULL;
return 0;
}

④判断循环队列是否为空

int is_empty_seqqueue(seqqueue *ptmpqueue)
{
return ptmpqueue->head == ptmpqueue->tail;
}

⑤ 判断循环队列是否为满

1)为避免循环队列空与满的条件冲突,牺牲一个存放数据的空间,将tail+1 == head作为判断队满的条件

2)循环队列如果head或者tail下标超过tlen范围,需要对tlen取余,保障head和tail的值在队列下标范围内变化

int is_full_seqqueue(seqqueue *ptmpqueue)
{
return ((ptmpqueue->tail + 1) % ptmpqueue->tlen) ==
ptmpqueue->head;
}

⑥入队

int enter_seqqueue(seqqueue *ptmpqueue, datatype tmpdata)
{
if (is_full_seqqueue(ptmpqueue))
{
return -1;
}
ptmpqueue->pdata[ptmpqueue->tail] = tmpdata;
ptmpqueue->tail = (ptmpqueue->tail + 1) % ptmpqueue->tlen;
return 0;
}

⑦出队

datatype quit_seqqueue(seqqueue *ptmpqueue)
{
datatype retval;
if (is_empty_seqqueue(ptmpqueue))
{
return -1;
}
retval = ptmpqueue->pdata[ptmpqueue->head];
ptmpqueue->head = (ptmpqueue->head + 1) % ptmpqueue->tlen;
return retval;
}

(2)链式队列

使用链表的思想实现链式队列,参考单向链表节点定义,入队使用尾插法,出队返回链表第一个有效节点的值,并删除该节点,在主函数循环出栈队,销毁栈参考单向链表的销毁

#include "linkstack.h"
#include <stdio.h>
#include <stdlib.h>

linknode *create_empty_linkstack(void)
{
linknode *ptmpnode = NULL;

    ptmpnode = malloc(sizeof(linknode));
if (NULL == ptmpnode)
{
perror("fail to malloc");
return NULL;
}

    ptmpnode->pnext = NULL;

    return ptmpnode;
}

int is_empty_linkstack(linknode *phead)
{
return NULL == phead->pnext;
}

int push_linkstack(linknode *phead, datatype tmpdata)
{
linknode *ptmpnode = NULL;

    ptmpnode = malloc(sizeof(linknode));
if (NULL == ptmpnode)
{
perror("fail to malloc");
return -1;
}

    ptmpnode->data = tmpdata;
ptmpnode->pnext = phead->pnext;
phead->pnext = ptmpnode;

    return 0;
}

datatype pop_linkstack(linknode *phead)
{
linknode *ptmpnode = NULL;
datatype tmpdata = 0;

    ptmpnode = phead->pnext;
tmpdata = ptmpnode->data;
phead->pnext = ptmpnode->pnext;
free(ptmpnode);
ptmpnode  = phead->pnext; 

    return tmpdata;
}

int destory_linkstack(linknode **phead)
{
linknode *ptmpnode = NULL;
linknode *pprenode = NULL;

    ptmpnode = pprenode = *phead;
while(ptmpnode != NULL)
{
ptmpnode = ptmpnode->pnext;
free(pprenode);
pprenode = ptmpnode;
}
*phead = NULL;

    return 0;
}

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

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

相关文章

vue2.如何给一个页面设置动态的name。不同路由使用一样的组件。页面不刷新怎么办?

page里面detail.vue export default { name: detail, } vue2里面.vue的页面都会设置一个name&#xff0c;这个通常是写死的。不能在页面动态设置的。页面刷新缓存通常都是根据这个name来判断的。如果name写死。我几个页面都通用这一个页面的话&#xff0c;他也不刷新页面啊。 比…

浮动IP(Floating IP)的删除通常需要满足什么条件

浮动IP&#xff08;Floating IP&#xff09;的删除通常需要满足什么条件在云计算或网络环境中&#xff0c;浮动IP&#xff08;Floating IP&#xff09;的删除通常需要满足一定的条件&#xff0c;以确保操作不会影响现有业务或导致网络中断。以下是常见的可删除浮动IP的场景和条…

机器学习之随机森林(Random Forest)实战案例

一、算法基础 首先&#xff0c;来介绍一下算法的基础语法 class sklearn.ensemble.RandomForestClassifier(\ n_estimators’warn’,\ criterion’gini’,\max_depthNone, \ min_samples_split2,\ min_samples_leaf1, \ min_weight_fraction_leaf0.0, \ max_features’auto’…

《C语言》指针练习题--1

《C语言》指针练习题–1 1. 交换两个整数的值 题目描述&#xff1a; 编写一个C程序&#xff0c;定义一个函数swap&#xff0c;使用指针参数交换两个整数的值。在main函数中调用该函数并输出交换后的结果。 解题思路&#xff1a; 为了交换两个整数的值&#xff0c;可以通过指针传…

应急响应整理

目录 windows下 1. 检查账号安全 利用注册表实现用户隐藏 粘滞键后门 2 检查异常端口、进程 3. 检查启动项、计划任务、服务 4. 日志分析-Windows 常见事件类型、登录类型 Linux下 1. 账号安全 2. 历史命令 3. 检查异常端口 4. 检查异常进程 5. 检查开机启动项 …

一文读懂 C# 中的 Bitmap

一文读懂 C# 中的 Bitmap 一、Bitmap 到底是什么? 二、推荐使用场景 三、实战 Demo 基础用法:加载、创建和保存 进阶用法 缩放图片 裁剪图片 颜色调整(反色处理) 四、核心方法和属性说明 常用函数 常用属性 五、避坑指南、注意事项 六、总结与决策 一文读懂 C# 中的 Bitmap…

预约时间组件

效果图如何使用<template><view><button click"pickerTime(0)">预约时间0</button><button click"pickerTime(1)">预约时间1</button><button click"pickerTime(2)">预约时间2</button><but…

Android 开发 - Service、Camera、Layout Design 自定义设备类型和大小

一、Service 启动 1、基本介绍 &#xff08;1&#xff09;startService()其他组件通过调用 startService() 启动 Service 后&#xff0c;Service 可在后台无限期运行&#xff0c;即使启动 Service 的组件被销毁也不受影响&#xff0c;一般情况下 startService() 是执行单一操作…

Qwen Image:开源中文渲染SOTA,重塑文生图技术边界

1. Qwen Image的技术定位与行业痛点1.1 文本渲染&#xff1a;文生图领域的长期技术瓶颈传统文生图模型在图像美学与真实感优化上已取得显著进展&#xff0c;但多语言文本渲染始终是行业难以突破的瓶颈。主流模型在处理中文等非字母语言时&#xff0c;常出现字符断裂、布局错位、…

Docker入门教程:在腾讯云轻量服务器上部署你的第一个容器化应用 (2025)

更多云服务器知识&#xff0c;尽在hostol.com“在我电脑上明明是好的啊&#xff01;”这句话&#xff0c;是不是堪称程序员“甩锅”排行榜第一名的金句&#xff1f;当你辛辛苦苦开发完一个应用&#xff0c;把它交给同事或者部署到服务器上时&#xff0c;却发现因为它依赖的某个…

DevOps平台结合Gradle实现打包流水线

在现代软件开发中,持续集成与持续交付(CI/CD)已成为团队提速、降本增效的核心实践。Gradle作为强大的自动化构建工具,常被用于Android与Java项目的构建打包任务。而将Gradle集成进企业的DevOps平台中,不仅可以标准化构建过程,还能自动化打包、测试、发布的全流程,大幅提…

Node.js 操作 MySQL

目录 一、什么是 MySQL&#xff1f; 二、MySQL 的功能概览 三、MySQL 的安装与启动 安装 MySQL 启动服务 四、Node.js 如何连接 MySQL&#xff1f; 使用 mysql2 模块&#xff08;推荐&#xff09; 建立连接 五、创建数据表和插入数据&#xff08;SQL 初始化&#xff09…

解锁高效敏捷:2025年Scrum项目管理工具的核心应用解析

一、为什么Scrum团队需要专业项目管理工具&#xff1f;在敏捷开发实践中&#xff0c;Scrum框架虽然提供了基础的工作流程&#xff0c;但缺乏对任务细粒度管理的支持。传统白板或简单看板工具往往无法满足现代敏捷团队的需求&#xff0c;导致&#xff1a;冲刺规划混乱&#xff1…

途游大数据面试题及参考答案

Java 的反射机制是什么?主要应用在哪些场景? Java的反射机制是指程序在运行时,能够获取自身类的信息(如类名、属性、方法、构造器等),并动态操作这些信息的能力。正常情况下,Java代码编译时类型已确定,而反射打破了这种编译期约束,让程序在运行时灵活操作类和对象。 …

贪心+矩阵算法

贪心算法贪心的本质是&#xff1a;选择每一阶段的局部最优&#xff0c;从而达到全局最优做题的时候&#xff0c;只要想清楚 局部最优 是什么&#xff0c;如果推导出全局最优&#xff0c;其实就够了。买卖股票的最佳实际思路&#xff1a;如果第i天卖出股票&#xff0c;则最大利润…

STM32U5 周期性异常复位问题分析

关键字&#xff1a; Option Bytes, IDWG 1. 问题背景 客户反馈使用 NUCLEO_STM32U575 进行评估时&#xff0c;发现板子烧录完程序后&#xff0c;能看到指示程序运行的 LED 灯正常点亮&#xff0c;但是程序跑不起来。仔细观察 LED 指示灯&#xff0c;并不是常亮而是出现周期性…

RedisBloom使用

安装RedisBloom模块&#xff0c;从git获取对应的原码&#xff0c;make生成.so文件&#xff0c;挂载.so文件&#xff0c;启动redis docker run --name test-redis -v /iothub/test-redis/data:/data -v /iothub/test-redis/modules:/modules -p 6378:6379 -d redis:4.0.10 redis…

ADC、Flash、SPI、watchdog

ADCADC(Analog-to-Digital Converter), 即模拟信号 - 数字信号转换器在STM32F103C8T6中, 同样具有ADC功能.以我们的芯片为例, 也存在2个片上外设ADC, 即ADC1和ADC2, 这两个ADC片上外设都挂载在APB2总线上.我们的ADC片上外设, 是一种具有12位逐次逼近型ADC,ADC转换的本质是不断的…

冷库设备远程监控物联网+省电节能解决方案

随着生鲜电商、医药冷链、跨境物流等行业的爆发式增长&#xff0c;我国冷库容量激增&#xff0c;但传统冷库管理模式正面临严峻挑战。据统计&#xff0c;国内冷链运输损耗率高达12%-15%&#xff0c;其中因温度失控导致的货损占比超60%。在某医药企业冷库事故中&#xff0c;因制…

如何开发一个运行在windows系统服务器上的服务

第一步&#xff1a;vs2022创建一个windows服务项目第二步&#xff1a;从工具箱拖拽出一个timer第三步&#xff1a;按下图所示进入&#xff0c;开始编辑业务逻辑下面给个例子using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; …