前言
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out)
不管永远保持先进先出
入队列:进行插入操作的一端称为
队尾
出队列:进行删除操作的一端称为
队头
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。
今天使用链表实现队列。
一、queue.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int Datatype;
//这里要定义两个结构体,一个结构体存结点的数据,里面存自己的data和下一个结点的指针
//一个结构体存整个队列的数据,里面包含一个头指针一个尾指针
//还有一个保存队列长度的size,因为插入时从队尾,删除时从队头
typedef struct QueueNode
{
struct QueueNode* next;//
Datatype data;
}QNode;
typedef struct Queue
{
QNode* head;
QNode* tail;
int size;
}Queue;
//初始化
void Init(Queue* q);
//摧毁
void Destroy(Queue* q);
//从队尾入数据
void Push(Queue* q, Datatype x);
//打印
void Printf(Queue* q);
//从队头删除数据
void Pop(Queue* q);
//判空
bool Empty(Queue* q);
//获取队头数据
Datatype QueueFront(Queue* q);
Datatype QueueBack(Queue* q);
int QueueSize(Queue* q);
二、queue.c
1.初始化
void Init(Queue* q)
{
assert(q);
q->head = NULL;
q->tail = NULL;
q->size = 0;
}
初始化时将头指针和尾指针置空,长度设0
2.摧毁
void Destroy(Queue* q)
{
assert(q);
QNode* cur = q->head;
while (cur)
{
//注意此处如何迭代
QNode* next = cur->next;
free(cur);
cur = next;
}
//注意置空
q->head = q->tail = NULL;
q->size = 0;
}
挨个释放结点
然后将头尾指针置空,size置0
最后在外面将指向队列这个结构体的指针置空
3.插入
void Push(Queue* q,Datatype x)
{
assert(q);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail");
return;
}
newnode->next = NULL;//注意置空,否则循环时出问题
//队列为空时插入
if (q->head == NULL)
{
assert(q->head == NULL);//尾指针为空时断言头指针也为空,不为空就说明出错了
q->head = newnode;
q->tail = newnode;
}
else//队列不为空时插入
{
q->tail->next = newnode;
q->tail = newnode;
}
newnode->data = x;
q->size++;
}
4.删除
void Pop(Queue* q)
{
assert(q);
assert(!Empty(q));
// 1、一个节点
// 2、多个节点
if (q->head->next == NULL)
{
q->head = NULL;
q->tail = NULL;
}
//头删
else
{
QNode* next = q->head->next;
free(q->head);
q->head = next;
}
q->size--;
}
队列为空时依旧要检查不能删除
删除的时候为避免空指针的解引用问题,要分一个结点和多个结点情况讨论
5.判空
bool Empty(Queue* q)
{
assert(q);
//这里其实只要其中一个为空就说明队列为空了,但是为了防止前面出错,所以两个写都为空
return q->head==NULL && q->tail==NULL;
}
6.获取队头数据
Datatype QueueFront(Queue* q)
{
assert(q);
assert(!Empty(q));
return q->head->data;
}
7.获取队尾数据
Datatype QueueBack(Queue* q)
{
assert(q);
assert(!Empty(q));
return q->tail->data;
}
8.获取队列长度
int QueueSize(Queue* q)
{
assert(q);
return q->size;
}
9.queue.c
#include"queue.h"
void Init(Queue* q)
{
assert(q);
q->head = NULL;
q->tail = NULL;
q->size = 0;
}
void Destroy(Queue* q)
{
assert(q);
QNode* cur = q->head;
while (cur)
{
//注意此处如何迭代
QNode* next = cur->next;
free(cur);
cur = next;
}
//注意置空
q->head = q->tail = NULL;
q->size = 0;
}
void Push(Queue* q,Datatype x)
{
assert(q);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail");
return;
}
newnode->next = NULL;//注意置空,否则循环时出问题
//队列为空时插入
if (q->head == NULL)
{
assert(q->head == NULL);//尾指针为空时断言头指针也为空,不为空就说明出错了
q->head = newnode;
q->tail = newnode;
}
else//队列不为空时插入
{
q->tail->next = newnode;
q->tail = newnode;
}
newnode->data = x;
q->size++;
}
void Printf(Queue* q)
{
assert(q);
QNode* cur = q->head;
while (cur)
{
printf("%d ", cur->data);
cur = cur->next;
}
}
bool Empty(Queue* q)
{
assert(q);
//这里其实只要其中一个为空就说明队列为空了,但是为了防止前面出错,所以两个写都为空
return q->head==NULL && q->tail==NULL;
}
void Pop(Queue* q)
{
assert(q);
assert(!Empty(q));
// 1、一个节点
// 2、多个节点
if (q->head->next == NULL)
{
q->head = NULL;
q->tail = NULL;
}
//头删
else
{
QNode* next = q->head->next;
//q->head = q->head->next;//释放呢?
free(q->head);
q->head = next;
}
q->size--;
}
Datatype QueueFront(Queue* q)
{
assert(q);
assert(!Empty(q));
return q->head->data;
}
Datatype QueueBack(Queue* q)
{
assert(q);
assert(!Empty(q));
return q->tail->data;
}
int QueueSize(Queue* q)
{
assert(q);
return q->size;
}
总结
上面就是用链表实现栈,需要对链表和栈都有一定的了解。