当前位置: 首页 > news >正文

栈与队列入门:定义、操作及完整 C 语言实现教程

一、用生活场景读懂栈和队列

你是否经历过这些场景?

        1. 奶茶店排队点单:先到的人先下单,后到的人只能排后面(队列);

        2. 收拾碗柜时叠盘子:后叠上去的盘子,要先拿下来才能用到下面的()。

        这两个日常场景,恰好对应了数据结构中两种基础且核心的结构 —— 队列(Queue)和栈(Stack)。它们都是 “线性结构”(数据元素排成一条直线),但因数据操作规则不同,适用场景天差地别。今天就带大家从 “是什么→怎么用→用在哪”,彻底搞懂这对 “孪生兄弟”。

二、队列和栈的差异

1.定义与核心规则

(1)队列(Queue):先进先出(FIFO)

        队列就像一条单向通道,数据从 “队尾” 进入(入队,enqueue),从 “队头” 离开(出队,dequeue),中间元素无法直接操作。比如电影院检票,只有前一个人检票完成,下一个人才能进入。

        核心操作:入队、出队、判断队空、取队头元素、取队尾元素、取元素个数

(2)栈(Stack):后进先出(LILO)

        栈类似一个垂直的容器,数据从 “栈顶” 进入(压栈,push),也只能从 “栈顶” 离开(弹栈,pop),栈底元素最后才能访问。比如叠放的书本,只能先拿最上面的一本。

        核心操作:入栈、出栈、查看栈顶、判断栈空、取栈元素个数

2.可视化对比

特性队列
操作规则先进先出后进先出
插入/删除操作端队尾插入、队头出队列仅栈顶插入/删除
访问限制只能访问队头/队尾元素仅能访问栈顶元素

三、队列和栈的实现

1.队列实现

(1)结构和接口声明(可以根据代码内容尝试自行实现)

#define _CRT_SECURE_NO_WARNINGS
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>typedef int QDataType;
typedef struct QNode
{QDataType val;struct QNode* next;
}QNode;typedef struct Queue
{QNode* phead;QNode* ptail;int size;	//队列数据个数
}Queue;//初始化
void QueueInit(Queue* pq);
//销毁
void QueueDestroy(Queue* pq);
//队尾插入
void QueuePush(Queue* pq,QDataType x);
//队头删除
void QueuePop(Queue* pq);
//取队头数据
QDataType QueueFront(Queue* pq);
//取队尾数据
QDataType QueueBack(Queue* pq);
//队列判空
bool QueueEmpty(Queue* pq);
//队列有效元素个数
int QueueSize(Queue* pq);

(2)接口实现

#define _CRT_SECURE_NO_WARNINGS
#include "Queue.h"//初始化
void QueueInit(Queue* pq)
{assert(pq);pq->phead = pq->ptail = NULL;pq->size = 0;
}//销毁
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;
}//队尾插入
void QueuePush(Queue* pq, QDataType x)
{assert(pq);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("QueuePush::malloc");return;}newnode->val = x;if (pq->phead == NULL){pq->phead = pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}//队头删除
void QueuePop(Queue* pq)
{assert(pq);assert(pq->size!=0);//如果只有一个节点if (pq->phead == pq->ptail){free(pq->phead);pq->phead = pq->ptail = NULL;}else{QNode* next = pq->phead->next;free(pq->phead);pq->phead = next;}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;
}//队列判空
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->size == 0;
}//队列有效元素个数
int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}

2.栈实现

(1)结构和接口声明(可以根据代码内容尝试自行实现)

#define _CRT_SECURE_NO_WARNINGS#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>typedef int STDataType;
typedef struct Stack
{STDataType* a;	// 指向数组的指针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);

(2)接口实现

#define _CRT_SECURE_NO_WARNINGS#include "Stack.h"// 初始化和销毁
void STInit(ST* pst)
{assert(pst);pst->a = NULL;
//	pst->top = -1;	// 指向栈顶元素,为-1时表示无数据-》放数据时要先++pst->top = 0;	// 指向栈顶元素的下一个元素,相当于size了(有效数据个数)-》放数据时要后++pst->capacity = 0;
}void STDestroy(ST* pst)
{assert(pst);free(pst->a);pst->a = NULL;pst->top = 0;	pst->capacity = 0;
}// 入栈 出栈
void STPush(ST* pst, STDataType x)
{assert(pst);// 扩容if (pst->top == pst->capacity){int newcapacity = pst->capacity == 0 ? 4 : 2 * pst->capacity;	//要判断是不是第一次扩容STDataType* tmp = realloc(pst->a, newcapacity * sizeof(STDataType));	//如果realloc给的指针为空相当于mallocif (tmp == NULL){perror("STPush::realloc");return;}pst->a = tmp;pst->capacity = newcapacity;}pst->a[pst->top] = x;pst->top++;
}void STPop(ST* pst)
{assert(pst);pst->top--;
}// 取栈顶数据
STDataType STTop(ST* pst)
{assert(pst);assert(pst->top > 0);return pst->a[pst->top - 1];
}// 栈是否为空
bool STEmpty(ST* pst)
{assert(pst);return pst->top == 0;
}// 数据个数
int STSize(ST* pst)
{assert(pst);return pst->top;
}
http://www.dtcms.com/a/605166.html

相关文章:

  • vue3 + antd + print-js 实现打印功能(含输出PDF)
  • 主动交互和情境感知,AI 硬件是脱离手机屏幕掌控的蓝海机会丨硬件和端侧模型专场@RTE2025 回顾
  • NeurIPS2025丨MIT提出自动化科学发现工具,AutoSciDACT对天文/物理/生物医学等异常数据强敏感
  • Java: 为PDF批量添加图片水印实用指南
  • 使用 Python 将 PDF 转换为 PNG
  • docker desktop 限制wsl使用内存空间
  • 学校网站的建设论文WordPress订阅下载插件
  • 内连接与隐式内连接:SQL连接的本质解析
  • 内存网盘 - Go语言实现的WebDAV内存文件系统
  • 【复习408】操作系统进程描述与控制详解
  • 实战1: worldskills3.vmem
  • redis-manger管理平台
  • 基于SpringBoot与Vue的海外理财系统设计与实现
  • 测开学习DAY28
  • android短视频sdk,灵活集成,快速上线!
  • Android AIDL 的详细讲解和实践指南
  • 制作网站首页教案网站建设外包兼职平台
  • 荆门网站制作网站建设ktv
  • 适合实现多生产者单消费者(MPSC)队列的常见数据结构及其优缺点
  • 【高级机器学习】5. Dictionary learning and Non-negative matrix factorisation
  • PPTX 格式的底层数据结构
  • 前端错误监控与上报:Sentry 接入与自定义告警规则
  • 27.Telnet
  • 多级缓存体系与热点对抗术--速度是用户体验的王道,而缓存是提升速度的银弹
  • CPU 缓存 高并发探索
  • 郑州三牛网站建设企业邮箱号码从哪里查
  • 《C++在量化、KV缓存与推理引擎的深耕》
  • php网站建立教程wordpress 合并js
  • [MSSQL] 读写分离(主从备份)
  • 潮州市住房和城乡建设局网站石英手表网站