1 引子
- 排队各位肯定都知道对吧,无非就是"叫一个走一个,叫一个走一个",我们在医院等号的时候,其实就是把你的号放进一个虚拟的队列里头,模拟排队,这就是队列
2 队列的定义
- 队列是一个带有限制的线性表,他限制在你只能从尾部进入数据,再从头部出数据,就像排队一样,先进去的肯定先出来,后进去的肯定后出来(我么们来看看动画)
3 队列的实现
3.1 队列类型定义
- 队列我们一般用链表实现,当然用顺序表其实也是可以的,只是说用起来没有链表方便
typedef int QDataType;
//链表节点定义
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QNode;
typedef struct Queue
{
QNode* front;
QNode* rear;
int size;
}QU;
3.2 需要实现的接口
//队列数据量
int QSize(QU* pq);
//队列的判空
bool QEmpty(QU* pq);
//队列的初始化
void QInit(QU* pq);
//队列的删除
void QDestroy(QU* pq);
//出队
void QPop(QU* pq);
//入队
void QPush(QU* pq, QDataType x);
//取队头
QDataType QFront(QU* pq);
//取队尾
QDataType QBack(QU* pq);
3.3 队列的初始化
- 队列其实就是带有限制的链表,初始化方式按照链表来就行
//队列的初始化
void QInit(QU* pq)
{
assert(pq);
pq->front = NULL;
pq->rear = NULL;
pq->size = 0;
}
3.4 队列的删除
- 删除也是同理,只需要按照链表标准的删除方式就行
//队列的删除
void QDestroy(QU* pq)
{
assert(pq);
QNode* cur = pq->front;
while (cur)
{
QNode* lastnode = cur;
cur = cur->next;
free(lastnode);
}
pq->front = NULL;
pq->rear = NULL;
pq->size = 0;
}
3.5 队列的数据量
- 这里直接返回size就行
//队列数据量
int QSize(QU* pq)
{
assert(pq);
return pq->size;
}
3.6 队列的判空
- 这里我们直接用表达式判空,如果 size 为 0 就返回 true,否则返回 false
//队列的判空
bool QEmpty(QU* pq)
{
assert(pq);
return pq->size == 0;
}
3.7 取队头
- 取队头要保证队列不能为空,要判一下空(当然你用 if 这种不会报错的判空也行)
//取队头
QDataType QFront(QU* pq)
{
assert(pq);
assert(!QEmpty(pq));
return pq->front->data;
}
3.8 取队尾
- 和取队头方式一样,只是返回值换成队尾而已
//取队尾
QDataType QBack(QU* pq)
{
assert(pq);
assert(!QEmpty(pq));
return pq->rear->data;
}
3.9 出队
- 注意一定要考虑只剩一个数据和没有数据的情况
//出队
void QPop(QU* pq)
{
assert(pq);
if (!QEmpty(pq))//这里我们用 if 这种不报错的判空
{
QNode* lastnode = pq->front; //存储当前节点的地址
if (pq->rear == pq->front) // 如果只剩下最后一个节点了就先让队尾置为空
{
pq->rear = NULL;
}
pq->front = pq->front->next; //让front往后挪,如果只剩一个节点了那front就会变成空
free(lastnode); //释放要出队的节点
pq->size--; //size减1
}
}
3.10 入队
- 入队需要考虑队列里只有一个结点的情况,还需要把申请新节点打包进入队函数里
//入队
void QPush(QU* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)calloc(1, sizeof(QNode)); //队列没有其他函数会申请新节点,我们直接就把申请新节点这个步骤打包进入队里了
if (newnode == NULL)
{
perror("QPush::calloc");
exit(1);
}
newnode->data = x;
newnode->next = NULL;
if (pq->rear == NULL) //如果队列里一个节点都没有,就让 front 和 rear 全部指向新节点
{
pq->front = newnode;
pq->rear = newnode;
}
else //如果队列里已经有节点了,就执行尾插
{
pq->rear->next = newnode;
pq->rear = newnode;
}
pq->size++; //别忘了让 size 加1
}
4 完整实现代码
queue.h
//类型定义
typedef int QDataType;
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QNode;
typedef struct Queue
{
QNode* front;
QNode* rear;
int size;
}QU;
//函数定义
//队列数据量
int QSize(QU* pq);
//队列的判空
bool QEmpty(QU* pq);
//队列的初始化
void QInit(QU* pq);
//队列的删除
void QDestroy(QU* pq);
//出队
void QPop(QU* pq);
//入队
void QPush(QU* pq, QDataType x);
//取队头
QDataType QFront(QU* pq);
//取队尾
QDataType QBack(QU* pq);
queue.c
//函数定义
//队列数据量
int QSize(QU* pq)
{
assert(pq);
return pq->size;
}
//队列的判空
bool QEmpty(QU* pq)
{
assert(pq);
return pq->size == 0;
}
//队列的初始化
void QInit(QU* pq)
{
assert(pq);
pq->front = NULL;
pq->rear = NULL;
pq->size = 0;
}
//队列的删除
void QDestroy(QU* pq)
{
assert(pq);
QNode* cur = pq->front;
while (cur)
{
QNode* lastnode = cur;
cur = cur->next;
free(lastnode);
}
pq->front = NULL;
pq->rear = NULL;
pq->size = 0;
}
//出队
void QPop(QU* pq)
{
assert(pq);
if (!QEmpty(pq))
{
QNode* lastnode = pq->front;
if (pq->rear == pq->front)
{
pq->rear = NULL;
}
pq->front = pq->front->next;
free(lastnode);
pq->size--;
}
}
//入队
void QPush(QU* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)calloc(1, sizeof(QNode));
if (newnode == NULL)
{
perror("QPush::calloc");
exit(1);
}
newnode->data = x;
newnode->next = NULL;
if (pq->rear == NULL)
{
pq->front = newnode;
pq->rear = newnode;
}
else
{
pq->rear->next = newnode;
pq->rear = newnode;
}
pq->size++;
}
//取队头
QDataType QFront(QU* pq)
{
assert(pq);
assert(!QEmpty(pq));
return pq->front->data;
}
//取队尾
QDataType QBack(QU* pq)
{
assert(pq);
assert(!QEmpty(pq));
return pq->rear->data;
}
佬!都看到这了,如果觉得有帮助的话一定要点赞啊佬 >v< !!!
放个卡密在这,感谢各位能看到这儿啦!