数据结构:基于链式存储的队列

本文探讨了一种基于带头结点单链表实现的链队列,详细介绍了队列的初始化、入队、出队及判空操作,并讨论了代码中存在的问题与改进方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这是一个基于带头结点单链表下实现的的链队列,但是写完我觉得代码中存在如下问题(感觉不够完美)

首先看定义:

#define ElemType int

typedef struct LinkNode{ // 定义每个元素结点 
	ElemType data;
	struct LinkNode *next;
} LinkNode;

typedef struct{ // 定义队列 
	LinkNode *front; // 队首指针 
	LinkNode *rear; // 队尾指针 
} LinkQueue;

初始时队首指针和队尾指针都指向头结点

带头结点的链队列中队首指针指向头结点,队首元素应该时Q.front->next

所以初始化操作这样写:

// 队列带头结点初始化 
void InitQueue(LinkQueue &Q)
{
	// 初始 front和rear都指向头结点,队列为空 
	LinkNode *newNode = (LinkNode *)malloc(sizeof(LinkNode)); // 申请一个结点当作头结点 
	Q.front = newNode;
	Q.rear = newNode; 
	Q.front->next = NULL; // 头结点后无结点表示队列为空 
}

这样就产生了两种判断队列为空的方法

// 判断队列是否为空 
bool QueueIsEmpty(LinkQueue Q) 
{
	return (Q.front == Q.rear) ? true : false;
//	return (Q.front->next == NULL) ? true : false; // 这样也可以 
}

因为删除的时候需要调用判空函数,可以这样写

bool QueuePop(LinkQueue &Q) 
{
	if(QueueIsEmpty(Q)){
		return false;
	}
	if(Q.front->next == Q.rear){ // 如果被删除队列中只剩一个元素,则队尾指针要指向头结点 
		Q.rear = Q.front;
	}
	LinkNode *tmp = Q.front->next; // 等待出队元素 
	Q.front->next = Q.front->next->next; // // 从队列中删除出队元素 
	free(tmp); // 释放空间 
	return true;
}

上面代码段中第二个if判断必不可少,如果缺了,那么Q.front和Q.rear就不会相等了,这样的话即使队列已经为空,但是队列判空函数依然会判断非空。但是由于多了这个if我总感觉不够完美。如果判空函数采用第二种方法只根据Q.front->next == NULL来判断,就可以删除这个if,但是这样Q.rear就有可能成为野指针,同样感觉存在安全隐患。

完整代码:

// 基于带头结点单链表 
#include <stdio.h>
#include <stdlib.h>

#define ElemType int

typedef struct LinkNode{ // 定义每个元素结点 
	ElemType data;
	struct LinkNode *next;
} LinkNode;

typedef struct{ // 定义队列 
	LinkNode *front; // 队首指针 
	LinkNode *rear; // 队尾指针 
} LinkQueue;

// 前置函数声明 
bool QueueIsEmpty(LinkQueue Q);

// 队列带头结点初始化 
void InitQueue(LinkQueue &Q)
{
	// 初始 front和rear都指向头结点,队列为空 
	LinkNode *newNode = (LinkNode *)malloc(sizeof(LinkNode)); // 申请一个结点当作头结点 
	Q.front = newNode;
	Q.rear = newNode; 
	Q.front->next = NULL; // 头结点后无结点表示队列为空 
}

bool QueuePush(LinkQueue &Q, ElemType e) 
{
	LinkNode *newNode = (LinkNode *)malloc(sizeof(LinkNode));
	if(newNode == NULL){ // 申请空间失败 
		return false;
	}
	newNode->data = e;
	newNode->next = NULL; // 新入队元素后面为空 
	Q.rear->next = newNode; // 插入到队尾 
	Q.rear = newNode; // 修改队尾指针指向新的队尾元素 
	return true; 
}
bool QueuePop(LinkQueue &Q) 
{
	if(QueueIsEmpty(Q)){
		return false;
	}
	if(Q.front->next == Q.rear){ // 如果被删除队列中只剩一个元素,则队尾指针要指向头结点 
		Q.rear = Q.front;
	}
	LinkNode *tmp = Q.front->next; // 等待出队元素 
	Q.front->next = Q.front->next->next; // // 从队列中删除出队元素 
	free(tmp); // 释放空间 
	return true;
}
// 获取队首元素 
ElemType GetFront(LinkQueue Q)
{
	if(QueueIsEmpty(Q)){
		printf("队列为空,非法访问"); 
		exit(1); // 终止程序 
	} 
	return Q.front->next->data; 
}
// 判断队列是否为空 
bool QueueIsEmpty(LinkQueue Q) 
{
	return (Q.front == Q.rear) ? true : false;
//	return (Q.front->next == NULL) ? true : false; // 这样也可以 
}
int QueueSize(LinkQueue Q)
{
	int length = 0;
	LinkNode *q = Q.front;
	while(q->next != NULL){
		q = q->next;
		length++;
	}
	return length;
}

bool QueueDestroy(LinkQueue &Q) // 销毁队列 
{
	while(Q.front != NULL){
		LinkNode *tmp = Q.front;
		Q.front = Q.front->next;
		free(tmp);
	}
	Q.front = Q.rear = NULL;
	return true;
}

int main() 
{
	LinkQueue Q;
	InitQueue(Q);
	for(int i = 1; i <= 10; i++){
		QueuePush(Q, i);
	} 
	printf("length = %d\n", QueueSize(Q));
	for(int i = 0; i < 10; i++){
		printf("%d\n", GetFront(Q));
		QueuePop(Q);
	}
	printf("length = %d\n", QueueSize(Q));
	GetFront(Q);
	
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值