目录
一.队列的概念和队列的2种结构
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out)。入队列:进行插入操作的一端称为 队尾。出队列:进行删除操作的一端称为 队头。基本结构:
队列的实现可以用链表也可以用数组。(用链表更优,在使用数组来从数组头部出数据时,需要挪动大量的数据,效率较低;如果使用链表来实现,就可以让链表的头做队头,链表的尾做队尾,数据的插入和删除操作都比较方便)。
用数组实现队列:
用链表实现队列:
二.队列的各个函数接口及实现
1.队列的结构体定义(链式结构)
定义链式结构的队列,因为队列是先进先出的,(要实现它的功能需要头删和尾插)所以我们在这里分别定义了链表的头指针(head)和尾指针(tail)。
typedef int QDataType;
typedef struct QueueNode
{
struct QueueNode* next;
QDataType data;
}QueueNode;
typedef struct Queue
{
QueueNode* head;
QueueNode* tail;
}Queue;
2.队列的初始化
刚开始进行初始化的时候,队列里面还没有数据,所以应该先把头指针和尾指针先置空(NULL)。
void QueueTnit(Queue* pq)//初始化
{
assert(pq);
pq->head = pq->tail = NULL;
}
3.队列的销毁
我们实现的队列是用链表来实现的,所以要销毁队列就是要销毁链表,(所以和链表的销毁是一样的),要遍历队列,然后逐一的释放每个结点的空间,最后再把头指针和尾指针置空就可以了。
void QueueDestroy(Queue* pq)//销毁
{
assert(pq);
QueueNode* cur = pq->head;
while (cur)
{
QueueNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
}
4.队尾数据入队列(尾插)
入队 和链表的尾插是一样的,首先申请一块新的空间把要插入的数据放到新开辟的这块空间中,然后判断队列是否为空(head是否等于NULL),如果队列为空就是链表的头插,那么头指针和尾指针都要指向这个新的结点;如果队列不为空就是链表的尾插,那么只需要把新节点链接到尾指针的后面,然后更新尾指针(让尾指针指向新的尾 --- 也就是所插入的新节点)。
void QueuePush(Queue* pq, QDataType x)//添加 尾插
{
assert(pq);
QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
if (newnode == NULL)
{
printf("malloc fail\n");
exit(-1);
}
newnode->next = NULL;
newnode->data = x;
if (pq->head == NULL)
{
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;
}
}
5.队头数据出队列(头删)
出队 和链表的头删是一样的,要判断一下队列是否为空,为空的话就不能删了。
要删除头结点,所以要先保存一下头结点的下一个结点的位置(next=head->next;),然后把头结点释放掉(free),让头指针指向新的头(next所指向的位置) (head=next),
还有一种情况需要进行特殊的考虑:
就是当删除头结点以后,队列如果为空了的话(head=NULL),这个时候要记得把尾指针也置空(tail=NULL)。
void QueuePop(Queue* pq)//删除 头删
{
assert(pq);
assert(!(QueueEmpty(pq)));
QueueNode* next = pq->head->next;
free(pq->head);
pq->head = next;
if (pq->head == NULL)
// 这个情况是需要特殊来判断一下的,就是删除以后链表为空了,
// 这时要记得把尾指针(tail)也置空一下
{
pq->tail = NULL;
}
}
6.取队头的数据
取数据,需要首先判断一下队列是否已经为空了,如果已经为空了,队列里面就没有数据了,也就不能取数据了。
队头的数据:head->data
QDataType QueueFront(Queue* pq)//取队头的数据
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->data;
}
7.取队尾的数据
取数据,需要首先判断一下队列是否已经为空了,如果已经为空了,队列里面就没有数据了,也就不能取数据了。
队尾的数据:tail->data
QDataType QueueBack(Queue* pq)//取队尾的数据
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->data;
}
8.计算队列的数据个数(队列的大小)
计算队列的数据个数:直接遍历链式队列的每一个结点,然后返回size就可以了。
int QueueSize(Queue* pq)//队列的大小
{
QueueNode* cur = pq->head;
int size = 0;
while (cur)
{
cur = cur->next;
size++;
}
return size;
}
9.判断队列是否为空
如果 队列为空 == 头结点为NULL
头结点为空(NULL),则队列为空; 头结点不为空,则队列不为空。
bool QueueEmpty(Queue* pq)//判断队列是否为空
{
assert(pq);
return pq->head == NULL;
}