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

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

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

cpp 复制代码
#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;
		} 
	} 
	
}

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

c 复制代码
#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 必须是指针类型?
c 复制代码
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

错误分析

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

实现方案

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

优化建议(推荐):

c 复制代码
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. 初始化函数解析
c 复制代码
Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));
  • 创建头结点 :在堆内存分配一个 LinkNode 结构体
  • 指针赋值
    • frontrear 都指向这个头结点
    • 头结点不存储有效数据(仅作为哨兵节点)
  • 队列状态
    • front->next = NULL → 空队列标志
    • front == rear → 队列为空
相关推荐
小xin过拟合14 分钟前
day20 二叉树part7
开发语言·数据结构·c++·笔记·算法
刘 大 望22 分钟前
网络编程--TCP/UDP Socket套接字
java·运维·服务器·网络·数据结构·java-ee·intellij-idea
寻星探路1 小时前
数据结构青铜到王者第三话---ArrayList与顺序表(1)
数据结构
今后1231 小时前
【数据结构】顺序表详解
数据结构·顺序表
啟明起鸣1 小时前
【数据结构】B 树——高度近似可”独木成林“的榕树——详细解说与其 C 代码实现
c语言·开发语言·数据结构
这周也會开心1 小时前
数据结构-ArrayList
数据结构
nonono1 小时前
数据结构——线性表(链表,力扣中等篇,技巧型)
数据结构·leetcode·链表
hrrrrb1 小时前
【数据结构】栈和队列——队列
数据结构
XMZH030421 小时前
数据结构:单向链表的逆置;双向循环链表;栈,输出栈,销毁栈;顺序表和链表的区别和优缺点;0825
数据结构·链表·
lxmyzzs1 小时前
【图像算法 - 23】工业应用:基于深度学习YOLO12与OpenCV的仪器仪表智能识别系统
人工智能·深度学习·opencv·算法·计算机视觉·图像算法·仪器仪表识别