简介
链队(Linked Queue)是一种基于链表实现的队列数据结构。队列是一种先进先出(FIFO)的数据结构,即最先进入队列的元素最先被取出。链队的实现利用链表的特性,不像顺序队列需要提前确定队列的大小。
链队包含两个主要部分:节点(Node)和链表(Linked List)。每个节点都包含两个字段,一个用于存储数据元素,另一个用于指向下一个节点。链表的头部通常指向队列的前端,而尾部指向队列的后端。
链队的特点
-
动态大小: 与顺序队列不同,链队可以动态调整大小,无需预先分配固定大小的内存空间。这意味着可以根据需要灵活地添加或删除元素。
-
灵活插入和删除: 由于链队基于链表,插入和删除元素的操作更为灵活。入队和出队的时间复杂度为O(1)。
-
无需移动元素: 在链队中,不需要像顺序队列那样移动元素来保持队列的顺序。插入和删除只涉及修改节点的指针,而不涉及元素的搬移。
-
不需要预定义大小: 链队不需要事先定义队列的大小,因为链表的节点可以根据需要动态创建。
基本操作
初始化(Initialization)
创建一个空链队,并初始化头尾指针。
// 初始化链队
void initQueue(struct LinkedQueue* queue) {
queue->front = queue->rear = NULL;
}
入队(Enqueue)
在链队的尾部插入一个新元素。这涉及创建一个新节点,并将尾指针指向这个新节点。如果链队是空的,头指针也要指向这个新节点。
// 入队操作
void enqueue(struct LinkedQueue* queue, int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
if (newNode == NULL) {
printf("Memory allocation failed.\n");
return;
}
newNode->data = data;
newNode->next = NULL;
if (isEmpty(queue)) {
// 队列为空,新节点成为队头和队尾
queue->front = queue->rear = newNode;
} else {
// 将新节点加入队尾
queue->rear->next = newNode;
queue->rear = newNode;
}
}
出队(Dequeue)
从链队的头部删除一个元素。这涉及将头指针指向下一个节点。如果链队在出队操作后为空,需要更新尾指针。
// 出队操作
int dequeue(struct LinkedQueue* queue) {
if (isEmpty(queue)) {
printf("Queue is empty.\n");
return -1; // 表示队列为空
}
struct Node* frontNode = queue->front;
int data = frontNode->data;
if (queue->front == queue->rear) {
// 队列中只有一个节点
queue->front = queue->rear = NULL;
} else {
// 将队头指针指向下一个节点
queue->front = frontNode->next;
}
free(frontNode);
return data;
}
判空(IsEmpty)
检查链队是否为空,即头指针是否为null。
// 判断链队是否为空
int isEmpty(struct LinkedQueue* queue) {
return queue->front == NULL;
}
获取队头元素(Front)
// 获取队头元素
int frontElement(struct LinkedQueue* queue) {
if (isEmpty(queue)) {
printf("Queue is empty.\n");
return -1; // 表示队列为空
}
return queue->front->data;
}
链队小结
链队的优点在于它能够动态地适应不同大小的队列,而无需预先分配固定大小的内存空间。然而,与顺序队列相比,链队可能在访问元素时有更多的指针操作,导致一些额外的开销。
代码完整实现
#include<stdlib.h>
#include<stdio.h>
#define MaxSize 10
typedef struct LinkNode{//链式队列节点
int data;
struct LinkNode *next;
} LinkNode;
typedef struct{//链式队列
LinkNode *front,*rear;//链式队列头指针,尾指针
}LinkQueue;
//初始化队列(带头节点)
void InitQueue(LinkQueue &Q){
Q.front=Q.rear=(LinkNode *)malloc(sizeof(LinkNode));//头指针和尾指针都指向头节点
Q.front->next=NULL;
}
//判空
bool IsEmpty(LinkQueue Q){
if(Q.front==Q.rear){
return true;
}
return false;
}
//入队(带头节点)
void InsertQueue(LinkQueue &Q,int x){
LinkNode *s=(LinkNode *)malloc(sizeof(LinkNode));
s->data=x;
s->next=NULL;
Q.rear->next=s;//新节点接到表尾指针之后
Q.rear=s;//修改表尾指针
}
//(不带头节点)
void InsertQueue1(LinkQueue &Q,int x){
LinkNode *s=(LinkNode *)malloc(sizeof(LinkNode));
s->data=x;
s->next=NULL;
if(Q.front==NULL){//在空队列中插入第一个元素
Q.front=s;
Q.rear=s;
}
else{
Q.rear->next=s;
Q.rear=s;
}
}
//出队(带头节点) Q.front指向头节点
bool DeleteQueue(LinkQueue &Q,int &e){
//判空
if(Q.front==Q.rear){
return false;
}
LinkNode *s;
s=Q.front->next;//指向队列中第一个元素
e=s->data;
Q.front->next=s->next;//修改头节点的next指针
if(Q.rear==s){
Q.rear=Q.front;
}
free(s);
return true;
}
//出队(不带头节点) Q.front指向第一个元素节点
bool DeleteQueue1(LinkQueue &Q,int &e){
if(Q.front==NULL){//判空
return false;
}
LinkNode *s=Q.front;
e=s->data;
Q.front=s->next;
if(s->next==NULL||Q.rear==s){
Q.front=NULL;
Q.rear=NULL;
}
free(s);
return true;
}
int main(){
LinkQueue Q;
InitQueue(Q);
}