队列的相关知识
一.队的结构
队(queue)作为一种特殊的线性表,与现实中的排队相类似,作为受限的线性表,它只被允许在一端进行插入,另一端进行删除。
被允许插入的叫做队尾(front),允许删除的另一端就叫做队头(rear)。
从队列的尾部插入新的元素被称作入队,相反从队头删除相应元素就称为出队。
二.队列的存储结构
与栈相同,队的存储结构也分为两种结构:
顺序存储(数组)以及链式存储结构(链表),以上两者均可完成队列的实现
1.顺序队列
(1)定义:
用一段地址连续的存储单元(数组),来依次存放队头到队尾的元素,叫做顺序队列
我们在使用顺序结构来实现队列时,除了数组之外,我们需要用结构体封装两个指针:队头指针(front)和队尾指针(rear),使其分别指向队头与队尾
队尾与队头指针的用法如下所示:
(2)假溢出
通过以上例子,当元素F将继续插入队列之中就会发生假溢出
的情况发生,因为rear=5 > 4
,结尾已经达到了队列的最大长度了,但实际上队列中的空间并未被数据完全占据,因此此现象被称为假溢出
。
2.循环队列
(1)定义:
为了避免假溢出的发生,使得队列的空间能够得到充分的利用,于是我们将顺序队列的队首与队尾相连,将数组看作一个首位相连的循环结构
队头和队尾相互连接的顺序队列我们称之为循环队列。
那么问题随之而来,当循环队列为为空或者未满时,我们应该如何进行判断呢?
以下提供两个相关方案:
方案一:在循环中增加一个计算器count
,当count = MAXSIZE
时我们就可以判断,循环队列此时为满。
那么队满的条件就可以如此表示:(rear+1)%MAX==front
方案二:我们可以在队列的结构体中,增添一个指向该队列中的队尾下个数据的指针,当指针指向队头元素所在位置时,则判断队满。
那么队满的条件就为:rear==front
(2)基本操作
队的结构
typedef struct
{
int data[MAX];
int front; //头指针
int rear; //尾指针
}Queue;
队的初始化
Queue* initQueue(){
Queue* q=(Queue*)malloc(sizeof(Queue));
q->front=0;
q->rear=0;
return q;
}
判空操作
bool Queuefull(Queue* q){
return (q->rear+1)%MAX==q->front;
}
入队操作
void enterQueue(Queue *q,int data){
if(Queuefull){
printf("队列已满");
return ;
}
q->data[q->rear]==data;
q->rear=(q->rear+1)%MAX;
return 1;
}
出队操作
int pop(Queue *q){
if(Queuefull(q)){
return -1;
}
int temp=q->data[q->front];
q->front = (q->front + 1) % MAX;
return temp;
}
求队首元素
3.链式队列
顾名思义,采取链式存储的队列就被称之为链式队列,根据队列的结构,我们需要两个指针front
,rear
分别指向队头和队尾。
-
链表的声明
#include <stdio.h> #include <stdlib.h> //声明一个结构体来表示节点 typedef struct Node { int data; struct Node * next; }Node; //声明一个结构体来定义上面这个结构体的两个指针 typedef struct { Node *front,*rear;//分别指向队首和队尾的指针 }Queue;
-
链表的初始化
void initializeQueue(Queue* q) { q->front = q->rear = NULL; }
-
队列的遍历
void printQueue(Queue* q) { if (isEmpty(q)) { printf("队列为空\n"); } else { Node* current = q->front; while (current != NULL) { printf("%d ", current->data); current = current->next; } printf("\n"); } }
-
入队操作
void enqueue(Queue* q, int data) { Node* newNode = (Node*)malloc(sizeof(Node)); newNode->data = data; newNode->next = NULL; if (q->rear == NULL) { // 队列为空 q->front = q->rear = newNode; } else { q->rear->next = newNode; q->rear = newNode; } }
-
查看队首元素
int peek(Queue* q) { if (q->front == NULL) { // 队列为空 printf("队列为空\n"); return -1; // 返回一个特殊值表示队列为空 } else { return q->front->data; } }
-
队列的判空
int Empty(Queue* Q); { //队空的条件是头指针和尾指针指向相同的地方 if(Q.front==Q.rear) { return 1; } return 0;
-
出队操作
int dequeue(Queue* Q) { if (Empty(Q)) { printf("队列为空\n"); return -1; } else { int data = q->front->data; Node* temp = q->front; q->front = q->front->next; if (q->front == NULL) { q->rear = NULL;// 如果队列中只有一个节点,则出队后将rear置为NULL } free(temp); return value; } }
主函数内容如下
int main() { Queue q; initializeQueue(&q); enqueue(&q, 10); enqueue(&q, 20); enqueue(&q, 30); printf("队列元素: "); printQueue(&q); printf("队首元素: %d\n", peek(&q)); printf("出队元素: %d\n", dequeue(&q)); enqueue(&q, 10); printf("打印队列: "); printQueue(&q); return 0; }
printf("队列元素: "); printQueue(&q); printf("队首元素: %d\n", peek(&q)); printf("出队元素: %d\n", dequeue(&q));
enqueue(&q, 10);
printf("打印队列: ");
printQueue(&q);return 0;
}