逻辑结构:线性结构
存储结构:链式存储
1.结构体
typedef int datatype;
typedef struct node
{
datatype data; // 数据域
struct node *next; // 指针域
} linkqueue_node_t, *linkqueue_list_t;
// linkqueue_list_t p === linkqueue_node_t *
typedef struct // 将队列头指针和尾指针封装到一个结构体里
{
linkqueue_list_t front; // 相当于队列的头指针
linkqueue_list_t rear; // 相当于队列的尾指针
// 有了链表的头指针和尾指针,那么我们就可以操作这个链表
} linkqueue_t;
2.创建空队列
(1)开辟一个结构体类型大小的空间作为头结点
(2)开辟一块指针类型大小的空间存放头尾指针
(3)初始化头节点为空,初始化头尾指针指向头节点。
// 1.创建一个空的队列,用有头链表
linkqueue_t *CreateEmptyLinkQueue()
{
// 创建头节点
linkqueue_node_t *head = malloc(sizeof(linkqueue_node_t));
if (head == NULL)
{
perror("head malloc error");
return NULL;
}
// 头节点初始化
head->next = NULL;
// 创建空间存放头尾指针
linkqueue_t *p = (linkqueue_t *)malloc(sizeof(linkqueue_t));
if (p == NULL)
{
perror("q malloc error");
return NULL;
}
// 初始化头尾指针,头尾指针指向头节点
p->front = head;
p->rear = head;
return p;
}
3.入列
步骤:
(1)新建节点存放数据,指针域置空
(2)将新节点尾插到链表后
(3)移动尾节点,让新建节点成为新的尾节点
// 2.入列 data代表入列的数据
int InLinkQueue(linkqueue_t *p, datatype data)
{
// 创建新节点
linkqueue_node_t *pnew = (linkqueue_node_t *)malloc(sizeof(linkqueue_node_t));
// 初始化新节点
pnew->data = data;
pnew->next = NULL;
// 连接新节点到链表
p->rear->next = pnew;
// 移动尾指针
p->rear = pnew;
return 0;
}
4.出列
释放头节点,将头节点的下一个节点做成新的头节点通过返回其数据域中数据(相当于数据域无效了成为头节点了)。
步骤:
(1)判断队列是否为空
(2)用指针指向要释放头节点,暂存头节点
(3)头指针后移,第二个节点作为新的头节点
(4)释放旧的头节点
(5)返回要出队的数据,也就是现在新的头节点的数据
// 3.出列
datatype OutLinkQueue(linkqueue_t *p)
{
datatype temp;
// 判空
if (IsEmptyLinkQueue(p))
{
perror("队列已空");
return -1;
}
// 创建指针指向将要出队的头节点
linkqueue_node_t *pdel;
pdel = p->front;
// 数据出队
temp = pdel->next->data;
// 等同于 temp = p->front->next->data;
// 移动头节点
p->front = p->front->next;
// 释放空间
free(pdel);
pdel = NULL;
printf("%d\n", temp);
return temp;
}
// 4.判断队列是否为空
int IsEmptyLinkQueue(linkqueue_t *p)
{
return p->front == p->rear;
}
5.计算队列长度
定义一个指针循环遍历队列的节点,每遍历到一个节点,长度+1
// 5.求队列长度的函数
int LengthLinkQueue(linkqueue_t *p)
{
int length = 0;
// 定义结构体类型的指针代替头指针移动
linkqueue_node_t *p1;
p1 = p->front;
while (p1 != p->rear)
{
p1 = p1->next;
length++;
}
printf("长度为:%d\n", length);
return length;
}
6.清空队列
与出队比较相似,不断后移头指针,不断释放头节点。
// 6.清空队列
int ClearLinkQueue(linkqueue_t *p)
{
// 循环释放头节点
// 创建指针指向出队的节点
linkqueue_node_t *pdel = NULL;
while (p->front != p->rear)
{
// 指向释放的头节点
pdel = p->front;
// 移动头指针,让第二个节点成为新的头节点
p->front = p->front->next;
// 释放头节点
free(pdel);
pdel = NULL;
}
// 判空
if (IsEmptyLinkQueue(p))
{
perror("队列已空");
return 0;
}
return 0;
}
7.头文件
#include <stdio.h>
#include <stdlib.h>
typedef int datatype;
typedef struct node
{
datatype data; // 数据域
struct node *next; // 指针域
} linkqueue_node_t, *linkqueue_list_t;
// linkqueue_list_t p === linkqueue_node_t *
typedef struct // 将队列头指针和尾指针封装到一个结构体里
{
linkqueue_list_t front; // 相当于队列的头指针
linkqueue_list_t rear; // 相当于队列的尾指针
// 有了链表的头指针和尾指针,那么我们就可以操作这个链表
} linkqueue_t;
// 1.创建一个空的队列
linkqueue_t *CreateEmptyLinkQueue();
// 2.入列 data代表入列的数据
int InLinkQueue(linkqueue_t *p, datatype data);
// 3.出列
datatype OutLinkQueue(linkqueue_t *p);
// 4.判断队列是否为空
int IsEmptyLinkQueue(linkqueue_t *p);
// 5.求队列长度的函数
int LengthLinkQueue(linkqueue_t *p);
// 6.清空队列
int ClearLinkQueue(linkqueue_t *p);