1、队列的概念及结构
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)排队功能的线性表。
入队列:进行插入操作的一端称为队尾。
出队列:进行删除操作的一端称为队头。
2、队列的实现
线性表有顺序存储和链式存储,队列也是线性表的一种表现形式。因而,队列也可以数组和链表的结构实现。顺序结构一般采用数组形式,在存储空间内开辟一块大小为n的数组,并将队列的数据存储在素组的前n单元内。数组下标0为队头,下标n-1为队尾。数组的入队列如下图所示:
队列从下标0位置的队头出,则整个队列在数组上都必须整体向前移动,以保障下标0处的队头不为空,此时的时间复杂度为0(n),具体的出队列如下图所示:
队头出队列时,队列需要整体前移,这大大降低了队列的效率。为了增加效率,使用链表的结构实现队列更优一些。队列的链表存储结构,本质上就是线性表的单链表,只不过它只能尾插头删而已,因而称之为链队列。
为了方便代码实现,下图中head
指针指向队头结点,tail
指针指向队尾结点。
空队列时,head
与tail
都指向头结点,下图所示:
2.1 入队操作
入队列操作就是在链表尾部an处插入新结点,如下图所示:
链队列的入队操作的代码如下:
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
if (pq->tail == NULL)
{
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;
}
}
2.2 出队操作
出队列就是头结点a1出队(删除),a1的下一个结点作为新的头结点。
链队列的出队列操作的代码如下:
void QueuePop(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}
else
{
QNode* del = pq->head;
pq->head = pq->head->next;
free(del);
del = NULL;
}
}
2.3 队列是否为空的判定函数
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL && pq->tail == NULL;
}
2.4 取队头数据
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->data;
}
2.5 取队尾数据
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->data;
}
2.6 队列大小
int QueueSize(Queue* pq)
{
assert(pq);
int size = 0;
QNode* cur = pq->head;
while (cur)
{
cur = cur->next;
++size;
}
return size;
}
2.7 初始化
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = NULL;
pq->tail = NULL;
}
2.8 队列清空
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* del = cur;
cur = cur->next;
free(del);
del = NULL;
}
pq->head = pq->tail = NULL;
}
3、测试
为了检验上面的逻辑及代码的可行性,使用下面代码进行测试,包括了队列初始化、入队列、出队列、打印队列的占用空间(int类型)大小及清空队列(释放链表在对内的空间)。
void QueueTest1()
{
Queue q;
QueueInit(&q);
QueuePush(&q, 10);
QueuePush(&q, 20);
QueuePush(&q, 30);
QueuePush(&q, 40);
QueuePop(&q);
int n = QueueSize(&q);
printf("The number of queue is %d", n);
QueueDestroy(&q);
}
在队列尾部插入数据后,队列内部的数据下图所示:
队列头部出队列后的队列内部数据具体下图所示:
输出调试函数的相关结果下图所示,此时队列内仅剩3个整型数。