1. 程式人生 > 其它 >佇列之鏈佇列詳解(C語言版)

佇列之鏈佇列詳解(C語言版)

技術標籤:資料結構與演算法資料結構

文章目錄


前言

大家好,越努力,越幸運。本篇文章小猿將跟您分享資料結構佇列中的鏈佇列,希望對您有所幫助。

在這裡插入圖片描述

一、鏈佇列的定義

首先我們來看看什麼是佇列?佇列是一種先進先出(FIFO)的線性表,它只允許在表的一端進行插入,而在另一端刪除元素。這和我們日常生活中的排隊是一致的,最早進入佇列的元素最早離開。佇列的結構圖如下所示:
在這裡插入圖片描述
明白了佇列之後,鏈佇列就非常簡單了,用連結串列表示的佇列就簡稱為鏈佇列。一個鏈佇列顯然需要兩個分別指示隊頭和隊尾的指標(分別稱為頭指標和尾指標)才能惟一確定。

二、鏈佇列的結構

結構圖
在這裡插入圖片描述
程式碼描述

//資料型別
#define ElemType int

//佇列結點型別
typedef struct QueueNode
{
	ElemType data;          //資料域
	struct QueueNode *next; //指標域
}QueueNode;

//鏈式佇列管理結構
typedef struct LinkQueue
{
	QueueNode *front;  //隊頭指標
	QueueNode *tail;   //隊尾指標
}LinkQueue;

三、鏈佇列的常用操作

初始化

