目录
前言
1.什么是链队
2.链队的表示和实现
1.定义
2.初始化
3.销毁
4.清空
5.空队列
6.队列长度
7.获取队头
8.入队
9.出队
10.遍历队列
11.完整代码
前言
本篇博客介绍链栈队列的表示和实现。
1.什么是链队
链队是采用链式存储结构实现的队列。通常链队使用单链表表示。
图1.链队的示意图
为了操作方便,我们给链队列增加一个头结点,令头指针始终指向头结点。
2.链队的表示和实现
1.定义
typedef int QElemType;
typedef int Status;
typedef struct QNode{
QElemType data;
struct QNode * next;
}QNode,*QueuePtr;
typedef struct {
QueuePtr front;//队头指针
QueuePtr rear;//队尾指针
}LinkQueue;
2.初始化
初始化的时候给链队分配一个结点。
图2.空队列
//初始化
Status initLinkQueue(LinkQueue * linkQueue){
linkQueue->front = linkQueue->rear = (QueuePtr)malloc(sizeof(QNode));
if (!linkQueue->front) {
return 0;
}
return 1;
}
3.销毁
当需要销毁队列时,我们需要释放队列中所有节点的内存,并将队列结构体中的指针置空。
我们需要遍历所有的结点,释放结点内存,最后置空头结点。
// 销毁队列
void destroyLinkQueue(LinkQueue *linkQueue) {
while (linkQueue->front) { // 循环释放队列中所有节点的内存
QueuePtr temp = linkQueue->front;
linkQueue->front = linkQueue->front->next;
free(temp);
}
linkQueue->rear = NULL; // 将 rear 指针置空
}
4.清空
清空队列的方法与销毁队列的方法类似,但不释放队列结构体本身的内存,只释放队列中节点的内存并将队列恢复到初始状态。
// 清空队列
void clearLinkQueue(LinkQueue *linkQueue) {
while (linkQueue->front) { // 循环释放队列中所有节点的内存
QueuePtr temp = linkQueue->front;
linkQueue->front = linkQueue->front->next;
free(temp);
}
linkQueue->rear = NULL; // 将 rear 指针置空
}
5.空队列
队头和队尾相同的时候为空队列。
// 判断队列是否为空
Status isLinkQueueEmpty(LinkQueue *linkQueue) {
return linkQueue->front == NULL; // 如果队头指针为空,则队列为空
}
6.队列长度
// 计算队列长度
int getLinkQueueLength(LinkQueue *linkQueue) {
int length = 0;
QueuePtr p = linkQueue->front->next; // 从队头指针开始
while (p != NULL) { // 遍历队列
length++;
p = p->next;
}
return length;
}
7.获取队头
获取队头元素。
// 获取队列头结点
Status getLinkQueueFront(LinkQueue *linkQueue, QElemType *element) {
if (linkQueue->front == NULL) { // 队列为空
return 0;
}
*element = linkQueue->front->next->data; // 将队头节点的数据存储到 element 中
return 1;
}
8.入队
入队列的时候如下所示。
图3.入队列示意图
// 入队列
Status enLinkQueue(LinkQueue * linkQueue,QElemType element){
QueuePtr newNode = (QNode *)malloc(sizeof(QNode));//生成一个新节点
if (!newNode) {
return 0;
}
newNode->data = element;
newNode->next = NULL;
linkQueue->rear->next = newNode;
linkQueue->rear = newNode;
return 1;
}
9.出队
出队列的时候如下如所示:
图4.出队列示意图
// 出队列
Status deLinkQueue(LinkQueue * linkQueue,QElemType *element){
if (linkQueue->front == linkQueue->rear) {//空队列
return 0;
}
QueuePtr p = linkQueue->front->next;// 指向头结点
* element = p->data;
linkQueue->front->next = p->next;//修改头指针
if (linkQueue->front == p) {//如果仅有一个节点
linkQueue->rear = linkQueue->front;//修改尾指针
}
free(p);
return 1;
}
10.遍历队列
// 遍历队列(忽略头结点)
void traverseLinkQueueIgnoreHead(LinkQueue *linkQueue) {
if (linkQueue->front == NULL || linkQueue->front->next == NULL) { // 队列为空或只有头结点
printf("队列为空\n");
return;
}
QueuePtr current = linkQueue->front->next; // 从头结点的下一个节点开始遍历
while (current != NULL) { // 遍历直到队尾
printf("%d\t", current->data); // 打印当前节点的数据
current = current->next; // 移动到下一个节点
}
printf("\n");
}
11.完整代码
#include <stdlib.h>
typedef int QElemType;
typedef int Status;
typedef struct QNode{
QElemType data;
struct QNode * next;
}QNode,*QueuePtr;
typedef struct {
QueuePtr front;//队头指针
QueuePtr rear;//队尾指针
}LinkQueue;
//初始化
Status initLinkQueue(LinkQueue * linkQueue){
linkQueue->front = linkQueue->rear = (QueuePtr)malloc(sizeof(QNode));
if (!linkQueue->front) {
return 0;
}
return 1;
}
// 销毁队列
void destroyLinkQueue(LinkQueue *linkQueue) {
while (linkQueue->front) { // 循环释放队列中所有节点的内存
QueuePtr temp = linkQueue->front;
linkQueue->front = linkQueue->front->next;
free(temp);
}
linkQueue->rear = NULL; // 将 rear 指针置空
}
// 清空队列
void clearLinkQueue(LinkQueue *linkQueue) {
while (linkQueue->front) { // 循环释放队列中所有节点的内存
QueuePtr temp = linkQueue->front;
linkQueue->front = linkQueue->front->next;
free(temp);
}
linkQueue->rear = NULL; // 将 rear 指针置空
}
// 判断队列是否为空
Status isLinkQueueEmpty(LinkQueue *linkQueue) {
return linkQueue->front == NULL; // 如果队头指针为空,则队列为空
}
// 计算队列长度
int getLinkQueueLength(LinkQueue *linkQueue) {
int length = 0;
QueuePtr p = linkQueue->front->next; // 从队头指针开始
while (p != NULL) { // 遍历队列
length++;
p = p->next;
}
return length;
}
// 获取队列头结点
Status getLinkQueueFront(LinkQueue *linkQueue, QElemType *element) {
if (linkQueue->front == NULL) { // 队列为空
return 0;
}
*element = linkQueue->front->next->data; // 将队头节点的数据存储到 element 中
return 1;
}
// 遍历队列
// 遍历队列(忽略头结点)
void traverseLinkQueueIgnoreHead(LinkQueue *linkQueue) {
if (linkQueue->front == NULL || linkQueue->front->next == NULL) { // 队列为空或只有头结点
printf("队列为空\n");
return;
}
QueuePtr current = linkQueue->front->next; // 从头结点的下一个节点开始遍历
while (current != NULL) { // 遍历直到队尾
printf("%d\t", current->data); // 打印当前节点的数据
current = current->next; // 移动到下一个节点
}
printf("\n");
}
// 入队列
Status enLinkQueue(LinkQueue * linkQueue,QElemType element){
QueuePtr newNode = (QNode *)malloc(sizeof(QNode));//生成一个新节点
if (!newNode) {
return 0;
}
newNode->data = element;
newNode->next = NULL;
linkQueue->rear->next = newNode;
linkQueue->rear = newNode;
return 1;
}
// 出队列
Status deLinkQueue(LinkQueue * linkQueue,QElemType *element){
if (linkQueue->front == linkQueue->rear) {//空队列
return 0;
}
QueuePtr p = linkQueue->front->next;// 指向头结点
* element = p->data;
linkQueue->front->next = p->next;//修改头指针
if (linkQueue->front == p) {//如果仅有一个节点
linkQueue->rear = linkQueue->front;//修改尾指针
}
free(p);
return 1;
}
void testLinkQueue(void){
LinkQueue queue;
if (initLinkQueue(&queue)) {
printf("链队列初始化成功!\n");
}else {
printf("链队列初始化失败!\n");
}
if (isLinkQueueEmpty(&queue)) {
printf("队列为空\n");
}
printf("队列长度:%d\n",getLinkQueueLength(&queue));
for (int i = 1; i <= 10 ; i++) {
if (enLinkQueue(&queue, i)) {
printf("数据元素%d入队成功!\n",i);
}else{
printf("入队失败!\n");
}
}
printf("遍历链队列初!\n");
if (!isLinkQueueEmpty(&queue)) {
printf("队列不为空\n");
}
QElemType headFront;
if (getLinkQueueFront(&queue, &headFront)) {
printf("队列头结点获取成功,队头元素为:%d\n",headFront);
}
traverseLinkQueueIgnoreHead(&queue);
printf("队列长度:%d\n",getLinkQueueLength(&queue));
printf("队列长度:%d\n",getLinkQueueLength(&queue));
for (int i = 1; i <= 10 ; i++) {
int element;
if (deLinkQueue(&queue, &element)) {
printf("出队列成功,出队列的数据元为素%d!\n",element);
}else{
printf("入队失败!\n");
}
}
destroyLinkQueue(&queue);
}