数据结构与算法教程,数据结构C语言版教程!(第三部分、栈(Stack)和队列(Queue)详解)二

 第三部分、栈(Stack)和队列(Queue)详解

栈和队列,严格意义上来说,也属于线性表,因为它们也都用于存储逻辑关系为 "一对一" 的数据,但由于它们比较特殊,因此将其单独作为一章,做重点讲解。

使用栈结构存储数据,讲究“先进后出”,即最先进栈的数据,最后出栈;使用队列存储数据,讲究 "先进先出",即最先进队列的数据,也最先出队列。

既然栈和队列都属于线性表,根据线性表分为顺序表和链表的特点,栈也可分为顺序栈和链表,队列也分为顺序队列和链队列,这些内容都会在本章做详细讲解。

三、链栈及基本操作(包含入栈和出栈)详解

链栈,即用链表实现栈存储结构。

链栈的实现思路同顺序栈类似,顺序栈是将数顺序表(数组)的一端作为栈底,另一端为栈顶;链栈也如此,通常我们将链表的头部作为栈顶,尾部作为栈底,如图 1 所示:

链栈示意图

图 1 链栈示意图

将链表头部作为栈顶的一端,可以避免在实现数据 "入栈" 和 "出栈" 操作时做大量遍历链表的耗时操作。

链表的头部作为栈顶,意味着:

  • 在实现数据"入栈"操作时,需要将数据从链表的头部插入
  • 在实现数据"出栈"操作时,需要删除链表头部的首元节点;

因此,链栈实际上就是一个只能采用头插法插入或删除数据的链表。

1、链栈元素入栈

例如,将元素 1、2、3、4 依次入栈,等价于将各元素采用头插法依次添加到链表中,每个数据元素的添加过程如图 2 所示:

链栈元素依次入栈过程示意图

图 2 链栈元素依次入栈过程示意图

C语言实现代码为:

//链表中的节点结构

typedef struct lineStack{

        int data;

        struct lineStack * next;

}lineStack;

//stack为当前的链栈,a表示入栈元素

lineStack* push(lineStack * stack,int a){

        //创建存储新元素的节点

        lineStack * line=(lineStack*)malloc(sizeof(lineStack));

        line->data=a;

        //新节点与头节点建立逻辑关系

        line->next=stack;

        //更新头指针的指向

        stack=line;

        return stack;

}

2、链栈元素出栈

例如,图 2e) 所示的链栈中,若要将元素 3 出栈,根据"先进后出"的原则,要先将元素 4 出栈,也就是从链表中摘除,然后元素 3 才能出栈,整个操作过程如图 3 所示:

链栈元素出栈示意图

图 3 链栈元素出栈示意图

因此,实现栈顶元素出链栈的 C 语言实现代码为:

//栈顶元素出链栈的实现函数

lineStack * pop(lineStack * stack){

        if (stack) {

                //声明一个新指针指向栈顶节点

                lineStack * p=stack;

                //更新头指针

                 stack=stack->next;

                printf("出栈元素:%d ",p->data);

                if (stack) {

                        printf("新栈顶元素:%d\n",stack->data);

                }else{

                        printf("栈已空\n");

                }

                free(p);

        }else{

                printf("栈内没有元素");

                return stack;

        }

        return stack;

}

代码中通过使用 if 判断语句,避免了用户执行"栈已空却还要数据出栈"错误操作。

3、总结

本节,通过采用头插法操作数据的单链表实现了链栈结构,这里给出链栈及基本操作的C语言完整代码:

#include <stdio.h>

#include <stdlib.h>

typedef struct lineStack{

        int data;

        struct lineStack * next;

}lineStack;

lineStack* push(lineStack * stack,int a){

        lineStack * line=(lineStack*)malloc(sizeof(lineStack));

        line->data=a;

        line->next=stack;

        stack=line;

        return stack;

}

lineStack * pop(lineStack * stack){

        if (stack) {

                lineStack * p=stack;

                stack=stack->next;

                printf("弹栈元素:%d ",p->data);

                if (stack) {

                        printf("栈顶元素:%d\n",stack->data);

                }else{

                        printf("栈已空\n");

                }

                free(p);

        }else{

                printf("栈内没有元素");

                return stack;

        }

        return stack;

}

int main() {

        lineStack * stack=NULL;

        stack=push(stack, 1);

        stack=push(stack, 2);

        stack=push(stack, 3);

        stack=push(stack, 4);

        stack=pop(stack);

        stack=pop(stack);

        stack=pop(stack);

        stack=pop(stack);

        stack=pop(stack);

        return 0;

}

程序运行结果为:

弹栈元素:4 栈顶元素:3
弹栈元素:3 栈顶元素:2
弹栈元素:2 栈顶元素:1
弹栈元素:1 栈已空
栈内没有元素


 四、[数据结构实践项目]进制转换器

进制转换器项目要求:用户提供需要转换的数据和该数据的进制,以及要转换的进制,进制转换器提供给用户最终的正确转换的结果。

1、转换器实例

例如,用户提供了一个十进制数:10,要求将此数据以二进制形式转换,则通过进制转换器转换的最终结果应该:1010。

