数据结构C语言练习(两个栈实现队列)

news2025/5/20 18:46:16

一、引言

在数据结构的学习中,我们经常会遇到一些有趣的问题,比如如何用一种数据结构去实现另一种数据结构的功能。本文将深入探讨 “用栈实现队列” 这一经典问题,详细解析解题思路、代码实现以及每个函数的作用,帮助读者更好地理解数据结构之间的转换与应用。

练习题:

1.力扣 232. 用栈实现队列

二、解题思路

队列的特点是先进先出(FIFO),而栈的特点是后进先出(LIFO)。为了用栈实现队列,我们使用两个栈:pushST 和 popST

  • 入队操作(push:直接将元素压入 pushST 栈。
  • 出队操作(pop)和获取队头元素(peek:若 popST 栈为空,将 pushST 栈中的所有元素依次弹出并压入 popST 栈,此时 popST 栈的栈顶元素就是队列的队头元素,然后进行相应的弹出(pop)或返回(peek)操作。
  • 判空操作(empty:只有当 pushST 和 popST 两个栈都为空时,队列才为空。

三、数据结构定义

typedef int STDataType;
typedef struct Stack {
    STDataType* _a;
    int _top;
    int _capacity;
} Stack;

typedef struct {
    Stack pushST;
    Stack popST;
} MyQueue;
  • Stack 结构体表示栈,包含存储数据的数组 _a、栈顶指针 _top 和容量 _capacity
  • MyQueue 结构体包含两个栈 pushST 和 popST,用于实现队列功能。

四、栈的基础操作函数详解

1. 栈初始化(StackInit

void StackInit(Stack* ps) {
    ps->_a = NULL;
    ps->_capacity = ps->_top = 0;
}
  • 功能:初始化栈,将栈的存储数组、容量和栈顶指针都置为初始状态。
  • 步骤:将 _a 置为 NULL_capacity 和 _top 置为 0,表示空栈。

2. 入栈操作(StackPush

void StackPush(Stack* ps, STDataType data) {
    assert(ps);
    if (ps->_capacity == ps->_top) {
        int newCapacity = ps->_capacity == 0 ? 4 : 2 * ps->_capacity;
        STDataType* tmp = (STDataType*)realloc(ps->_a, newCapacity * sizeof(STDataType));
        if (tmp == NULL) {
            perror("Fail realloc");
            exit(1);
        }
        ps->_a = tmp;
        ps->_capacity = newCapacity;
    }
    ps->_a[ps->_top++] = data;
}
  • 功能:将元素压入栈顶。
  • 步骤
    1. 检查栈是否已满,若满则扩容(初始容量为 4,每次扩容为原来的 2 倍)。
    2. 扩容后将新元素插入到栈顶位置,更新 _top 指针。

三、队列操作函数详解

1. myQueueCreate:创建队列

MyQueue* myQueueCreate() {
    MyQueue* pq = (MyQueue*)malloc(sizeof(MyQueue));
    StackInit(&pq->pushST);
    StackInit(&pq->popST);
    return pq;
}

 

  • 功能:创建队列实例。
  • 步骤
    • 为 MyQueue 分配内存,确保存储队列相关数据的空间。
    • 初始化内部的 pushST(入) 和 popST(出) 栈,通过 StackInit 清空栈状态,为后续操作做准备。

2. myQueuePush:入队操作

void myQueuePush(MyQueue* obj, int x) {
    StackPush(&obj->pushST, x);
}

 

  • 功能:将元素加入队列尾部。
  • 原理:直接利用 pushST 栈的入栈操作。入队操作只需关注元素添加,无需处理顺序,因此直接将元素压入 pushST,后续出队时再通过 popST 调整顺序。

3. myQueuePop:出队操作(取后删)

int myQueuePop(MyQueue* obj) {
    if (StackEmpty(&obj->popST)) {
        while (!StackEmpty(&obj->pushST)) {
            StackPush(&obj->popST, StackTop(&obj->pushST));
            StackPop(&obj->pushST);
        }
    }
    int top = StackTop(&obj->popST);
    StackPop(&obj->popST);
    return top;
}

 

  • 功能:移除并返回队列头部元素。
  • 步骤
    • 检查 popST 是否为空。若为空,需将 pushST 中元素转移到 popST,以模拟队列的先进先出。转移过程:不断获取 pushST 栈顶元素(StackTop),压入 popSTStackPush),再弹出 pushST 栈顶元素(StackPop)。
    • 转移完成后,popST 栈顶即为队列头部元素,获取该元素值(StackTop),弹出 popST 栈顶元素(StackPop),并返回元素值。

4. myQueuePeek:获取队头元素(取不删)

int myQueuePeek(MyQueue* obj) {
    if (StackEmpty(&obj->popST)) {
        while (!StackEmpty(&obj->pushST)) {
            StackPush(&obj->popST, StackTop(&obj->pushST));
            StackPop(&obj->pushST);
        }
    }
    return StackTop(&obj->popST);
}

 

  • 功能:返回队列头部元素,不弹出。
  • 逻辑:与 myQueuePop 类似。先确保 popST 有元素(若 popST 空,转移 pushST 元素),再通过 StackTop 获取 popST 栈顶元素,即队列头部元素,不执行弹出操作。

5. myQueueEmpty:判断队列是否为空

bool myQueueEmpty(MyQueue* obj) {
    return StackEmpty(&obj->pushST) && StackEmpty(&obj->popST);
}

 

  • 功能:判断队列是否为空。
  • 原理:队列由 pushST 和 popST 共同维护,只有两者都为空时,队列才为空。通过同时检查两个栈的 StackEmpty 状态实现判断。

6. myQueueFree:释放队列资源

void myQueueFree(MyQueue* obj) {
    StackDestroy(&obj->pushST);
    StackDestroy(&obj->popST);
    free(obj);
}
  • 功能:释放队列及内部栈占用的内存。
  • 步骤
    • 先调用 StackDestroy 销毁 pushST 和 popST 栈,释放栈内部存储元素的内存。
    • 最后释放队列结构体 obj 本身的内存,完成资源清理。

六、总结

通过两个栈的巧妙配合,我们成功地实现了队列的功能。这种实现方式不仅加深了我们对栈和队列特性的理解,还展示了如何通过组合数据结构来解决实际问题。在实际编程中,灵活运用数据结构的特性可以让我们更高效地解决各种问题。希望本文的解析能帮助读者更好地掌握这一经典实现方法。

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

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

相关文章

nextjs使用02

并行路由 同一个页面,放多个路由,, 目录前面加,layout中可以当作插槽引入 import React from "react";function layout({children,notifications,user}:{children:React.ReactNode,notifications:React.ReactNode,user:React.Re…

第2.6节 iOS生成全量和增量报告

2.6.1 简介 在采集了覆盖率数据后,就需要生成对应需求的全量和增量覆盖率报告,以便对测试进行查漏补缺。IOS系统有两种开发语言,所以生成报告的方式也不相同,下面就分别介绍一下Object C和Swift语言如何生成覆盖率报告。 2.6.2 O…

应用分享 | AWG技术突破:操控钻石氮空位色心,开启量子计算新篇章!

利用AWG操作钻石中的氮空位色彩中心 金刚石中的颜色中心是晶格中的缺陷,其中碳原子被不同种类的原子取代,而相邻的晶格位点则是空的。由于色心具有明亮的单光子发射和光学可触及的自旋,因此有望成为未来量子信息处理和量子网络的固态量子发射…

【视觉与语言模型参数解耦】为什么?方案?

一些无编码器的MLLMs统一架构如Fuyu,直接在LLM内处理原始像素,消除了对外部视觉模型的依赖。但是面临视觉与语言模态冲突的挑战,导致训练不稳定和灾难性遗忘等问题。解决方案则是通过参数解耦方法解决模态冲突。 在多模态大语言模型&#xf…

重建二叉树(C++)

目录 1 问题描述 1.1 示例1 1.2 示例2 1.3 示例3 2 解题思路 3 代码实现 4 代码解析 4.1 初始化 4.2 递归部分 4.3 主逻辑 5 总结 1 问题描述 给定节点数为 n 的二叉树的前序遍历和中序遍历结果,请重建出该二叉树并返回它的头结点。 例如输入前序遍历序…

10乱码问题的解释(1)

在计算机中,一个汉字,占几个字节? 针对这个问题,只要你回答出一个具体的数字,就一定是错的!! 前提条件: 当前中文编码使用的是哪种方式(字符集) 计算机存的其实是二进制数字~~ 英文字母,怎么表示的?? ASCII 码表~~ 规定了每个字符,都有一个对应的数字来表示~~ 只是表示英文,…

短视频文案--钓鱼女和滑板女

短视频文案 第一个文案: 1标题:风萧萧兮易水寒,美女钓鱼兮不复还 2内容: 我站在池边的微风中,再也看不到曾经快乐的少女了。 风很凉,凉得心不知前往何处。 水很清,清得深知这里没鱼群。 芦苇…

nginx的自动跳转https

mkdir /usr/local/nginx/certs/ 创建一个目录 然后用openssl生成证书 编辑nginx的配置文件 自动跳转成功 做一个优化,如果访问的时候后面加了其他的uri也一起自动跳转了

python-leetcode 62.搜索插入位置

题目: 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置 方法一:二分查找 假设题意是在排序数组中寻找是否存在一个目标值,则可以…

2. ollama下载及安装deepseek模型

ollamam 1. ollama2. ollama常用命令3. Windows配置Ollama与DeepSeek自定义目录环境3.1 自定义安装3.3 添加到系统变量 1. ollama 官网地址 下载地址 测试安装 deepseek模型下载地址 根据电脑性能下载对应版本 2. ollama常用命令 # 运行模型 ollama run 模型 # 查看模型…

Qt基本框架(1)

本篇主要介绍Qt的基本框架,并实现简单的按钮事件 本文部分ppt、视频截图原链接:[萌马工作室的个人空间-萌马工作室个人主页-哔哩哔哩视频] 1. Qt基本框架介绍 Qt基本框架主要分为两部分:Qt实例对象和Qt窗口。Qt实例对象负责初始化Qt运行时…

动手学深度学习:AlexNet

前言 从这个模型开始,我的数据集主阵地就将从装甲板转移到手语视频数据集,模型开始变得更加复杂,数据集当然也要更复杂啦,我将记录在这个过程中遇到的问题和解决后续。 数据读取 由于是视频数据集,我采取的方法是将…

MySql之binlog与数据恢复(Binlog and Data Recovery in MySQL)

MySql之binlog与数据恢复 什么是binlog binlog我们一般叫做归档日志,他是mysql服务器层的日志,跟存储引擎无关,他记录的是所有DDL和DML的语句,不包含查询语句,binlog是一种逻辑日志,他记录的是sql语句的原…

JDK1.8和Maven、Git安装教程自用成功

一.JDK安装 JRK:java运行环境 JDK:java语言的软件开发工具包;JDK里包含了java开发工具,也包含了JRE 1.下载JDK1.8并安装 Java Downloads | Oracle 进入官网后往下翻,找到JAVA8; 然后选择对应的版本&am…

数据采集助力AI大模型训练

引言使用抓取浏览器采集ebay商品页面选购亮数据AI训练数据总结 引言 AI技术在今天已经是我们工作生活中不可或缺的工具,很多小伙伴也在致力于训练AI模型。高质量的数据是训练强大AI模型的核心驱动力,无论是自然语言处理、计算机视觉还是推荐系统&#xf…

Rust 为什么不适合开发 GUI

前言 在当今科技蓬勃发展的时代,Rust 编程语言正崭露头角,逐步为世界上诸多重要基础设施提供动力支持。从存储海量信息到应用于 Linux 内核,Rust 展现出强大的实力。然而,当涉及构建 GUI(图形用户界面)时&…

消息队列篇--通信协议篇--理解HTTP、TLS和TCP如何协同工作

前面介绍了HTTP/HTTPS,SSL/TLS以及TCP和UDP,这些在网络传输上分别有着自己的作用。为了深入理解下这些概念,本篇重点介绍下HTTP、TLS 和 TCP是如何协同工作的?我们从底层到上层逐步分析每个协议的作用及其相互关系。这些协议共同协…

代码随想录算法训练营第三十四天 | 62.不同路径 63.不同路径II 343.整数拆分

62.不同路径 题目链接:62. 不同路径 - 力扣(LeetCode) 文章讲解:代码随想录 视频讲解:动态规划中如何初始化很重要!| LeetCode:62.不同路径_哔哩哔哩_bilibili 思路:机器人位于一…

2023第十四届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组(真题题解)(C++/Java题解)

记录刷题的过程、感悟、题解。 希望能帮到,那些与我一同前行的,来自远方的朋友😉 大纲: 1、日期统计-(解析)-暴力dfs(😉蓝桥专属 2、01串的熵-(解析)-不要chu…

RK3568-适配ov5647摄像头

硬件原理图 CAM_GPIO是摄像头电源控制引脚,连接芯片GPIO4_C2 CAM_LEDON是摄像头led灯控制引脚,连接芯片GPIO4_C3编写设备树 / {ext_cam_clk: external-camera-clock {compatible = "fixed-clock";clock-frequency = <25000000>;clock-output-names = "…