数据结构顺序循环队列。
队列:一个先进先出有队尾和队头的线性表。
如果队列为普通的顺序结构,那么在使用的过程中会导致在front之前空间的无法利用,队列最大长度缩小。
再一个当顺序队列的空间不够时即使用relloc扩展空间但仍存在空间不能使用问题。
所以为解决这个问题,我们就要把顺序队列环成一个圆。这个圆是通过算法处理尾rear和头front 使队列空间能够循环使用。
假设队列的初长度为Bases=6;队列中排列情况是0、1、2、3、4、5;当rear=5时若队列不为满则rear=(rear+1)%Base=0;
这样就达到了,循环的目的。
虽然这样的确是解决了空间浪费问题,但是如果把队列变成这样的话队列岂不是可以无限接收队列元素,当队列为满的时候新元素的进来会覆盖先前的元素,便造成了数据丢失。
为解决这个办法,我们在插入队列元素和删除队列元素是就应该先判断队列的满空性。
我掌握的有以下三种方法。
方法一:浪费一个空间;
初始分配空间时 rear=front=0;故而有当rear=front时 队空。
进一个元素rear+1;front不变
依然沿用上面的例子 Base=5 当rear=4且front=0时表示队里有个4个元素, 此时如果允许在进一个元素就有rear=front。这样rear=front
就有两种情况。
所以当rear=4,front=0时即(rear+1)%base=front时就不允许元素再进,此时队列状态为满。此时第五个空间无队列元素为空。
这样就将满和空两种情况区别开来了。
下面是代码示例:
#include<stdio.h>
#include<malloc.h>
#include<Windows.h>
#define elemtype int
#define basespace 5 //定义队列初长度为5 排列是 0 1 2 3 4
typedef struct Queue {
elemtype *base;
int rear;
int front;
//int lenth;
}queue; //顺序队列结构体
void InitQueue(queue* q);//初始化
void DestoryQueue(queue* q);//销毁
void ClearQueue(queue* q); //清空
int JudgeQueue(queue* q);//判断
int QueueLength(queue* q);//队列长度
void InsertQueue(queue* q, elemtype e);//入队
void Gethead(queue* q, elemtype* e);//获得队头元素
void DeQueue(queue* q, elemtype* e);//出队
void PutQueue(queue* q);// 全队出击(输出)一种QueueTraverse()遍历
int main()
{
int i;
elemtype n,e;
queue Q;
InitQueue(&Q);
for (i = 0; i < basespace - 1; i++)
{
printf("please enter a date:");
scanf_s("%d", &n);
InsertQueue(&Q, n);
}
DeQueue(&Q,&e);
DeQueue(&Q, &e);
printf("front=%d,rear=%d Length=%d\n", Q.front, Q.rear, QueueLength(&Q));
for (i = 0; i < basespace - 3; i++)
{
printf("please enter a date:");
scanf_s("%d", &n);
InsertQueue(&Q, n);
}
printf("front=%d,rear=%d Length=%d\n", Q.front, Q.rear, QueueLength(&Q));
PutQueue(&Q);
printf("front=%d,rear=%d Length=%d\n", Q.front, Q.rear, QueueLength(&Q));
system("pause");
}
以下是各函数具体实现代码
void InitQueue(queue* q) //初始化
{
q->base = (elemtype*)malloc(sizeof(elemtype)*basespace);
q->rear =q->front = 0;
//q->lenth = 0;
}
void DestoryQueue(queue* q)//销毁
{
free(q->base);
}
void ClearQueue(queue* q) //清空
{
q->front = q->rear;
}
int JudgeQueue(queue* q) //判断
{
if ((q->rear + 1) % basespace == q->front)
return 1; //为满 反1
if (q->rear == q->front)
return 0; //为空 反0
}
int QueueLength(queue* q) //队列长度
{
int L;
for (L = 0;; L++)
{
if ((q->front + L) % basespace == q->rear)
break;
}
return L;
}
void InsertQueue(queue* q, elemtype e)//入队
{
if (JudgeQueue(q)==1)
printf("queue is full!");
if (q->base == NULL)
printf("queue was destroied!");
else
{
*(q->base + q->rear) = e;
q->rear = (q->rear + 1) % basespace;
}
}
void Gethead(queue* q, elemtype* e) //获得队头元素
{
if (JudgeQueue(q) == 0)
printf("queue is empty!");
else
*e = *(q->base + q->front);
}
void DeQueue(queue* q, elemtype* e)//出队
{
if (JudgeQueue(q) == 0)
printf("queue is empty!");
else
if (q->base == NULL)
printf("queue was destroied!");
else
{
*e = *(q->base + q->front);
q->front =(q->front+1)%basespace;
}
}
void PutQueue(queue* q)// 全队出击(输出)一种QueueTraverse()遍历
{
elemtype e;
while (JudgeQueue(q)!=0)
{
DeQueue(q, &e);
printf("%d-> ", e);
}
printf("\n");
}
运行结果如上图。
方法2:长度法。
该方法不会浪费空间。也很简单。就是在结构体中加一个 int length;
初始化为0 ,进一就++,出一就 减减。
满的条件为Length=basespace-1;
空的条件为Length=0;
方法3:标记法。
我看到很多的标记法,都是方法二那一类的。
我叫方法二为长度法,顾名思义嘛。
标记法更简单。
结构体
typedef struct Queue {
elemtype *base;
int rear;
int front;
int tag;
}queue; //顺序队列结构体
加个int tag;
插入元素 tag置1;
删除元素 tag置0;
判断为满的条件是
if(q->rear==q->front&&tag==1)
为空的条件是
if(q->rear==q->front&&tag==0)
很好理解的
这就跟我们设置好了算法,让队列空间可循环一样
为满为空都是rear=front
但是如何区分是空还是满?
就设置一个标识 当出现这种情况时不慌
我们看看tag的状态
如果tag为1就说明队列不为空 那就剩满的情况
如果tag为0就说明队列不为满 那就剩空的情况
当然方法不止这三种,欢迎留言讨论。