//初始化佇列
void InitQueue(LinkQueue *Q)
{ //申請頭結點記憶體空間 QueueNode *s = (QueueNode *)malloc(sizeof(QueueNode)); assert(s != NULL); //初始化時,將頭指標和尾指標都指向頭結點 Q->front = Q->tail = s; //將頭結點的下一結點賦空 Q->tail->next = NULL; }

入隊

//入隊操作:在隊尾執行插入操作
void EnQueue(LinkQueue *Q, ElemType x)
{
	//申請佇列結點
	QueueNode *s = (QueueNode *)malloc(sizeof(QueueNode)
); assert(s != NULL); //為申請的佇列結點賦值 s->data = x; s->next = NULL; //將申請的佇列結點插入到隊尾 Q->tail->next = s; //更改佇列管理結點中尾指標的指向 Q->tail = s; }

出隊

//出隊操作:刪除隊頭的第一個有效結點
void DeQueue(LinkQueue *Q)
{
	//如果隊中無有效結點,無需進行操作
	if(Q->front == Q->tail)
		return;
	
	//獲取隊頭的第一個有效結點
	QueueNode *p = Q->front->next;
	//將隊頭的第一個有效結點從佇列中斷開
	Q->front->next = p->next;
	//釋放該結點
	free(p);
	//如果刪除的結點是最後一個有效結點,需要更改尾指標的指向
	if(p == Q->tail)
		Q->tail = Q->front;
}

列印佇列資料

//列印佇列內的資料
void ShowQueue(LinkQueue *Q)
{
	//獲取佇列中第一個有效結點
	QueueNode *p = Q->front->next;
	printf("Front:>");
	//將佇列中每個有效結點中的資料列印
	while(p != NULL)
	{
		printf("%d ",p->data);
		p = p->next;
	}
	printf("<:Tail.\n");
}

獲取隊頭元素

//獲取隊頭元素
void GetHead(LinkQueue *Q, ElemType *v)
{
	//如果隊中無有效結點,無需進行操作
	if(Q->front == Q->tail)
		return;
	//獲取隊頭的第一個有效結點
	QueueNode *p = Q->front->next;
	//返回隊頭第一個有效結點資料
	*v = p->data;
}

求佇列長度

//求佇列的長度
int Length(LinkQueue *Q)
{
	int len = 0;//初始長度為0
	//獲取隊頭的第一個有效結點
	QueueNode *p = Q->front->next;
	//遍歷佇列,獲取一個結點,將佇列長度加一
	while(p != NULL)
	{
		len++;
		p = p->next;
	}
	//返回長度值
	return len;
}

清空佇列

//清空佇列:釋放所有的有效結點
void ClearQueue(LinkQueue *Q)
{
	//如果隊中無有效結點,無需進行操作
	if(Q->front == Q->tail)
		return;
	//獲取隊頭的第一個有效結點
	QueueNode *p = Q->front->next;
	//遍歷佇列中的有效結點
	while(p != NULL)
	{
		//移除結點
		Q->front->next = p->next;
		//釋放結點
		free(p);
		//指向下一個結點
		p = Q->front->next;
	}
	Q->tail = Q->front;
}

銷燬佇列

//銷燬佇列
void DestroyQueue(LinkQueue *Q)
{
	//清空佇列
	ClearQueue(Q);
	//釋放頭結點
	free(Q->front);
	//將管理結點中的頭指標和尾指標都指向空
	Q->front = Q->tail = NULL;
}

結語

對鏈佇列的介紹就到這裡啦,希望這篇文章能給予你一些幫助,感謝各位人才的:點贊、收藏和評論,我們下次見。
在這裡插入圖片描述

附錄

以下提供鏈佇列的測試程式碼

LinkQueue.h

#ifndef __LINKQUEUE_H__
#define __LINKQUEUE_H__

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

//資料型別
#define ElemType int

//佇列結點型別
typedef struct QueueNode
{
	ElemType data;          //資料域
	struct QueueNode *next; //指標域
}QueueNode;

//鏈式佇列管理結構
typedef struct LinkQueue
{
	QueueNode *front;  //隊頭指標
	QueueNode *tail;   //隊尾指標
}LinkQueue;

void InitQueue(LinkQueue *Q);
void EnQueue(LinkQueue *Q, ElemType x);
void ShowQueue(LinkQueue *Q);
void DeQueue(LinkQueue *Q);
void GetHead(LinkQueue *Q, ElemType *v);
int Length(LinkQueue *Q);
void ClearQueue(LinkQueue *Q);
void DestroyQueue(LinkQueue *Q);

#endif //__LINKQUEUE_H__

LinkQueue.cpp

#include"LinkQueue.h"

//初始化佇列
void InitQueue(LinkQueue *Q)
{
	//申請頭結點記憶體空間
	QueueNode *s = (QueueNode *)malloc(sizeof(QueueNode));
	assert(s != NULL);
	//初始化時,將頭指標和尾指標都指向頭結點
	Q->front = Q->tail = s;
	//將頭結點的下一結點賦空
	Q->tail->next = NULL;
}

//入隊操作:在隊尾執行插入操作
void EnQueue(LinkQueue *Q, ElemType x)
{
	//申請佇列結點
	QueueNode *s = (QueueNode *)malloc(sizeof(QueueNode));
	assert(s != NULL);
	//為申請的佇列結點賦值
	s->data = x;
	s->next = NULL;
	//將申請的佇列結點插入到隊尾
	Q->tail->next = s;
	//更改佇列管理結點中尾指標的指向
	Q->tail = s;
}

//列印佇列內的資料
void ShowQueue(LinkQueue *Q)
{
	//獲取佇列中第一個有效結點
	QueueNode *p = Q->front->next;
	printf("Front:>");
	//將佇列中每個有效結點中的資料列印
	while(p != NULL)
	{
		printf("%d ",p->data);
		p = p->next;
	}
	printf("<:Tail.\n");
}

//出隊操作:刪除隊頭的第一個有效結點
void DeQueue(LinkQueue *Q)
{
	//如果隊中無有效結點,無需進行操作
	if(Q->front == Q->tail)
		return;
	
	//獲取隊頭的第一個有效結點
	QueueNode *p = Q->front->next;
	//將隊頭的第一個有效結點從佇列中斷開
	Q->front->next = p->next;
	//釋放該結點
	free(p);
	//如果刪除的結點是最後一個有效結點,需要更改尾指標的指向
	if(p == Q->tail)
		Q->tail = Q->front;
}
//獲取隊頭元素
void GetHead(LinkQueue *Q, ElemType *v)
{
	//如果隊中無有效結點,無需進行操作
	if(Q->front == Q->tail)
		return;
	//獲取隊頭的第一個有效結點
	QueueNode *p = Q->front->next;
	//返回隊頭第一個有效結點資料
	*v = p->data;
}

//求佇列的長度
int Length(LinkQueue *Q)
{
	int len = 0;//初始長度為0
	//獲取隊頭的第一個有效結點
	QueueNode *p = Q->front->next;
	//遍歷佇列,獲取一個結點,將佇列長度加一
	while(p != NULL)
	{
		len++;
		p = p->next;
	}
	//返回長度值
	return len;
}

//清空佇列:釋放所有的有效結點
void ClearQueue(LinkQueue *Q)
{
	//如果隊中無有效結點,無需進行操作
	if(Q->front == Q->tail)
		return;
	//獲取隊頭的第一個有效結點
	QueueNode *p = Q->front->next;
	//遍歷佇列中的有效結點
	while(p != NULL)
	{
		//移除結點
		Q->front->next = p->next;
		//釋放結點
		free(p);
		//指向下一個結點
		p = Q->front->next;
	}
	Q->tail = Q->front;
}

//銷燬佇列
void DestroyQueue(LinkQueue *Q)
{
	//清空佇列
	ClearQueue(Q);
	//釋放頭結點
	free(Q->front);
	//將管理結點中的頭指標和尾指標都指向空
	Q->front = Q->tail = NULL;
}

Main.cpp

#include"LinkQueue.h"

void main()
{
	LinkQueue Q;
	InitQueue(&Q);//初始化佇列
	
	for(int i=1; i<=10; ++i)
	{
		EnQueue(&Q,i);//入隊操作
	}
	ShowQueue(&Q);
	DeQueue(&Q);
	DeQueue(&Q);
	ShowQueue(&Q);
	printf("Len = %d\n",Length(&Q));
}