目录
队列
队列的定义
队列是:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头。
队列的实现
队列也可以数组和链表的结构实现
使用数组实现队列
优点:
数组在内存中是连续存储的,因此可以通过索引快速访问任意位置的元素。
在某些情况下,如果数组的大小预先确定或增长预测准确,则可以使用较少的内存。
缺点:
当队列在数组的一端进行插入(队尾)和删除(队头)操作时,如果数组已满或接近满,可能需要移动大量元素以维护队列的连续性,这会导致较高的时间复杂度(特别是删除操作)。
动态数组,虽然可以自动调整大小,但每次扩容都可能涉及大量元素的复制,这也可能带来性能问题。
使用链表实现队列
优点:
链表的节点在内存中是动态分配的,不需要连续的存储空间,因此插入和删除操作只需要修改指针,时间复杂度为O(1)。
链表不需要像数组那样预留额外的空间以避免扩容操作,因此在动态数据结构中更加灵活。
缺点:
链表中的每个节点都需要额外的空间来存储指针,这可能会增加内存消耗。
由于链表在内存中是分散的,所以遍历链表通常比遍历数组慢(尽管对于队列来说,这通常不是问题,因为队列的主要操作是插入和删除)
因为对于队列来说,使用链表进行头删和尾插比较方便,所以我选择链表。当然顺序表也可以。
创建队列的结构
typedef struct QueueNode
{
struct QueueNode* next;
QDatatype data;
}QNode;
typedef struct queue
{
QNode* head;
QNode* tail;
int size;
}queue;
首先创建一个结构体,结构体要连接,所以创建一个结构体指针,然后创建一个储存数据的类型( QDatatype),这个类型是typedef对int类型起的别名,若想更改储存数据类型,可以直接更改。
因为要进行先进先出,所以要找头和尾
所以创建了两个指针,多个数据用结构体创建
head表示创建的头节点
tail表示创建的尾节点
size表示存储的数字个数
队列的初始化
//进行初始化
void QueueInit(queue* pq)
{
assert(pq);
pq->tail = pq->head = NULL;
pq->size = 0;
}
初始全赋值为NULL
存储的数字个数为0;
进行插入数据
//插入数据
void QueuePush(queue* pq, QDatatype x)
{
assert(pq);
QNode * newdata = (QNode *)malloc(sizeof(QNode));
if (newdata==NULL)
{
perror("malloc");
return;
}
if (pq->head == NULL)
{
assert(pq->tail==NULL);
pq->tail = newdata;
pq->head = newdata;
}
else
{
pq->tail->next = newdata;
pq->tail = newdata;
}
newdata->next = NULL;
newdata->data = x;
pq->size++;
}
首先,要插入数据,就要进行开辟空间,这里使用的malloc进行开辟空间,如果开辟失败会进行打印错误并返回,
然后判断是否为第一个插入的数据,插入的第一个数据要进行处理;
如果不为空,尾节点向下进行互换;
size+1;
插入数据相当于是对链表的尾插
删除数据
//删除数据
void QueuePop(queue* pq)
{
assert(pq);
assert(pq->head);
QNode* node = pq->head;
if (pq->head == pq->tail)
{
pq->tail = NULL;
pq->head = NULL;
}
else
{
pq->head = pq->head->next;
}
pq->size--;
free(node);
node = NULL;
}
首先要判断删除数据前是否只剩下一个节点,如果为一个节点,则头尾节点全部置空;
如果不是,则头节点被下一个节点替换
计算个数
//计算个数
int QueueSize(queue* pq)
{
assert(pq);
return pq->size;
}
直接返回size即可
判断是否为空
//判断是否为空
bool QueueEmpty(queue* pq)
{
assert(pq);
return pq->head == NULL;
}
返回队列头部数据
//对头数据
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;
}
总体来说对应队列,比较容易理解,比较难理解的是他需要创建两个结构体,这个和之前的很不一样,一个拥有存放数据和连接,一个拥有记录数据。
代码连接