目录
队列的概念和结构
队列:只允许在一端进行插入数据操作,另一端进行删除数据操作的特殊线性结构,具有"先进先出"的特点,进行插入数据的一端称为队尾,出数据的一端称为队头。
队列的实现
队列的实现还是建立三个文件,一个头文件,两个源文件。
cs
typedef int QueDateType;
typedef struct SList {
struct SList* next;
QueDateType date;
}SL;
typedef struct Queue {
SL* head;
SL* tail;
int size;
}Queue;
创建两个结构体,队列的实现是用链表来实现的,如果使用数组来实现,那么效率就太低了,在进行数据删除时,需要挪动数据,在链表中删除数据就是头删,插入数据就是尾插,效率远比使用数组实现高效。
SList是一个节点,成员next 存储下一个节点的地址,date存储该节点的数据,Queue结构体包含两个节点指针,一个指向头,一个指针尾,还有size来统计节点个数。

队列初始化
函数声明
cs
void QueInit(Queue* p);
函数定义
cs
void QueInit(Queue* p)
{
assert(p);
p->head = p->tail = NULL;
p->size = 0;
}
初始化队列,没有节点需要将头指针和尾指针置空,size置为0。
入队操作
函数声明
cs
void QuePush(Queue* p, QueDateType x);
函数定义
cs
void QuePush(Queue* p, QueDateType x)
{
assert(p);
SL* newnode = (SL*)malloc(sizeof(SL));
if (newnode == NULL)
{
perror("QuePush:malloc");
return;
}
newnode->date = x;
newnode->next = NULL;
if (p->size == 0)
{
p->head = p->tail = newnode;
}
else
{
p->tail->next = newnode;
p->tail = newnode;
}
p->size++;
}
队列的入队操作,根据队列"先进先出"特点,所以我们插入数据在尾部。
先对结构体指针断言,用malloc函数申请一片空间来存储一个节点,这时就有两种情况,一个是队列为空,和队列不为空。当队列为空时,头指针和为尾指针都指向新开辟的节点,当队列不为空,就只需要改变尾指针就可以,最后size++。
出队操作
函数声明
cs
void QuePop(Queue* p);
函数定义
cs
void QuePop(Queue* p)
{
assert(p);
assert(p->head != NULL);
SL* next = p->head->next;
free(p->head);
p->head = NULL;
p->head = next;
p->size--;
}
出队操作不能一直执行,当队列为空时不可执行,因此对其断言,头指针不可以为空。定义一个节点指针来保存头指针的下一个节点的地址,这样释放头指针后还可以找到下一个节点,最后size--。
取队头的元素
函数声明
cs
QueDateType QueTop(Queue* p);
函数定义
cs
QueDateType QueTop(Queue* p)
{
assert(p);
assert(!QueJuS(p));
return p->head->date;
}
除了对结构体判空,还需要对节点个数断言,没有节点就不进行该操作,反之返回队头元素。
判断队列是否为空
函数声明
cs
bool QueJuS(Queue* p);
函数定义
cs
bool QueJuS(Queue* p)
{
assert(p);
return p->size == 0;
}
该函数返回类型为布尔类型,当size等于0时返回true,反之返回false。
队列的销毁
函数声明
cs
void QueDestroy(Queue* p);
函数定义
cs
void QueDestroy(Queue* p)
{
assert(p);
SL* cur = p->head;
while (cur)
{
SL* next = cur->next;
free(cur);
cur = next;
}
p->size = 0;
}
每插入一个节点就需要进行malloc,所以销毁队列时需要对每一个节点进行空间释放,最后size置为0。