提示:此进制转换器可以在 2-36 进制之间对数据进行任意转换。各进制中对应的数字如下表:

2、设计思路

当用户给定 2 - 36 进制中的任意一进制数时,最简单的方法是使用顺序存储结构进行存储,即使用字符串数组存储。

转化时,最直接的思路就是先将该数转化为十进制数据,然后再由十进制转化成要求的进制数,最终的结果用栈结构存储(先进后出),这样最终显示给用户的是正常的数据。

3、实现代码

#include <stdio.h>

#include <string.h>

#include <math.h>

int top=-1;//top变量时刻表示栈顶元素所在位置

void push(char * a,char elem){

        a[++top]=elem;

}

void pop(char * a){

        if (top==-1) {

                return ;

        }

        //输出时要按照正确的格式显示给用户

        if (a[top]>=10) {

                printf("%c",a[top]+55);

        }else{

                printf("%d",a[top]);

        }

        top--;

}

//将各进制数转换成十进制数

int scaleFun(char * data,int system){

        int k=(int)strlen(data)-1;

        int system_10_data=0;

        int i;

        for (i=k; i>=0; i--) {

                int temp;

                if (data[i]>=48 && data[i]<=57) {

                        temp=data[i]-48;

                }else{

                        temp=data[i]-55;

                }

                system_10_data+=temp*pow(system, k-i);

        }

        return system_10_data;

}

int main() {

        char data[100];

        printf("进制转换器,请输入原数据的进制(2-36):");

        int system;

        scanf("%d",&system);

        getchar();

        printf("请输入要转换的数据:");

        scanf("%s",data);

        getchar();

        int system_10_data=scaleFun(data, system);

        printf("请输入转换后的数据的进制:");

        int newSystem;

        scanf("%d",&newSystem);

        getchar();

        while (system_10_data/newSystem) {

                push(data,system_10_data%newSystem );

                system_10_data/=newSystem;

        }

        push(data,system_10_data%newSystem);

        printf("转换后的结果为:\n");

        while (top!=-1) {

                pop(data);

        }

}

运行结果:

进制转换器,请输入原数据的进制(2-36):10
请输入要转换的数据:100
请输入转换后的数据的进制:16
转换后的结果为:
64

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【JVM 基础】 Java 类加载机制

JVM 基础 - Java 类加载机制 类的生命周期类的加载: 查找并加载类的二进制数据连接验证: 确保被加载的类的正确性准备: 为类的静态变量分配内存&#xff0c;并将其初始化为默认值解析: 把类中的符号引用转换为直接引用 初始化使用卸载 类加载器&#xff0c; JVM类加载机制类加载…

「 CodeQL从入门到精通系列 」03.CodeQL常用术语介绍

相比其他代码检测工具&#xff0c;CodeQL中定义了很多专用术语&#xff0c;为了更快上手后续章节&#xff0c;本文对接下来要用到的术语做了统一汇总与解读。 1. 查询语言(QL) QL是一种声明性、面向对象的查询语言&#xff0c;经过优化&#xff0c;可实现对分层数据结构&#…

kafka入门(六):日志分段(LogSegment)

日志分段&#xff08;LogSegment&#xff09; Kafka的一个 主题可以分为多个分区。 一个分区可以有一至多个副本&#xff0c;每个副本对应一个日志文件。 每个日志文件对应一个至多个日志分段&#xff08;LogSegment&#xff09;。 每个日志分段还可以细分为索引文件、日志存储…

mybatis plus相同Id与xml配置错误时,mybatis plus解决逻辑

前言 处理做项目的问题&#xff0c;其中不乏奇奇怪怪的问题&#xff0c;其中mybatis plus的问题感觉有点隐蔽&#xff0c;有些是运行时出现&#xff0c;有些是运行到具体的逻辑触发&#xff0c;对于应用的状态监控提出了极大的挑战&#xff0c;应用的状态由健康检查接口提供&a…

facebook广告的基础知识与类型

Facebook广告是在Facebook平台上展示的一种数字广告形式&#xff0c;它允许广告主通过定位特定的受众群体来推广他们的产品、服务或品牌。以下是一些关于Facebook广告的基础知识&#xff1a; 支持Facebook广告的卡、556150、532959&#xff0c;点击获取 广告形式&#xff1a; …

【Proteus仿真】【Arduino单片机】智能感应温控风扇

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器&#xff0c;使用LCD1602液晶显示模块、DS18B20温度、按键、声光报警、L293D电机驱动等。 主要功能&#xff1a; 系统运行后&#xff0c;LCD1602显示传感器检…

.NET Framework 与 .NET Core 与 .NET Standard 之间的差异

介绍 在本文中&#xff0c;我们将探讨 .NET Framework、.NET Core 和 .NET Standard 之间的差异。 .NET Framework 与 .NET Core .NET框架.NET核心 历史 .NET Framework 是 .NET 的第一个实现。 .NET Core 是 .NET 的最新实现。 开源 .NET Framework 的某些组件是开源的。 .N…

前端实现搜索功能

