目录
1.队列的概念
入队列:进行插入操作的一端称为 队尾出队列:进行删除操作的一端称为 队头

二.队列的实现
1.基本结构
typedef int QDataType;
// 链式结构:表示队列
typedef struct QListNode
{
struct QListNode* _next;
QDataType _data;
}QNode;
// 队列的结构
typedef struct Queue
{
QNode* _front; //头指针
QNode* _rear; //尾指针
}Queue;
其中STDataType为重定义数据类型,这样定义有利于我们通过简便的修改,达到使栈存放不同类型数据的目的。
QNode为链表结点的基础结构,变量_data用于存放数据,而_next为指向下一个结点的指针。
Queue用于对队列进行管理,其头指针_front指向链表头结点,尾指针_rear指向链表尾结点。利用此结构存储头尾结点,即解决了前文尾部操作效率的问题,使其时间复杂度变为O(1)。
2.常见接口
// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType data);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue* q);
// 获取队列队尾元素
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);
1.QueueInit函数-对队列结构进行初始化
void QueueInit(Queue* q)
{
assert(q);
q->_front = NULL;
q->_rear = NULL;
}
先进行断言防止传入指针为空,然后初始化其内部变量指针为NULL。
2.QueuePush函数-队尾入队列
void QueuePush(Queue* q, QDataType data)
{
assert(q);
QNode* newNode = (QNode*)malloc(sizeof(QNode));
if (newNode == NULL)
{
printf("malloc error\n");
exit(-1);
}
newNode->_data = data;
newNode->_next = NULL;
if (q->_front == NULL)
{
q->_front = newNode;
q->_rear = newNode;
}
else
{
q->_rear->_next = newNode;
q->_rear = newNode;
}
}
要插入新数据,则要通过动态内存分配创建新结点指针newnode用于存放数据,当然还需要对开辟是否成功进行判断,若失败,则打印错误信息。若成功,则先初始化新结点,然后进行尾插。此处尾插和链表插入操作相同,不进行赘述。只需注意若队列为空,插入时将newnode赋值给_front和_rear,若队列不为空,则只需将新结点插入尾部,并更新尾部指针_rear。
3.QueuePop函数-队头出数据
void QueuePop(Queue* q)
{
assert(q);
assert(q->_front && q->_rear);
QNode* next = q->_front->_next;
free(q->_front);
q->_front = next;
if (q->_front == NULL)
q->_rear = NULL;
}
此处需要防止队列为空,故进行断言。然后进行头删操作即可,这也在链表里介绍过。只需额外注意若队列只有一个数据进行头删,则需要将_rear置为空。下面图解说明这一点:
如图,若队列大于1个元素,则释放p1结点,_front指向下一个元素即可。
然而按照上面的逻辑,当队列只有一个元素时,我们发现_rear指针还指向已被释放的空间,此时该指针便成了野指针,因此需要我们进行置空操作。
4.QueueBack函数-获取队尾元素
QDataType QueueBack(Queue* q)
{
assert(q);
assert(q->_front && q->_rear);
return q->_rear->_data;
}
断言后返回队尾数据即可。
5.QueueSize函数-获取队列有效元素个数
int QueueSize(Queue* q)
{
assert(q);
QNode* cur = q->_front;
int count = 0;
while (cur != NULL)
{
count++;
cur = cur->_next;
}
return count;
}
由于链表内存空间的不连续,想要获取队列元素个数,只能对链表进行遍历。以cur为变量,头结点为初值开始遍历结点,直到cur为NULL时跳出循环,此处用变量count计数,遍历完成后return count。
6.QueueEmpty函数-判断队列是否为空
bool QueueEmpty(Queue* q)
{
assert(q);
return q->_front == NULL;
}
条件表达式_front==NULL,若为真,则说明队列为空,返回bool类型值True。否则为假,队列不为空,返回False。
7.QueueDestroy函数-队列的销毁
void QueueDestroy(Queue* q)
{
assert(q);
QNode* cur = q->_front;
while (cur != NULL)
{
QNode* next = cur->_next;
free(cur);
cur = next;
}
q->_front = NULL;
q->_rear = NULL;
}
遍历链表对结点进行依次释放,释放完成后将Queue内变量置为初始值即可。
队列介绍到此结束,感谢阅读!