结构特点:先进先出实现模式:单向非循环双指针链表
两个指针分别记录头和尾之所以不用循环链表是添加删除元素都在链表头部进行,不涉及尾部增删操作。
声明队列
声明队列之所以要用到两个结构体是因为除了单个链表节点之外,还需要一个尾指针记录队尾。
typedef int QDataType;
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QNode;
struct Queue
{
QNode* head;
QNode* tail;
int size;
};
初始化
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = NULL;
pq->tail = NULL;
pq->size = 0;
}
销毁
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* Next =cur->next;
free(cur);
cur = Next;
}
pq->head = pq->tail = NULL;//避免野指针
pq->size = 0;
}
Push
由于只在头部插入数据,所以不需要再对是否新增一个节点额外封装一层函数。
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
pq->size++;
if (pq->head == NULL)
{
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;
}
}
判空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL && pq->tail == NULL;//其中一个为空即可
}
Pop
出队是在头删除节点,注意只有一个节点需要将头尾指针置空。没有节点需要进行断言等检查。
void QueuePop(Queue* pq)
{
//出队头删
assert(pq);
assert(!QueueEmpty(pq));
Queue* del = pq->head;
pq->head = pq->head->next;//一个节点next为NULL
free(del);
if (pq->head == NULL)
pq->tail = NULL;
pq->size--;
}
Size
size的作用是记录节点的个数,我们可以通过遍历得到个数,但时间复杂度为O(n),这时我们定义的结构体成员size就发挥作用了,直接返回即可。
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
Front
同理,直接调用可能不知道存在哨兵节点等问题。
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->data;
}
Back
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->data;
}
测试
完整代码
//Queue.h
#pragma once
#include <stdbool.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int QDataType;
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QNode;
struct Queue
{
QNode* head;
QNode* tail;
int size;
};
void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
void QueuePush(Queue* pq, QDataType x);
void QueuePop(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
bool QueueEmpty(Queue* pq);
int QueueSize(Queue* pq);
//Queue.cpp
#include "Queue.h"
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* Next =cur->next;
free(cur);
cur = Next;
}
pq->head = pq->tail = NULL;//避免野指针
pq->size = 0;
}
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
pq->size++;
if (pq->head == NULL)
{
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;
}
}
void QueuePop(Queue* pq)
{
//出队头删
assert(pq);
assert(pq->head);
QNode* del = pq->head;
pq->head = pq->head->next;
free(del);
if (pq->head == NULL)
pq->tail = NULL;
pq->size--;
}
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = NULL;
pq->tail = NULL;
pq->size = 0;
}
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL && pq->tail == NULL;
}
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
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;
}
//test.cpp
#include "Queue.h"
void Test1()
{
Queue q;
QueueInit(&q);
QueuePush(&q, 1);
QueuePush(&q, 2);
/*printf("%d ", QueueFront(&q));*/
//QueuePop(&q);
QueuePush(&q, 3);
QueuePush(&q, 4);
//printf("%d\n", QueueSize(&q));
//printf("%d\n", QueueEmpty(&q));
//printf("%d\n", QueueFront(&q));
//printf("%d\n", QueueBack(&q));
//打印--先进先出
while (!QueueEmpty(&q))
{
printf("%d ", QueueFront(&q));
QueuePop(&q);
}
printf("\nsize:%d\n", QueueSize(&q));
printf("%d\n", QueueEmpty(&q));
QueueDestroy(&q);
}
int main()
{
Test1();
return 0;
}