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

【数据结构】队列的顺序存储与链式存储(C语言版)

队列的顺序存储与链式存储(C语言版)

  • 一、队列的顺序存储(初始化、判断队空、入队、出队、获取队头元素、获取当前队列的元素个数)
  • 二、带头结点队列的链式存储(初始化、判断队空、入队、出队、获取队头元素、获取当前队列的元素个数)
  • 三、链式存储的问题答疑
        • 1. 为什么 `s` 必须是指针类型?
        • 2. `->` 和 `.` 的区别
        • 3. 获取队列元素个数
        • 4. 初始化函数解析

一、队列的顺序存储(初始化、判断队空、入队、出队、获取队头元素、获取当前队列的元素个数)

#include <stdio.h>
using namespace std;/*
循环队列: 
队空:Q.front == Q.rear
队满:(Q.rear + 1) % MaxSize == Q.front 
队伍长度:(Q.rear + MaxSize - Q.front) % MaxSize 
队头指针+1:(Q.front+1) % MaxSize
队尾指针+1:(Q.rear+1) % MaxSize
*/#define MaxSize 50
typedef struct{int data[MaxSize]; // 队列int front, rear; // 队头指针、队尾指针 
}SqQueue;//InitQueue(&Q):初始化队列,构造一个空队列Q。
void InitQueue(SqQueue &Q){Q.front = Q.rear = 0;
}//QueueEmpty(Q):判队列空,若队列为空返回true,否则返回false。
bool QueueEmpty(SqQueue Q){if(Q.front == Q.rear) return true;return false;
}//EnQueue (&Q,x):入队,若队列Q未满,将x加入,使之成为新的队尾。
bool EnQueue(SqQueue &Q, int x) {if((Q.rear + 1) % MaxSize == Q.front) return false;Q.data[Q.rear] = x;Q.rear = (Q.rear + 1) % MaxSize;return true;
}//DeQueue(&Q,&x):出队,若队列Q非空,删除队首元素,并用x返回。
bool DeQueue(SqQueue &Q, int &x){if(Q.front == Q.rear) return false;x = Q.data[Q.front];Q.front = (Q.front + 1) % MaxSize;return true;
}//GetHead (Q,&x):读队首元素,若队列Q非空,则将队首元素赋值给x。
bool GetHead(SqQueue Q, int &x) {if(Q.front == Q.rear) return false;x = Q.data[Q.front];return true;
}// GetLength(Q,&l): 获取队列长度
int GetLength(SqQueue Q){return (Q.rear + MaxSize - Q.front) % MaxSize;
}int main() {bool flag = true;SqQueue Q;InitQueue(Q);while(flag) {printf("\n===============================\n");printf("1.入队\n");printf("2.出队\n");printf("3.判队列空\n");printf("4.读队首元素\n");printf("5.获取队列长度\n");printf("6.结束\n");printf("===============================\n");printf("选择:");int choose;scanf("%d", &choose);switch(choose){case 1:printf("输入新入队的数:");int num;scanf("%d", &num);if(EnQueue(Q, num)) printf("%d入队成功!\n", num);else printf("入队失败!\n");break; case 2:int deNum;if(DeQueue(Q, deNum)) printf("此时出队的曾队头元素是:%d\n", deNum);else printf("出队失败!\n");break;case 3:if(QueueEmpty(Q)) printf("此时队列为空!\n");else printf("此时队列仍然不为空!\n");break;case 4:int geNum;if(GetHead(Q, geNum)) printf("此时的队首元素为%d\n", geNum);else printf("获取失败!\n");break;case 5:printf("此时的队列长度为: %d\n", GetLength(Q));break;case 6:flag = false;} } }

二、带头结点队列的链式存储(初始化、判断队空、入队、出队、获取队头元素、获取当前队列的元素个数)

#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;typedef struct LinkNode{ // 队列结点int data; // 数据struct LinkNode *next; // 指针 
}LinkNode;typedef struct{LinkNode *front, *rear; // 头指针、尾指针 
}LinkQueue;//InitQueue(&Q): 初始化队列,构造一个空队列Q。
void InitQueue(LinkQueue &Q){// front 和 rear 都指向这个头结点,注意:头结点不存储有效数据(仅作为哨兵节点) Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode)); // malloc() 返回的是内存地址(指针),不是结构体实例本身,所以是(LinkNode*) Q.front->next = NULL;
}//QueueEmpty(Q): 判队列空,若队列Q为空返回true,否则返回false。
bool QueueEmpty(LinkQueue Q){if(Q.front == Q.rear) return true;return false;
}//EnQueue (&Q,x): 入队,将x加入,使之成为新的队尾。
bool EnQueue(LinkQueue &Q, int x){LinkNode *s = (LinkNode*)malloc(sizeof(LinkNode)); // 新结点s->data = x;s->next = NULL;Q.rear->next = s;Q.rear = s;return true;
} //DeQueue(&Q, &x): 出队,若队列Q非空,删除队首元素,并用x返回。
bool DeQueue(LinkQueue &Q, int &x){if(Q.front == Q.rear) return false;LinkNode *p = Q.front->next; // 临时存储队头结点(头结点的下一位) x = p->data;Q.front->next = p->next;if(Q.rear == p) {Q.front = Q.rear;} free(p); return true;
}//GetHead (Q,&x):读队首元素,若队列Q非空,则将队首元素赋值给x。
bool GetHead(LinkQueue Q, int &x){if(Q.front == Q.rear) return false;x = Q.front->next->data; // 指针访问成员必须用 ->,不能用 . return true;
}// 获取当前队列的元素个数 
int GetLength(LinkQueue Q){int length = 0;LinkNode *p = Q.front->next;while(p != NULL){length++;p = p->next;}return length;
} int main() {LinkQueue Q;InitQueue(Q); // 初始化队列bool flag = true;while(flag) {printf("\n===============================\n");printf("1.入队\n");printf("2.出队\n");printf("3.判队列空\n");printf("4.读队首元素\n");printf("5.获取队列当前元素个数\n");printf("6.结束\n");printf("===============================\n");printf("选择:");int choose;scanf("%d", &choose);switch(choose){case 1:int x1; printf("输入要入队的值:");scanf("%d", &x1);if(EnQueue(Q, x1)) printf("%d成功入队!\n", x1);else printf("入队失败!\n");break;case 2:int x2;if(DeQueue(Q, x2)) printf("%d成功出队!\n", x2);else printf("出队失败!\n");break;case 3:if(QueueEmpty(Q)) printf("队列为空!\n");else printf("此时队列仍不为空!\n");break;case 4:int x3;if(GetHead(Q, x3)) printf("此时队头元素是:%d\n", x3);else printf("获取失败!\n");break;case 5:int len;len = GetLength(Q);printf("队列的当前元素个数是:%d\n", len);break; case 6:flag = false;break;default:printf("非法输入!\n");break;} } 
} 

