数据结构之队列
队列和栈一样,也是一种思想,它是一种“先进先出”的思想,它本身可以是一个数组,也可以是一条链表!
同样,它仅仅只是一种思想,只要我们对数组或者链表,按照队列的规则操作即可。
下面举个排队打饭的例子让大家理解一下队列
排队打饭
ok,现在呢锤某人食堂开业了,来了五个人排队打饭,黑人先排,黄人再排,蓝人再排,绿人跟着,橙人慢了一点点排到了最后。
因为锤某人食堂,是个讲究先来先打原则的食堂
所以黑人就先打到饭溜溜球啦
按照这个规则
黄人打完,蓝人打,蓝人打完,绿人打,绿人打完,橙人打
就这样,终于全部人都打到饭啦!我们的白人大妈总算能休息休息了。
总结:
在锤某人的食堂,我们了解到,锤某人的食堂有个规则,那就是先排队的人先打饭。
那么在队列中呢,先进链表或数组的元素,先出队列
故队列是一种“先进先出”的思想,和栈恰好相反
我们还能发现我们的操作好像都是在窗口进行的!
所以可以知道,我们的操作基本上都是队尾进行操作!(尾插尾删)
那么接下来就是各位熟悉的代码环节咯,请各位动动小手,一块来!
代码
queue.h
这里使用的是我们熟悉的带头结点单链表哦!
注意队头结点(头结点)类型哦!
和前面我所写的单链表有所不同哈!
这样写单链表更加方便,并且省了一个结点的空间。
#ifndef __QUEUE_H__
#define __QUEUE_H__
#include<stdio.h>
#include<stdlib.h>
//带头结点的单链表
typedef int Elemtype; //队列的元素类型
//创建队列的结点类型
typedef struct node
{
Elemtype data;
struct node* next;
}Node;
//创建队列队类型(头结点类型)
typedef struct queue
{
Node* front; //队头
Node* rear; //队尾
int node_num; //结点个数
}Queue;
Queue* queue_init(); //初始化队(头结点)
Node* node_init(Elemtype d); //初始化结点
int Node_enqueue(Queue* q, Node* n); //结点入队
int Elemt_Enqueue(Queue* q, Elemtype d); //元素入队
int Is_empty(Queue* q); //判断队是否存在,队是否为空
Node* Node_Dequeue(Queue* q); //结点出队
Elemtype Elemt_Dequeue(Queue* q); //元素出队
void Destory_queue(Queue* q); //销毁队列
void printf_queue(Queue* q); //打印队列
#endif //!__QUEUE_H__
queue.c
准备工作!
#include"queue.h"//头文件不要忘记哦!
准备工作当然是初始化啦!
/*
* 初始化队列(头结点)
*/
Queue* queue_init()
{
Queue* q = (Queue*)malloc(sizeof(Queue));
q->front = NULL;
q->rear = NULL;
q->node_num = 0;
return q;
}
/*
* 初始化结点
*/
Node* node_init(Elemtype d)
{
Node* p = (Node*)malloc(sizeof(Node));
p->next = NULL;
p->data = d;
return p;
}
判断队列是否为空,或者是否存在
有的时候需要用到,这里附上啦!
/*
* 判断一个队列是否为空,为空返回1,否则返回0
* 参数:Queue * 类型,传入队
* 返回值:int 类型,空队返回1,否则返回0
*/
int Is_empty(Queue* q)
{
if (!q || !(q->rear)) //空队或队不存在
{
return 1;
}
return 0;
}
入队
入队分两种哈!
元素入队和结点入队
实际上没有太大区别,需要哪种用哪种叭!
/*
* 结点入队
* 参数:第一个参数:Queue * 类型,传入队
* 第二个参数:Node * 类型,传入结点
* 返回值:int 类型,入队成功返回1,入队失败返回0
*/
int Node_enqueue(Queue* q, Node* n)
{
if (!q) //队列不存在,返回0
{
printf("队列不存在,无法入队\n");
return 0;
}
if (q->rear == NULL)//空队,从无到有
{
q->front = n;
q->rear = n;
}
else//从少到多
{
q->rear->next = n;
q->rear = n;
}
q->node_num++;
return 1; //队列存在,返回1
}
/*
* 元素入队
* 参数:第一个参数:Queue * 类型,传入队
* 第二个参数:Elemtype 类型,传入数据域
* 返回值:int 类型,入队成功返回1,入队失败返回0
*/
int Elemt_Enqueue(Queue* q, Elemtype d)
{
if (!q) //队列不存在,返回0
{
printf("队列不存在,无法入队\n");
return 0;
}
Node* n = node_init(d);
if (q->rear == NULL)//空队,从无到有
{
q->front = n;
q->rear = n;
}
else
{
q->rear->next = n;
q->rear = n;
}
q->node_num++;
return 1; //队列存在,返回1
}
出队
出队同样也是分两种哈
元素出队和结点出队!
需要啥咱们用啥。
/*
* 结点出队
* 参数:Queue * 类型,传入队
* 返回值:Node * 类型,出队成功,返回出队结点;出对失败,返回NULL
*/
Node* Node_Dequeue(Queue* q)
{
if (Is_empty(q))//判断队列是否为空
{
printf("队列为空,出队失败!\n");
return NULL;
}
Node* p = q->front;
q->front = q->front->next;//令front指向下一个结点
if (q->front == NULL)//判断队列(front)是否为空,为空令rear指向front
q->rear = q->front;
p->next = NULL;
q->node_num--;
return p;
}
/*
* 元素出队
* 参数:Queue * 类型,传入队
* 返回值:Elemtype 类型,出队成功,返回结点的数据域d;出对失败,返回NULL
*/
Elemtype Elemt_Dequeue(Queue* q)
{
if (Is_empty(q))//判断队列是否为空
{
printf("队列为空,出队失败!\n");
return NULL;
}
Elemtype d; //存储p的数据域
Node* p = q->front;
d = p->data;
q->front= q->front->next;//令front指向下一个结点
if (q->front == NULL)//判断队列(front)是否为空,为空令rear指向front
q->rear = q->front;
p->next = NULL;//释放结点p
free(p);
q->node_num--;
return d;
}
销毁队列
就是把整个队列全部都释放掉!
可不是直接free哦!
/*
* 销毁一个队列
* 参数:Queue * 类型,传入队
* 返回值:void
*/
void Destory_queue(Queue* q)
{
if (q==NULL)//判断队列是否存在
{
printf("队列不存在,无需销毁!\n");
return;
}
//先删除结点
Node* traversal = q->front;//遍历指针
while(traversal)//一个节点一个节点销毁释放内存
{
q->front = q->front->next;
traversal->next = NULL;
free(traversal);
traversal = q->front;
q->node_num--;
}
//再删除头
q->rear = NULL;//令rear指向NULL,返回初始化状态
free(q);
}
打印队列
想看队列有啥嘛?
想知道你就得用我!
/*
* 打印队列
* 参数:Queue * 类型,传入队
* 返回值:void
*/
void printf_queue(Queue* q)
{
if (!q)//判断队列是否存在
{
printf("队列不存在,打印失败!\n");
return;
}
if (q->front==NULL)//判断队列是否为空
{
printf("队列为空,打印失败!\n");
return;
}
Node* p = q->front;
while (p)//开始打印
{
printf("%d ", p->data);
p = p->next;
}
putchar('\n');
}
好啦,看到这里的大佬们就会发现我好像没有创建队列欸。
实际上呢,队列是需要一个一个入队的。
所以我们,只需要初始化一个队头,然后再不断进行入队操作就能获得一个队列啦!
注意:由于编译器原因可能scanf为scanf_s将_s删去即可!
感谢各位的观看啦,希望对各位有所帮助,有问题一定要提出来哦!