1.什么是队列?
队列:只允许在一端进行数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)的特点。
入队列:进行插入操作的一端称为队尾。
出队列:进行删除操作的一端称为队头。
2.队列的实现:
可以用数组和链表模拟实现,在这里我们用链表实现
typedef int QDataType;
typedef struct QueueNode {
QDataType data;
struct QueueNode* next;
//先创建一个队列的结构体
}QNode;
typedef struct Queue {
//再创建一个可以指向队列头和尾的结构体(有头指针和尾指针)
QNode* head;
QNode* tail;
}Queue;
先创建一个QNode的结构体为每一个队列的节点,里面有对应节点的数据与下个节点的地址。
再创建一个结构体,里面放一个头指针与尾指针,指向队列的头和尾。
接下来看看队列有哪些函数接口:
①:队列的初始化
void InitQueue(Queue* pq) {
assert(pq);
pq->head = NULL;
pq->tail = NULL;
}
只需将头尾指针置为空即可
②:入队
void QueuePush(Queue* pq,QDataType x) {
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));//动态内存开辟一个新节点
if (newnode == NULL) {
printf("动态内存开辟失败");
exit(-1);
}
newnode->next = NULL;
newnode->data = x;
if (pq->tail == NULL) {
assert((pq->head) == NULL);
pq->head = pq->tail = newnode;
}
else {
pq->tail->next = newnode;
pq->tail = newnode;//注意尾指针也要移动到对应的尾部
}
}
由于队列FIFO的特点,入队应该就是在链表尾部插入一个节点。
注意:当队列中没有元素时要单独处理!
③:出队
void QueuePop(Queue* pq){
assert(pq);
assert(pq->head && pq->tail);//保证队列不为空
if (pq->head->next == NULL) //只有一个元素时单独处理
{
free(pq->head);
pq->head = pq->tail = NULL;
}
else {
QNode* record = pq->head->next; //记录下一个节点
free(pq->head);
pq->head = record;//头指针移动到下一个节点完成头删
}
}
④:获得队头和队尾的数据元素的值:
QDataType QueueFront(Queue* pq) { //获取队头的值
assert(pq);
assert(pq->head && pq->tail);//确保队列不为空
return pq->head->data;
}
QDataType QueueBack(Queue* pq) { //获取队尾的值
assert(pq);
assert(pq->head && pq->tail);
return pq->tail->data;
}
⑤:队列的大小
遍历链表
int QueueSize(Queue* pq) {
assert(pq);
int count = 0;
QNode* cur = pq->head;
while (cur) {
++count;
cur = cur->next;
}
return count;
}
⑥:判断队列是否为空
bool QueueEmpty(Queue* pq){
assert(pq);
if (pq->head == NULL)
{
return true;
}
else {
return false;
}
}
**我这里代码比较冗余 可以直接 return pq->head == NULL **
⑦:队列的销毁
void DestroyQueue(Queue* pq) {
assert(pq);
QNode* cur = pq->head;
while (cur) {
QNode* NEXT = cur->next;//记录下一个节点,一个节点一个节点进行销毁
free(cur);
cur = NEXT;
}
pq->head = pq->tail = NULL;
}