C++ 顺序队列结构实现与基本操作详解
本文深入解析 C++ 中顺序队列(Sequential Queue)的原理与实现,涵盖从内存申请到核心算法操作的完整过程。作为遵循“先进先出”(FIFO)原则的重要线性结构,队列在并发处理与任务调度中应用广泛。文章提供了基于 SQType 结构体的详细代码实现,包括入队、出队、判空、清空及资源释放,并附带可直接运行的测试主函数,帮助开发者掌握底层数据结构的搭建方法。
结果或目标:理解顺序队列的结构与操作
队列是一种特殊的线性表,其核心特征是允许在一端(队尾 tail)进行插入操作,在另一端(队头 head)进行删除操作。这种机制模拟了现实生活中的排队现象:新加入的元素必须排在队伍最后,而最先到达的元素将优先被处理。
根据存储方式的不同,队列可分为两类:
- 顺序队列结构:使用一组地址连续的内存单元(通常是数组)依次保存数据,通过
head和tail指针管理位置。 - 链式队列结构:利用链表节点动态分配内存来保存元素。
本文将聚焦于顺序队列的 C++ 实现。
准备条件:定义数据结构与基础变量
要实现一个顺序队列,首先需要定义存储数据的类型和容器本身的骨架。我们使用一个名为 DATA 的结构体代表队列中的单个元素,并使用 SQType 来封装整个队列状态。
#define QUEUELEN 10 // 定义队列最大容量
#include <string>
using namespace std;
struct DATA {
string name;
int age;
};
struct SQType {
DATA data[QUEUELEN]; // 用于存储元素的数组
int head; // 指向队头的索引
int tail; // 指向队尾的索引
};
在上述结构中,head 表示下一个待取出元素的索引,tail 表示下一个可插入位置的索引。初始状态下,两者均为 0;当 head == tail 时,队列处于空状态。
真实操作顺序:队列的生命周期与核心功能
第 1 步:初始化与资源管理
在开始使用队列前,必须为其分配内存并重置指针。初始化成功后,应将 head 和 tail 都置为 0。使用完毕后,务必调用释放函数以回收内存,防止内存泄漏。
// 初始化:分配内存并清零指针
SQType *SQTypeInit() {
SQType *q = new SQType;
if (q) {
q->head = 0;
q->tail = 0;
return q;
}
return NULL;
}
// 释放:清理申请的内存空间
void SQTypeFree(SQType *q) {
if (q != NULL) delete q;
}
第 2 步:状态检查(判空与判满)
在进行任何读写操作前,必须检查队列状态。对于顺序队列,可以通过比较指针关系快速判断:
- 判断空:若
head == tail,说明没有有效数据。 - 判断满:若
tail == QUEUELEN,说明数组空间已耗尽。
int SQTypeIsEmpty(SQType *q) {
return (q->head == q->tail);
}
int SQTypeIsFull(SQType *q) {
return (q->tail == QUEUELEN);
}
第 3 步:数据出入(入队与出队)
入队操作:将新元素放入 tail 指向的位置,然后将 tail 加 1。如果此时 tail 已达到上限,则拒绝插入。
int InSQType(SQType *q, DATA data) {
if (q->tail == QUEUELEN) {
cout << "队列已满!操作失败!" << endl;
return 0;
} else {
// 先赋值,后移动指针
q->data[q->tail++] = data;
return 1;
}
}
出队操作:读取 head 指向的元素并将其返回,随后将 head 加 1。此操作不会物理删除数组中的数据,只是逻辑上跳过了该元素。
DATA *OutSQType(SQType *q) {
if (q->head == q->tail) { // 判空保护
cout << "队列已空!操作失败!" << endl;
return NULL;
} else {
// 先取值,后移动指针
return &(q->data[q->head++]);
}
}
第 4 步:辅助操作(清队与查看)
清空队列:不改变内存布局,仅将指针复位至起点,使队列逻辑上变空。
void SQTypeClear(SQType *q) {
q->head = 0;
q->tail = 0;
}
读首元素(Peek):与出队不同,它仅返回头部元素的引用而不修改 head,常用于预览即将处理的数据。
DATA *PeekSQType(SQType *q) {
if (SQTypeIsEmpty(q)) return NULL;
return &(q->data[q->head]);
}
完成判断:完整运行测试实例
以下代码整合了上述所有接口,提供了一个标准的测试流程。用户可通过控制台循环输入数据进行入队,随后演示逐个出队的过程,直观感受 FIFO 特性。
int main() {
SQType *stack; // 注意:此处实际应命名为 queue,但保持原文变量名习惯
DATA data, *p;
// 1. 初始化
stack = SQTypeInit();
// 2. 入队测试
cout << "执行入队列操作:请输入姓名,年龄(年龄输0结束):" << endl;
while (1) {
cin >> data.name >> data.age;
if (data.age == 0) break; // 结束标志
InSQType(stack, data);
}
// 3. 出队与查看
cout << "读取首结点数据:" << endl;
p = PeekSQType(stack);
if (p) cout << p->name << "," << p->age << endl;
cout << "进行出栈操作:" << endl;
p = OutSQType(stack);
if (p) cout << p->name << "," << p->age << endl;
// 4. 循环清空
cout << "继续出队直到为空:" << endl;
while (1) {
if (SQTypeIsEmpty(stack)) {
cout << "所有数据出栈完毕,栈为空!" << endl;
break;
} else {
p = OutSQType(stack);
if (p) cout << p->name << "," << p->age << endl;
}
}
// 5. 释放资源
SQTypeFree(stack);
return 0;
}
程序执行界面参考如下:
简要总结
通过本教程,我们完成了基于数组的顺序队列从定义到核心逻辑的实现。虽然现代 C++ 开发中通常会直接使用标准模板库(STL)中的 <queue> 容器,但理解其底层指针管理与内存控制对于编写高性能、低延迟的代码至关重要。以上就是关于C++顺序队列建立与操作的详细内容,更多关于C++数据结构开发的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













