在今天的学习中,将会介绍栈和队列的概念,以及其功能的实现,还有其应用场景
前言
队列是只允许再一端进行插入数据操作,另一端进行删除数据操作的特殊线性表,和栈不同的是,队列是先进先出的,进行插入的一端叫做队尾,出队列的一段叫做队头。
就像排队上公交车一样先排的肯定先进公交车,后来的就等着。 更简洁一点来说就是:
队列的实现
队列也是一种特殊的线性表,所以也可以用顺序表或者链表来实现,那么该选谁呢?这时候我们就要思考效率的问题,如果用顺序表的话,数组头就是队头,我要出队的话肯定是从数组头开始出,那么我后面的数据全要挪移,这复杂度就变成O(N)了,如果使用链表呢?用链表的话无论是入队还是出队,都只需要挪动前一个节点或者后一个节点的指向而已,所以我们选用链表来实现队列。 实现功能如下:
1.初始化队列
2.购买节点
3.入队
4.出队
5.检查队列是否为空
6.销毁队列
首先如果是链表的话,我们现要有一个节点的结构体:
typedef struct QListNode
{
struct QListNode* _next;
QDataType _data;
}QNode;
typedef struct Queue
{
QNode* _front;
QNode* _rear;
}Queue;
这里面有两个结构体,其中QNode是队列中每一个节点,Queue代表整个队列,其中存储队头和队尾。(有点头节点那意思了)
1.初始化队列
void QueueInit(Queue* q)
{
q->_front = NULL;
q->_rear = NULL;
}
2.购买节点
QNode * BuyQueueNode(QDataType x)
{
QNode * cur = (QNode*)malloc(sizeof(QNode));
cur->_data = x;
cur->_next = NULL;
return cur;
}
这是链表的节点,注意是队列的结构体存的结构体指针的类型,不是队列的类型
3.入队
void QueuePush(Queue* q, QDataType data)
{
QNode * cur = BuyQueueNode(data);
if(q->_front==NULL)
{
q->_front = q->_rear = cur;
}
else
{
q->_rear->_next = cur;
q->_rear = cur;
}
}
入队要分成两种情况,一种是队列中没有节点,一种是已经有节点了,没有节点的时候,我们直接让队头和队尾的指针都指向新节点就可以了,那有节点的时候呢?有节点的时候就和链表的尾插是一样的,但是要注意,此时rear 存储的是队尾,我们尾插之后,要让rear 后移一位成新队尾。 红色是我们新进队的节点,这时候队尾的指向就不对了,要指向新节点。
4.出队
void QueuePop(Queue* q)
{
assert(q);
if(q->_front == NULL)
return ;
QNode *cur = q->_front->_next;
free(q->_front);
q->_front = cur;
}
出队就是头删,别忘了要把储存队头的指针后移一位。
检查队列是否为空
int QueueEmpty(Queue* q)
{
if(q->_front == NULL)
return 1;
else return 0;
}
销毁链表
void QueueDestroy(Queue* q)
{
if(q->_front == NULL)
return ;
while(q->_front)
{
QueuePop(q);
}
}
销毁链表的时候就一直执行头删,删完为止。
应用:
有时候我们会用栈实现队列,队列实现栈,在实际应用中循环的队列是使用次数比较高的,在下一篇博客中将会介绍用队列实现栈,用栈实现队列,以及循环队列的写法。
源码
Queue.h
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int QDataType;
typedef struct QListNode
{
struct QListNode* _next;
QDataType _data;
}QNode;
typedef struct Queue
{
QNode* _front;
QNode* _rear;
}Queue;
void QueueInit(Queue* q);
void QueuePush(Queue* q, QDataType data);
void QueuePop(Queue* q);
QDataType QueueFront(Queue* q);
QDataType QueueBack(Queue* q);
int QueueSize(Queue* q);
int QueueEmpty(Queue* q);
void QueueDestroy(Queue* q);
Queue.c
#include"Queue.h"
QNode* BuyQueueNode(QDataType x)
{
QNode* cur = (QNode*)malloc(sizeof(QNode));
cur->_data = x;
cur->_next = NULL;
return cur;
}
void QueueInit(Queue* q)
{
q->_front = NULL;
q->_rear = NULL;
}
void QueuePush(Queue* q, QDataType data)
{
QNode* cur = BuyQueueNode(data);
if (q->_front == NULL)
{
q->_front = q->_rear = cur;
}
else
{
q->_rear->_next = cur;
q->_rear = cur;
}
}
void QueuePop(Queue* q)
{
assert(q);
if (q->_front == NULL)
return;
QNode* cur = q->_front->_next;
free(q->_front);
q->_front = cur;
}
QDataType QueueFront(Queue* q)
{
return q->_front->_data;
}
QDataType QueueBack(Queue* q)
{
return q->_rear->_data;
}
int QueueSize(Queue* q)
{
QNode* cur;
int cnt = 0;
for (cur = q->_front; cur; cur = cur->_next)
{
cnt++;
}
return cnt;
}
int QueueEmpty(Queue* q)
{
if (q->_front == NULL)
return 1;
else return 0;
}
void QueueDestroy(Queue* q)
{
if (q->_front == NULL)
return;
while (q->_front)
{
QueuePop(q);
}
}
Queuetest.c
#include"Queue.h"
int main()
{
Queue q ;
QueueInit(&q);
QueuePush(&q, 1);
QueuePush(&q, 1);
QueuePush(&q, 1);
QueuePush(&q, 1);
QueuePush(&q, 1);
QueuePush(&q, 1);
}
|