队列的性质
1 只允许在一端进行插入数据操作,另一端进行删除数据操作的特殊线性表.
2 队列的数据遵循先进先出的原则,先入队列的数据先出队列.
3 进行插入操作【入队列】的一端叫队尾,进行删除操作【出队列】的一端叫队头.
队列的实现
因为数组的头插头删效率较低,所以用链表更优。
队列只需要在头尾进行删除和插入,所以可以考虑用单链表,多增加一个尾指针.
定义队列的节点
typedef int QDataType;
typedef struct QueueNode//定义队列的节点
{
QDataType data;
struct QueueNode* next;
}QNode;
定义队列的结构体
用尾指针方便在队尾入数据
typedef struct Queue//定义队列
{
QNode* phead;//队头
QNode* tail;//队尾 在队尾入数据,队头出数据
}Queue;
队列的初始化和销毁
void QueueInit(Queue* queue)//队列的初始化
{
assert(queue);
queue->phead = queue->tail = NULL;
}
void QueueDestroy(Queue* queue)//队列销毁
{
assert(queue);
QNode* cur = queue->phead;//从队列的头指针开始遍历队列的所有节点
while (cur != NULL)
{
//在free掉节点时保留它的下一个节点地址
QNode* next = cur->next;
free(cur);
cur = next;
}
}
入队列
情况1:队列没有数据,phead和tail都为空,此时入数据,应该把头尾指针都指向新节点
情况2:队列有数据,在tail后面插入节点,最后更新tail.
void QueuePush(Queue* queue, QDataType x)//入队列
{
assert(queue);
QNode* newNode = buyQNode(x);
if (QueueEmpty(queue))//判断队列是否为空的函数
{
queue->tail = queue->phead = newNode;
}
else
{
queue->tail->next = newNode;//尾插节点
queue->tail = newNode;//更新尾指针
}
}
出队列
情况1:队列无数据;
情况2:队列只有1个节点,free掉头节点指针后,要同时把tail和phead置空,不然tail就是野指针。
情况3:队列有多个节点,保存phead->next,
free掉头节点后,把头节点指针更新成之前的phead->next.
void QueuePop(Queue* queue)//出队列
{
assert(queue);
assert(!QueueEmpty(queue));//队列不为空
//只有一个节点
//有多个节点
if (queue->phead == queue->tail)
{
free(queue->phead);
queue->phead = queue->tail = NULL;
}
else
{
QNode* newHead = queue->phead->next;
free(queue->phead);
queue->phead = newHead;
}
}
取队头或队尾的数据
QDataType QueueFront(Queue* queue)//取队头数据
{
assert(queue);
assert(!QueueEmpty(queue));
return queue->phead->data;
}
QDataType QueueBack(Queue* queue)//取队尾数据
{
assert(queue);
assert(!QueueEmpty(queue));
return queue->tail->data;
}
获取队列的节点数
int QueueSize(Queue* queue)//获取队列的节点数
{
assert(queue);
QNode* cur = queue->phead;
int num = 0;
while (cur != NULL)
{
num++;
cur = cur->next;
}
return num;
}
判断队列是否为空
bool QueueEmpty(Queue* queue)
{
assert(queue);
return queue->phead == NULL;//头或尾为空说明队列一定为空
}