文章目录
- 队列的定义
- 初始化队列
- 队尾入队列
- 队头出队列
- 取队头元素
- 取队尾元素
- 获取队列有效元素个数
- 判断队空
- 销毁队列
因为队列比较简单,关于队列的概念就不过多赘述了,本文只讲链队的基本操作实现
队列的定义
定义队列结点结构
- 链队中的每个结点都应该包含一个数据域用来存储数据,以及一个指针域用来存储下一个结点的地址。
typedef int QDataType;
//对列中每个结点的结构
typedef struct QListNode
{
QDataType data; //数据域
struct QListNode* next; //指针域
}QNode;
定义队列
- 一个正常的队列应该有一个队头指针和一个队尾指针分别用来指向队列的头和尾。
- 除此之外,还需要一个变量用来表示当前队列有效数据的个数。
// 队列的结构
typedef struct Queue
{
int size; //元素个数
QNode* head; //队头指针
QNode* tail; //队尾指针
}Queue;
初始化队列
- 在队列内没有任何元素时,队头和队尾指针都应该指向空,元素个数也置为 0。
// 初始化队列
void QueueInit(Queue* q)
{
assert(q);
q->head = q->tail = NULL; //队头尾指针都置空
q->size = 0; //队内元素个数置空
}
队尾入队列
链队在入队时有两种情况
- 队列内无元素:同时让队头和队尾指针指向新结点。
- 队列内有元素:让队尾结点的指针域存储新结点的地址,将新插入的结点更新为尾结点。
// 队尾入队列
void QueuePush(Queue* q, QDataType data)
{
assert(q);
//创建新结点
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (NULL == newnode)
{
perror("malloc");
exit(-1);
}
newnode->data = data; //将数据插入新结点数据域
newnode->next = NULL; //将新结点指针域置空
if (NULL == q->tail) //当前队列没有结点
{
q->head = q->tail = newnode; //队头队尾的指针域同时指针新结点
}
else //当前队列中有结点
{
q->tail->next = newnode; //队尾结点指针域指向新结点
q->tail = newnode; //将插入的结点更新为尾结点
}
q->size++; //队列内有效元素个数 + 1
}
队头出队列
队头出队列就是删除队头元素,在删除队头元素时有两种情况。
- 删除的是最后一个元素:删除该结点时头指针会往后走到 NULL 的位置,此时必须也将队尾指针也置空,否则队尾指针就成野指针了。
- 删除的非最后一个元素:保存队头的地址,然后将队头指针指向下一个结点,最后释放队头。
// 队头出队列
void QueuePop(Queue* q)
{
assert(q);
assert(q->head); //队列不为空
QNode* delete = q->head; //保存要删除的队头结点的地址
q->head = q->head->next; //头指针走向下一个结点
free(delete); //删除队头结点
delete = NULL;
if (NULL == q->head) //前面删除的是最后一个元素
{
q->tail = NULL; //尾指针也置空
}
q->size--; //队内元有效元素个数 -1
}
取队头元素
- 在队列非空时,直接返回队头结点数据域内的数据即可。
// 获取队列头部元素
QDataType QueueFront(Queue* q)
{
assert(q);
assert(q->head);
return q->head->data; //返回队头结点的数据域内容
}
取队尾元素
- 在队列非空时,直接返回队尾结点数据域内的数据即可。
// 获取队列队尾元素
QDataType QueueBack(Queue* q)
{
assert(q);
assert(q->tail); //队列不为空
return q->tail->data; //返回队尾结点的数据域内容
}
获取队列有效元素个数
// 获取队列中有效元素个数
int QueueSize(Queue* q)
{
assert(q);
return q->size;
}
判断队空
- 检测队列是否为空,如果为空返回非零结果,如果非空返回 0 。
int QueueEmpty(Queue* q)
{
assert(q);
return 0 == q->size; //表达式成立则结果为真,反之为假
}
销毁队列
- 和单链表的销毁相同,利用一个指针 cur 保存当前要删除结点的地址,再定义一个 next 指针指向下一个要删除的结点。
- 重复上述直到 cur 指向空为止,此时表示队列内的所有结点已经销毁完毕。
// 销毁队列
void QueueDestroy(Queue* q)
{
assert(q);
QNode* cur = q->head; //cur 先指向队头
while (NULL != cur)
{
QNode* next = cur->next; //保存下一个结点
free(cur); //删除当前结点
cur = next; //指向下一个结点
}
q->head = q->tail = NULL; //队头尾指针都置空
q->size = 0;
}