【数据结构】C语言实现队列的相关操作
队列
队列是一种遵循先入先出规则的线性数据结构,是一种只允许在表的一端插入,在另一端删除的线性表
队尾 rear:插入端,线性表的表尾。
队头 front:删除端,线性表的表头

队列可以用数组或者链表实现
用数组实现队列时,由于队列采用头删尾插的操作方式,数组中队列的队头和队尾会不断的后移,如果到达数组末尾,那么队列就难以实现头删尾插的操作了,为了解决这种问题,采用循环队列的形式,让队头或队尾在越过数组尾部时,可以回到数组的头部然后继续操作,这种循环的形式可以通过取余操作来实现
用数组实现的队列又叫做“循环队列”
循环队列
表示
#define MAXSIZE 100
typedef struct Queue {
int data[MAXSIZE];
int front;
int rear;
}Queue;
front:记录队头的位置
rear:记录队尾后第一个空间的位置
rear 记录的位置是由入队操作决定的
当 front == rear == 0 时,假设此时有一个元素 x 入队
则代码大致为
data[rear] == x
rear++
此时 rear 的位置就是队尾后第一个空间的位置
由于采用循环的操作形式,front 和 rear 更新都是通过取余的方式
front = (front + 1) % MAXSIZE
rear = (rear + 1) % MAXSIZE
当 front == rear 时,既有可能是队空,也有可能是队满,
为了区别这两种情况,要么少用一个存储空间,要么再设一个变量 size 来记录队列的大小
假设要求队列中能存储99个数据元素,则实际上需要100(MAXSIZE)个存储空间,数组的下标范围为0到99
队满情况表(少用一个存储空间)
| front | rear | (rear + 1) % MAXSIZE |
|---|---|---|
| 0 | 99 | 0 |
| 1 | 0 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 3 |
| ... | ||
| 98 | 97 | 98 |
| 99 | 98 | 99 |
于是有
队空:front == rear
队满:(rear + 1) % MAXSIZE == front
初始化
void init(Queue* Q)
{
int i = 0;
for (i = 0; i < MAXSIZE; i++)
{
Q->data[i] = 0;
}
Q->front = 0;
Q->rear = 0;
}
或者在主函数中
Queue Q = { {0},0,0 };
判断队空
int isEmpty(Queue* Q)
{
if (Q->front == Q->rear)
{
return 1;
}
else
{
return 0;
}
}
判断队满
int isFull(Queue* Q)
{
if ((Q->rear + 1) % MAXSIZE == Q->front)
{
return 1;
}
else
{
return 0;
}
}
入队
void in(Queue* Q, int x)
{
if (isFull(Q) == 1)
{
return;
}
else
{
Q->data[Q->rear] = x;
Q->rear = (Q->rear + 1) % MAXSIZE;
}
}
出队
int out(Queue* Q)
{
if (isEmpty(Q) == 1)
{
exit(0);
}
else
{
int x = Q->data[Q->front];
Q->front = (Q->front + 1) % MAXSIZE;
return x;
}
}
求队列长度
int get_length(Queue* Q)
{
int length = (Q->rear - Q->front + MAXSIZE) % MAXSIZE;
return length;
}
清空
void clear(Queue* Q)
{
Q->front = 0;
Q->rear = 0;
}
链式队列
用链表表示的队列简称为链队列
链队列带头结点,有头指针和尾指针,头指针指向头结点(不是首元结点),尾指针指向最后一个结点
队头是首元结点,队尾是尾结点,
在单链表中,用链表的头指针来表示链表,在给结构体自定义名字时,除了一个 QNode 还有一个指针 LinkList,该指针就是头指针,由于用头指针表示链表,所以名字就叫 LinkList
在链队中,同样是用头指针来表示链队,但是除了一个头指针,链队中还有一个尾指针,为了方便操作,又定义了一个结构体来存放头指针和尾指针,在对该结构体自定义名字时,名字就叫 LinkQueue
目前我的理解是,其实链表就是一个指针,没什么花里胡哨的
表示
typedef struct QueueNode
{
int data;
struct QueueNode* next;
}QueueNode;
typedef struct QueuePtr
{
QueueNode* front;
QueueNode* rear;
}LinkQueue;
当 front == rear 时,表示链队为空
初始化
void init(LinkQueue* Q)
{
Q->front = (QueueNode*)malloc(sizeof(QueueNode));
if (Q->front == NULL)
{
return;
}
Q->rear = Q->front;
Q->front->next = NULL;
}
判断队空
int isEmpty(LinkQueue* Q)
{
if (Q->front == Q->rear)
{
return 1;
}
else
{
return 0;
}
}
入队
void in(LinkQueue* Q, int x)
{
QueueNode* p = (QueueNode*)malloc(sizeof(QueueNode));
if (p == NULL)
{
return;
}
p->data = x;
p->next = NULL;
Q->rear->next = p;
Q->rear = p;
}
出队
int out(LinkQueue* Q)
{
if (isEmpty(Q) == 1)
{
exit(0);
}
QueueNode* p = Q->front->next;
int x = p->data;
if (Q->front->next == Q->rear)
{
Q->rear = Q->front;
}
Q->front->next = p->next;
free(p);
p = NULL;
return x;
}
出队时,注意当链队中除头结点外只剩一个结点时的情况,此时需要改变尾指针的指向
求队长
int get_length(LinkQueue* Q)
{
QueueNode* p = Q->front->next;
int count = 0;
while (p != NULL)
{
p = p->next;
count++;
}
return count;
}
取队头
int get_front(LinkQueue* Q)
{
if (isEmpty(Q) == 1)
{
exit(0);
}
int x = Q->front->next->data;
return x;
}
清空
遵循队列头删尾插操作原则的清空
void clear(LinkQueue* Q)
{
QueueNode* p = Q->front->next;
while (p != NULL)
{
QueueNode* pFree = p;
Q->front->next = p->next;
free(pFree);
pFree = NULL;
p = Q->front->next;
}
Q->rear = Q->front;
}
遍历清空
void clear(LinkQueue* Q)
{
QueueNode* p = Q->front->next;
while (p != NULL)
{
QueueNode* pFree = p;
p = p->next;
free(pFree);
pFree = NULL;
}
Q->front->next = NULL;
Q->rear = Q->front;
}
销毁
void destroy(LinkQueue* Q)
{
clear(Q);
free(Q->front);
Q->front = NULL;
Q->rear = NULL;
}
浙公网安备 33010602011771号