队列
1. 队列
定义: 一种 “先进先出” 的存储结构,类似于不许插队的排队。
1.1 静态队列(数组)
- 静态队列必须是循环队列;
- 如果不使用循环队列的话,使用数组每当出栈的时候都会造成空间的浪费;
- 循环队列需要两个参数来确定。
- 只需要在出队入队时使控制下标的队首队尾元素对数组长度取余,即可达到循环的效果。
1.11. 控制循环队列的结构体
循环队列主用来要需要以下几个成员变量:
- 用来标识数组的指针;
- 记录数组长度的变量;
- 用来记录队头位置的变量;
- 用来记录对位位置的变量。
具体代码如下:
typedef struct Queue
{
int *pBase;//用来控制
int len;
int front;//队首
int rear;//队尾
}QUEUE, *PQUEUE;
1.1.2 循环队列初始化
初始化即给数组分配空间,需要预先设置队列长度,代码如下:
//初始化
void init_queue(QUEUE *p,int length)
{
//由于队列尾参数指向的空间需要为空,所以数组长度需要比队列长度大一
p->pBase = (int*)malloc(sizeof(int)*(length+1));
p->len = length+1;
p->front = 0;
p->rear = 0;
return;
}
1.1.3 判断队列是否空
当队首和队尾在一起的时候,即是队为空,代码如下:
//判断队空
bool emput_queue(QUEUE *p)
{
if(p->front == p->rear)
{
printf("队空!");
return true;
}
return false;
}
1.1.4 判断队列是否满
由于循环队列队尾元素为空,所以判断队列是否满有两种方法:
- 当数组长度==队列元素个数+1时;
- 当队尾元素下一个元素是队首元素时。
下面是第二种判断的方式:
//判断队满
bool full_queue(QUEUE * p)
{
if((p->rear+1) % (p->len) ==p->front)
{
printf("队列已满\n");
return true;
}
return false;
}
1.1.5 遍历队列
遍历数组只需要从队首到队尾依次输出即可,代码如下:
//遍历队列
void show_queue(QUEUE * p)
{
int i = p->front;
while(i != p->rear)
{
printf("%d\n",p->pBase[i]);
i = (i+1) % p->len;
}
return;
}
1.1.6 入队
数组入队前需要判断是否队满,如果队为满,只需将队尾存放元素,然后队尾向后移动即可。代码如下:
//入队
bool en_queue(QUEUE * p,int val)
{
if(full_queue(p))
return false;
p->pBase[p->rear] = val;
p->rear = (p->rear+1) % (p->len);
return true;
}
1.1.7 出队
出队时只需要将队首后移即可,代码如下:
//出队
bool out_queue(QUEUE *p, int * pVal)
{
if(emput_queue(p))
return false;
*pVal = p->pBase[p->front];
p->front = (p->front+1) % p->len;
return true;
}
1.1.8 测试的main函数
int main(void)
{
QUEUE p;
init_queue(&p,5);
en_queue(&p,1);
en_queue(&p,2);
en_queue(&p,3);
en_queue(&p,4);
en_queue(&p,5);
show_queue(&p);
printf("-----------\n");
int val;
if(out_queue(&p, &val))
printf("出队元素%d\n",val);
if(out_queue(&p, &val))
printf("出队元素%d\n",val);
show_queue(&p);
printf("-----------\n");
en_queue(&p,6);
en_queue(&p,7);
show_queue(&p);
printf("-----------\n");
return 0;
}
1.2 链式队列(链表)
1.2.1 链表的结构体
链表的结构体可以根据自己的需求来写,代码如下:
//链表的结构体
typedef struct Node
{
int data;//数据域
Node * next;//指针域
}NODE, *PNODE;
1.2.2 队列的结构体
队列的结构体如下:
//队列的结构体
typedef struct Queue
{
PNODE front;//队首
PNODE rear;//队尾
}QUEUE, *PQUEUE;
1.2.3 创建节点
创建节点的代码如下:
//创建节点
PNODE create_node(void)
{
PNODE pnode = (PNODE)malloc(sizeof(NODE));
//保证链表的末尾指向NULL
pnode->next = NULL;
return pnode;
}
1.2.4 初始化
队列初始化只需要将队首指针和队尾指针指向同一个新创建好的空节点即可,代码如下:
//初始化
void init_queue(QUEUE *p)
{
p->front = create_node();
p->rear = p->front;
return;
}
1.2.5 判断队列是否为空
队首指针与队尾指针指在同处即为队空,代码如下:
//判断队空
bool emput_queue(QUEUE *p)
{
if(p->front == p->rear)
{
printf("队空!");
return true;
}
return false;
}
1.2.6 遍历队列
遍历队列与遍历链表一样:
//遍历队列
void show_queue(QUEUE * p)
{
PNODE pn = p->front;
while(pn != p->rear)
{
printf("%d\n",pn->data);
pn = pn->next;
}
return;
}
1.2.7 入队
入队有点类似于尾插法,不过是先赋值,代码如下:
//入队
void en_queue(QUEUE * p,int val)
{
p->rear->data = val;
PNODE node = create_node();
p->rear->next = node;
p->rear = node;
return;
}
1.2.8 出队
出队即是把首节点的值取出来,然后释放首节点的内存,代码如下:
//出队
bool out_queue(QUEUE *p, int * pVal)
{
if(emput_queue(p))
return false;
*pVal = p->front->data;
PNODE pn = p->front;
p->front = p->front->next;
pn->next = NULL;
free(pn);
return true;
}
1.2.9 测试的main函数
{
QUEUE p;
init_queue(&p);
en_queue(&p,1);
en_queue(&p,2);
en_queue(&p,3);
en_queue(&p,4);
en_queue(&p,5);
show_queue(&p);
printf("-----------\n");
int val;
if(out_queue(&p, &val))
printf("出队元素%d\n",val);
if(out_queue(&p, &val))
printf("出队元素%d\n",val);
show_queue(&p);
printf("-----------\n");
en_queue(&p,6);
en_queue(&p,7);
show_queue(&p);
printf("-----------\n");
return 0;
}
2. 队列的应用
所有和时间有关的操作都与队列有关。