三、链式存储的问题答疑

1. 为什么 s 必须是指针类型?
LinkNode *s = (LinkNode*)malloc(sizeof(LinkNode)); // 正确
// LinkNode s = (LinkNode)malloc(sizeof(LinkNode)); // 错误
  • 内存分配原理malloc() 返回的是内存地址(指针),不是结构体实例本身
  • 动态内存管理
    • 队列需要动态创建/销毁节点
    • 指针允许我们操作堆(heap)内存中的对象
    • 结构体变量是栈(stack)对象,函数结束时会自动销毁
  • 类型匹配
    • malloc 返回 void* 需要强制转换为 LinkNode*
    • 不能将指针赋值给结构体变量(类型不匹配)
2. ->. 的区别
操作符适用对象示例等效写法
.结构体实例node.data直接访问成员
->结构体指针ptr->data(*ptr).data

错误分析

x = Q.front->next->data;  // 正确(两级指针访问)
x = Q.front->next.data;   // 错误
  • Q.front 是指针 → 必须用 ->
  • Q.front->next 返回的是指针(LinkNode*),不是结构体实例
  • 指针访问成员必须用 ->,不能用 .
3. 获取队列元素个数

实现方案

int QueueLength(LinkQueue Q) {int count = 0;LinkNode *p = Q.front->next;  // 跳过头结点while(p != NULL) {count++;p = p->next;}return count;
}

优化建议(推荐):

typedef struct {LinkNode *front, *rear;int length;  // 新增长度计数器
} LinkQueue;// 初始化时设置 length=0
void InitQueue(LinkQueue &Q) {Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));Q.front->next = NULL;Q.length = 0;  // 初始化长度
}// 入队操作增加
bool EnQueue(LinkQueue &Q, int x) {// ...原有代码...Q.length++;  // 增加长度计数return true;
}// 出队操作减少
bool DeQueue(LinkQueue &Q, int &x) {// ...原有代码...Q.length--;  // 减少长度计数return true;
}
4. 初始化函数解析
Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));
  • 创建头结点:在堆内存分配一个 LinkNode 结构体
  • 指针赋值
    • frontrear 都指向这个头结点
    • 头结点不存储有效数据(仅作为哨兵节点)
  • 队列状态
    • front->next = NULL → 空队列标志
    • front == rear → 队列为空
http://www.dtcms.com/a/313381.html

相关文章:

  • 基于深度学习的医学图像分析:使用变分自编码器(VAE)实现医学图像生成
  • (FD Conv)Frequency Dynamic Convolution for Dense Image Prediction论文精读(逐段解析)
  • 07.config 命令实现动态修改配置和慢查询
  • [硬件电路-138]:模拟电路 - 什么是正电源?什么是负电源?集成运放为什么有VCC+和VCC-
  • Unix 发展史概览
  • 探索 Zephyr 项目:高效、可扩展的实时操作系统
  • 源代码本地安装funasr
  • C语言数据结构(6)贪吃蛇项目1.贪吃蛇项目介绍
  • 有限元方法中的数值技术:三角矩阵求解
  • Vulnhub Corrosion2靶机复现
  • 机器人抓取流程介绍与实现——机器人抓取系统基础系列(七)
  • 腾讯云CentOS7镜像配置指南
  • Pytorch实现一个简单的贝叶斯卷积神经网络模型
  • Java 中也存在类似的“直接引用”“浅拷贝”和“深拷贝”
  • [创业之路-530]:创业公司五维架构设计:借鉴国家治理智慧,打造敏捷型组织生态
  • mysql8.0集群技术
  • 第13章 文件输入/输出
  • 知识蒸馏 - 基于KL散度的知识蒸馏 HelloWorld 示例 KL散度公式对应
  • 文件拷贝-代码
  • Doris json_contains 查询报错
  • 数据结构总纲以及单向链表详解:
  • 【LeetCode刷题指南】--对称二叉树,另一颗树的子树
  • [创业之路-531]:知识、技能、技术、科学之间的区别以及它们对于职业的选择的指导作用?
  • 【OpenGL】LearnOpenGL学习笔记02 - 绘制三角形、矩形
  • 13-day10生成式任务
  • 基于MBA与BP神经网络分类模型的特征选择方法研究(Python实现)
  • 在ANSYS Maxwell中对永磁体无线充电进行建模
  • 【大模型核心技术】Agent 理论与实战
  • 【设计模式】5.代理模式
  • Manus AI与多语言手写识别