最近遇到一个需求,用户在输入框输入关键字之后,点击搜索按钮后进行搜索,如下图,选中的数据在下面,上面展现的是搜索后的数据,现在选中了2条数据: 当用户输入KET后点击搜索,搜出的结果有16条,勾选全选选中后,将选中的16条的数据加到之前已选的2条数据里,于是此时已选…

认识Linux指令之 “ head tail ” 命令

01.head指令 head 与 tail 就像它的名字一样的浅显易懂&#xff0c;它是用来显示开头或结尾某个数量的文字区块&#xff0c;head 用来显示档案的开头至标准输出中&#xff0c;而 tail 想当然尔就是看档案的结尾。 语法&#xff1a; head [参数]... [文件]... 功能&#…

SAP CO11N报工批次分割(拆分)

CO11N做报工的时候&#xff0c;下阶料启用了批次&#xff0c;比如需要过账4166个&#xff0c;但是每一批次的库存都不满足4166个&#xff0c;所以需要拆分&#xff08;分割&#xff09;处理 这个时候我们就需要对这一行做分割处理 选中这一行&#xff0c;点击‘分割’按钮 弹…

Speech | 语音克隆Openvoice的论文解读及项目实现

本文主要介绍了语音克隆Openvoice的论文以及项目实现~ 论文题目&#xff1a;OpenVoice: Versatile Instant Voice Cloning 论文地址&#xff1a;2312.01479.pdf (arxiv.org) 项目地址&#xff1a;https://github.com/myshell-ai/OpenVoice.git 官网&#xff1a;Home (myshell.a…

C 练习实例23

题目&#xff1a;打印出如下图案&#xff08;菱形&#xff09;。 * *** ***** ******* ***** *** * 题目分析&#xff1a; 先打印前4行&#xff0c;因为是递增关系。 第0行&#xff1a;打印3个空格&#xff0c;1个* 第1行&#xff1a;打印2个空格&#xff0c;3个*…

【Github-Action】GithubAction 环境下,如何将临时生成的文件推送至指定分支。

通过这篇文章你可以掌握如何将github action 环境下临时生成的文件推送至指定分支&#xff0c;并且可以打开利用github开放的api做各种强大或有趣的事情的视野和思路。 如果你对github-action感兴趣&#xff0c;还可以看这篇文章&#xff0c; 这篇文章教会你如何开发Github Act…

分布式系统架构设计之分布式消息队列中间件的技术选型报告

1、主流消息队列中间件 01 Kafka 基本原理 Kafka 基于发布-订阅模式&#xff0c;它维护了一个或多个 Topic&#xff0c;生产者将消息发送到 Topic&#xff0c;消费者从 Topic 中读取消息。Kafka 强调高吞吐量&#xff0c;通过批量处理、顺序 I/O 和零拷贝等技术实现高性能 …

微信扫码进入小程序特定页面

小程序配置 开发 - 开发管理 - 开发设置-普通链接二维码打开小程序 配置好的截图 如下&#xff1a;二维码规则建议是自己的域名 /mini/ 功能页面 pages/index/index 是为了方便跳转其他页面 记得把校验文件发给后端 web 端处理 二维码格式为&#xff1a;二维码规则/功能页…

基于 SpringBoot + magic-api + Vue3 + Element Plus + amis3.0 快速开发管理系统

Tansci-Boot 基于 SpringBoot2 magic-api Vue3 Element Plus amis3.0 快速开发管理系统 Tansci-Boot 是一个前后端分离后台管理系统&#xff0c; 前端集成 amis 低代码前端框架&#xff0c;后端集成 magic-api 的接口快速开发框架。包含基础权限、安全认证、以及常用的一…

2024美赛数学建模思路 - 复盘:人力资源安排的最优化模型

文章目录 0 赛题思路1 描述2 问题概括3 建模过程3.1 边界说明3.2 符号约定3.3 分析3.4 模型建立3.5 模型求解 4 模型评价与推广5 实现代码 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 描述 …

【深度学习:数据增强】计算机视觉中数据增强的完整指南

【深度学习&#xff1a;数据增强】计算机视觉中数据增强的完整指南 为什么要做数据增强&#xff1f;等等&#xff0c;什么是数据增强&#xff1f;数据增强技术数据增强的注意事项和潜在陷阱什么时候应该做数据增强&#xff1f;类不平衡的数据增强那么我应该选择哪些转换呢&…

【Wordpress高级教程】 Wordpress免插件建立站群,wordpress整站迁移/安装

提示&#xff1a;该方法适用于Wordpress的站点&#xff0c;且无需插件哦&#xff08;插件一般都需要付费的&#xff0c;博主比较穷&#xff0c;我们就通过技术来解决&#xff09; 文章目录 前言一、准备工作二、搭建站群1.打包wp-content2.导入新站点3.导出数据库4.修改数据库配…

redis的高可用(主从复制、哨兵、群集)

redis的高可用&#xff08;主从复制、哨兵、群集&#xff09; 主从复制&#xff1a;主从复制是高可用Redis的基础&#xff0c;哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份&#xff0c;以及对于读操作的负载均衡和简单的故障恢复。缺陷&…