队列是一种操作受限的线性表,先进先出
数据处理尾端进入,从头部离开
数据的入队理解为线性表的尾插法,数据的出队理解为线性表的指定位置删除
在程序中,队列使用的是结构体
,而非结构体指针,所以在初始化时也就不用为队列申请内存了
使用单链表,双链表都行,这里我们使用单链表创建
在此程序里,链表作为基层单元被使用,并且这个单链表将有头结点
.
#include
#include
typedef int ElemType;
typedef struct LinkNode
{
ElemType data;
LinkNode *next;
} LinkNode;
除此之外,我们还需要定义另外的结构体,用以表示较为活跃的头部和尾部
整体的逻辑是通过头尾的变化,来影响
链表节点的增删,如果忽略操作先后的话,可以视为通过队列控制节点的增删
我们并未明显的将链表节点的内存申请定义出来,而是放在了初始化方法的内部,之后使用队列的头尾指针指向它,因为对外来说,我们统一使用队列来控制链表,所以不需要在外部定义链表,这个链表被我们严肃的封装在了队列里
void Init(Queue &Q)
{
LinkNode *L = (LinkNode *)calloc(1, sizeof(LinkNode));
Q.head = L;
Q.tail = L;
}
尾插法入队
此时队列的头尾已经保存了链表节点的地址,所以我们只需要使用队列作为形参即可,依旧可以实现对队列的操作
相当将队列的头尾指针拿到列明面上来,那么出入队也就是对头尾指针数据的操作
此时的入队是对尾节点的操作,在变更指向之前,需要先把链表续上
.
void EnQueue(Queue &Q, ElemType data)
{
/*创建节点,追加至尾部*/
LinkNode *tempNode = (LinkNode *)calloc(1, sizeof(LinkNode));
tempNode->data = data;
Q.tail->next = tempNode; // 先把链表续上
Q.tail = tempNode;
}
当我们使用calloc
方法申请内存时,tempNode->next
已经被设置为NULL
头结点之后的第一个位置结点删除.
设计出队的返回值为布尔类型,并使用引用形参带回数据
我们使用的是带有头结点
的链表,所以当两者相等的时候,即为第一位置的节点已经出队了,所以无可出队
队列的head指针
永远指向的是头结点
,而不是第一个节点,就像核酸窗口里面的检测人员不会变,会变的是外面排队的人,那么我们在处理删除的刚好是尾结点的时候,就要强制的让队列尾指针
指向队列头结点
来表示队列为空状态
不仅要考虑头结点,还有考虑尾结点,最后不要忘记释放内存
bool DeQueue(Queue &Q, ElemType &data)
{
/*我们使用的是带有头结点的链表,所以当两者相等的时候,即为第一位置的节点已经出队了,所以无可出队*/
if (Q.head == Q.tail)
{
return false;
}
LinkNode *tempNode = Q.head->next; // 临时节点指向第一位置节点
data = tempNode->data; // 拿到数据
Q.tail->next = tempNode->next; // 这里是尾结点也没关系
if (Q.tail == tempNode) // 这里需要处理尾结点
{
Q.tail = Q.head;
}
free(tempNode);
return true;
}
也就是说,我们一般对于定义为结构体的数据类型,不会使用指针,就像这里的引用,它已经完全的指向了从内存中申请来的链表空间的头和尾.我们只要在方法中进行对应的链表加工即可
可以将这个队列看做趁手的工具,用来操作数据,就像数组可以使用下标访问
将链表节点试做基本的结构类型,就像int,如此便可理解到一点套娃的门道.
#include
#include
typedef int ElemType;
typedef struct LinkNode
{
ElemType data;
LinkNode *next;
} LinkNode;
typedef struct
{
LinkNode *head, *tail;
} Queue;
void Init(Queue &Q)
{
LinkNode *L = (LinkNode *)calloc(1, sizeof(LinkNode));
Q.head = L;
Q.tail = L;
}
void EnQueue(Queue &Q, ElemType data)
{
/*创建节点,追加至尾部*/
LinkNode *tempNode = (LinkNode *)calloc(1, sizeof(LinkNode));
tempNode->data = data;
Q.tail->next = tempNode; // 先把链表续上
Q.tail = tempNode;
}
bool DeQueue(Queue &Q, ElemType &data)
{
/*我们使用的是带有头结点的链表,所以当两者相等的时候,即为第一位置的节点已经出队了,所以无可出队*/
if (Q.head == Q.tail)
{
return false;
}
LinkNode *tempNode = Q.head->next; // 临时节点指向第一位置节点
data = tempNode->data; // 拿到数据
Q.head->next = tempNode->next; // 这里是尾结点也没关系
if (Q.tail == tempNode) // 这里需要处理尾结点
{
Q.tail = Q.head;
}
free(tempNode);
return true;
}
int main()
{
Queue Q;
bool flag;
ElemType element; // 存储出队元素
Init(Q);
// EnQueue(Q, 3);
EnQueue(Q, 4);
EnQueue(Q, 5);
EnQueue(Q, 6);
EnQueue(Q, 7);
flag = DeQueue(Q, element);
if (flag)
{
printf("dequeue success %d\n", element);
}
else
{
printf("dequeue fault\n");
}
}