在前面我们学习了另一种结构:栈。其特点是,后进先出。对应的,本章我将为大家介绍“队列”,一中先进先出的结构。
1.队列的概念
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) :
由于队列的这一特点,所以在对数据进行操作时
在队列的头,取出数据。
在队列的尾,插入数据。
这一特点,在后面我们定义队列结构的时候可以清晰的认识到。
从上图,我们可以直观地看到数据如何进出队列。
2.队列结构的定义
我们在这里使用链式的结构去实现队列。
原因是,使用链式的结构对数据的删除更加方便,而如果使用数组式结构则会使效率降低。
我们首先确定队列结构中的需要哪些变量。
1.对每一个结点的定义。
2.由于入在队尾,出在队头,所以我们还要有记录队列的对头队尾的变量。
具体代码如下。
typedef int QueueDatatype;
typedef struct QueueNode
{
struct QueueNode* next;//指向下一个结点
QueueDatatype data;//结点存储的数据
}QN;
typedef struct Queue
{
QueueNode* phead;//记录队列的头
QueueNode* ptail;//记录队列的尾
}Queue;
我们可以看到,在定义记录队列头和尾的结构体中,phead和ptail都是QueueNode类型,所以实际上这是一个套娃的结构。 每一个结点中都包含data和指向下一个结点的next。
3.数据的插入
从前面的介绍中我们可以知道,队列数据的插入从尾插入。
在进行队列插入前要首先申请空间,我们直接上代码。
void QueueInsert(Queue* pq, QueueDatatype x)
{
assert(pq);//先判断指针是否为空
QN* newnode = (QN*)malloc(sizeof(QN));//开辟节点
newnode->data = x;//定义结点内部
newnode->next = NULL;
if (pq->phead == NULL)
{
pq->phead =pq->ptail= newnode;//队列为空,则首尾都为开辟的结点
}
else
{
pq->ptail->next = newnode;//尾插,用尾去链接
pq->ptail = newnode;//将newnode定义为尾
}
}
和链表一样,数据的插入前需要队指针进行判空,插入情况分为两种:1.队列为空 2.队列不为空。
4.数据的删除
void QueuePop(Queue* pq)
{
assert(pq);
assert(pq->phead);//如果phead为空则无法进删除操作,所以需要判空
if (pq->phead->next == NULL)//如果phead->next为空,则不需要关心链接问题,直接删除
{
free(pq->phead);
}
else
{
QN* cur = pq->phead->next;//有多个结点则需要先找phead-> next再free,否则没有新头
free(pq->phead);//释放旧的头结点
pq->phead = cur;//将原来保存的phead->next作为新头
}
}
在对队列数据进行删除操作时,要注意到队列中是多个结点还是只有一个结点,分情况处理。
5.取出队列中首尾元素
QueueDatatype QueueBack(Queue* pq)//取队列尾元素
{
assert(pq);
assert(pq->phead);//防止队列为空
return pq->ptail->data;
}
7
QueueDatatype QueueFront(Queue* pq)//取队列首元素
{
assert(pq);
assert(pq->phead);
return pq->phead->data;
}
6.队列判空
判空最基础的操作我们就直接上代码了。
bool QueueEmpty(Queue* pq)
{
assert(pq);
if (pq->phead == NULL)
{
return true;
}
else
{
return false;
}
}
7.打印队列
进行完以上操作,还是要看看我们创建的队列,我们看看如打印。
void QueuePrint(Queue* pq)
{
assert(pq);
assert(pq->phead);
QN* cur = pq->phead;//替换首结点,保证首不动
while (cur)
{
printf("%d ", cur->data);
cur = cur->next;
}
}
是不是很熟悉的代码呢,只要是链式的,大家一定要记住首结点不要移动!!!
8.总结
在队列这一部分我们可以看到很多链表的影子,如果大家对队列疑问较多,可以先学习链表。
此外,队列元素先进先出,栈元素后进先出!!!一定不要混淆哦!