链队列的实现

链队列存储结构
在这里插入图片描述
链队列的结点为结构体QNode;队列结构体LinkQueue,用来管理链队列,包含两个结点指针front和rear。

typedef int ElemType;	//队列元素类型
typedef struct QNode {	//结点
	ElemType data;
	QNode* next;
}QNode,*QueuePtr;

struct LinkQueue {
	QueuePtr front;		//队头指针
	QueuePtr rear;		//队尾指针
};

在这里插入图片描述

注意:
链队列包含一个头结点,是为了方便队列的操作,头结点没有有效数据,在队列初始化时就分配的头结点;
队头始终指向头结点,头结点指向首结点;队尾指向最后一个结点。当队列为空时,front和rear都指向头结点。
尾结点后为空,可以以NULL作为结束条件,遍历到后面包括尾结点的所有结点。
在这里插入图片描述
基本操作

1.初始化
分配一个头结点,将队列的front和rear指针指向头结点,头结点下一个结点为NULL。

void InitQueue(LinkQueue& Q) {
	Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));
	if (!Q.front)	exit(-1);
	Q.front->next=NULL;
}

2.销毁
在这里插入图片描述
销毁后包括头结点在内的链表都被释放,只有队列结构体LinkQueue,将里面的数据清空。
队尾元素后为空,所以以为空作为结束的条件。

void DestroyQueue(LinkQueue& Q) {
	while (Q.front) {
		Q.rear = Q.front->next;
		free(Q.front);
		Q.front = Q.rear;
	}
}
void DestroyQueue(LinkQueue& Q) {
	QueuePtr p;
	while (Q.front != Q.rear) {
		p = Q.front->next;
		free(Q.front);
		Q.front= p;
	}
	free(Q.rear);
	Q.front = Q.rear = NULL;
}

3.清空
在这里插入图片描述
队列清空时,还有头结点,队列的front和rear指针都指向头结点。

void ClearQueue(LinkQueue& Q) {
	QueuePtr p = Q.front->next,q;//p指向首结点
	Q.rear=Q.front;
	Q.front->next = NULL;
	while (p) {
		q = p->next;
		free(p);
		p = q;
	}
}
void ClearQueue(Queue &Q) {
	QueuePtr p=Q.front->next,q;	//p指向首结点
	while (p) {
		q = p->next;
		free(p);
		p = q;
	}
	Q.rear = Q.front;
	Q.rear->next = NULL;
}

4.队空
队首后不为空时或者队首等于队尾时为空

bool QueueEmpty(LinkQueue Q) {
	if (Q.front->next==NULL)
		return true;
	else
		return false;
}
bool QueueEmpty(Queue Q) {
	if (Q.rear == Q.front)
		return true;
	else
		return false;
}

5.长度
由队首遍历到队尾并计数。

int QueueLength(LinkQueue Q) {
	int n = 0;
	QueuePtr p = Q.front;
	while (p != Q.rear) {
		p=p->next;
		++n;
	}
	return n;
}

6.队头
队列不为空时,返回队头元素。队头为front指针的下一个位置。

bool GetHead(LinkQueue Q,ElemType &e) {
	if (Q.front==Q.rear)	//队空
		return false;
	e = Q.front->next->data;
	return true;
}

7.入队
在队尾Q.rear后插入元素,注意最后要改变尾指针指向。

void EnQueue(LinkQueue& Q, ElemType e) {
	QueuePtr p = (QueuePtr)malloc(sizeof(QNode));
	if (!p)		exit(-1);// 存储分配失败
	p->data = e;
	p->next = NULL;
	Q.rear->next = p;
	Q.rear=p;	//改变尾指针指向
}

8.出队
队列不为空时,释放头结点后的节点;注意,如果只有一个结点时,出队后队列为空,需要将队尾指针指向头结点。

bool DeQueue(LinkQueue& Q, ElemType& e) {
	if (Q.front == Q.rear)	return false;	//队空
	QueuePtr p = Q.front->next;	//p指向首结点
	e = p->data;
	Q.front->next = p->next;
	if (Q.rear == p)//队列只有一个元素要改变尾指针指向
		Q.rear = Q.front;
	free(p);
	return true;
}

9.遍历
从队首遍历到队尾。

void QueueTraverse(LinkQueue Q,void(*vi)(ElemType)) {
	QueuePtr p = Q.front->next;	//p指向首结点
	while (p) {
		vi(p->data);
		p = p->next;
	}
	printf("\n");
}

测试函数

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>

void visit(ElemType e)
{
	printf("%d ", e);
}

int main() {
	ElemType n;
	LinkQueue q;
	InitQueue(q);
	printf("成功地构造了一个空队列!\n");
	printf("是否空队列?%d(1:空 0:否) ", QueueEmpty(q));
	printf("队列的长度为%d\n", QueueLength(q));
	EnQueue(q, -5);
	EnQueue(q, 5);
	EnQueue(q, 10);
	printf("插入3个元素(-5,5,10)后,队列的长度为%d\n", QueueLength(q));
	printf("是否空队列?%d(1:空 0:否) ", QueueEmpty(q));
	printf("队列的元素依次为");
	QueueTraverse(q, visit);
	if (GetHead(q, n))
		printf("队头元素是:%d\n", n);
	DeQueue(q, n);
	printf("删除了队头元素%d\n", n);
	if (GetHead(q, n))
		printf("新的队头元素是:%d\n", n);
	ClearQueue(q);
	printf("清空队列后,q.front=%u q.rear=%u q.front->next=%u\n", q.front, q.rear, q.front->next);
	DestroyQueue(q);
	printf("销毁队列后,q.front=%u q.rear=%u\n", q.front, q.rear);
}

测试结果
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值