目录
1.队列的基础结构
队列的结构特点如下
先进先出 (FIFO):队列是一种先进先出的数据结构,即最先进入队列的元素也会最先从队列中被取出。队列的头部保存的是最先进入的元素,而队列的尾部保存的是最后进入的元素。
只能在队列的两端进行操作:队列只允许在队列的头部删除元素,在队列的尾部添加元素。这种限制保证了队列的操作具有一定的顺序性,符合先进先出的规则。
支持动态扩容:队列可以通过动态扩容来适应不同的需求。当队列元素数量达到队列的容量上限时,队列会自动扩容,以容纳更多的元素。扩容操作可能会导致队列的头部和尾部的物理位置发生变化。
队列的容量有限:队列的容量是有限的,即队列能够容纳的元素数量是有限的。队列容量的大小通常在创建队列时就确定了,并且在队列使用过程中不会发生变化。如果队列已满,再次插入元素会导致队列溢出。
可以用数组或链表实现:队列可以用数组或链表来实现。使用数组实现的队列叫做顺序队列,使用链表实现的队列叫做链式队列。顺序队列和链式队列在底层数据结构和操作方式上有所不同,但它们都具有队列的基本特点。
在这里,我选择使用单链表来实现队列,定义队列的结构如下
typedef int QDatatype;
typedef struct QueueNode
{
struct QueueNode* next;
QDatatype data;
}QNode;
typedef struct Queue
{
QNode* head;
QNode* tail;
int size;
}Queue;
2.队列的数据操作
①队列的初始化
//初始化队列
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
pq->size = 0;
}
②队列的销毁
//销毁队列
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* tmp = cur->next;
free(cur);
cur = tmp;
}
pq->head = pq->tail = NULL;
pq->size = 0;
}
③队列入数据
//队列入数据
void QueuePush(Queue* pq, QDatatype x)
{
assert(pq);
QNode* tmp = (QNode*)malloc(sizeof(QNode));
if (tmp == NULL)
{
perror("malloc fail");
return;
}
tmp->data = x;
tmp->next = NULL;
if (pq->head == NULL)
{
assert(pq->tail);
pq->head = pq->tail = tmp;
}
else
{
pq->tail->next = tmp;
pq->tail = tmp;
}
pq->size++;
}
④队列出数据
//队列出数据
void QueuePop(Queue* pq)
{
assert(pq);
assert(pq->tail);
QNode* tmp = pq->head;
pq->head = pq->head->next;
free(tmp);
pq->size--;
}
⑤取得队列元素个数
//队列元素个数
int QueueSize(Queue* pq)
{
assert(pq);
/*int count = 0;
QNode* cur = pq->head;
while (cur)
{
count++;
cur = cur->next;
}
return count;*/
return pq->size;
}
⑥判断队列内是否为空
//判断队列是否为空
bool QueueEmpty(Queue* pq)
{
assert(pq);
/*if (pq->head == NULL)
{
return true;
}
else
{
return false;
}*/
return pq->size == 0;
}
⑦取得队列首元素
//取得队列首元素
QDatatype QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->data;
}
⑧取得队列尾元素
//取得队列尾元素
QDatatype QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->data;
}
3.队列的优势与劣势
①优势
-
先进先出:队列是一种先进先出的数据结构,它保证了元素的顺序性,符合实际问题的要求。例如,操作系统中的进程调度、消息队列等都需要保证先进入的元素先被处理。
-
轻松实现同步:队列可以很方便地实现同步操作。例如,多线程环境下,线程可以将任务添加到队列中,另一个线程负责从队列中取出任务并执行,从而避免了线程之间的竞争和死锁等问题。
-
支持动态扩容:队列可以通过动态扩容来适应不同的需求。当队列元素数量达到队列的容量上限时,队列会自动扩容,以容纳更多的元素。
-
适用于广泛的应用场景:队列可以用于广泛的应用场景,如进程调度、消息队列、网络数据包的传输等。
②劣势
-
队列的插入和删除操作的时间复杂度都为O(1),但在使用数组实现的队列中,插入和删除操作可能会导致元素的移动,造成额外的时间和空间开销。
-
队列容量有限:队列的容量是有限的,即队列能够容纳的元素数量是有限的。如果队列已满,再次插入元素会导致队列溢出。
-
队列的检索操作效率较低:在使用数组实现的队列中,查找队列中某个元素的效率较低,需要遍历整个队列来查找。
-
队列的数据存储必须是顺序的:队列只能在队列的头部删除元素,在队列的尾部添加元素,数据的存储必须是顺序的,不适合随机访问和修改数据。