顺序队列的循环 浪费一个空间法及标志位法

数据结构顺序循环队列。
队列:一个先进先出有队尾和队头的线性表。
如果队列为普通的顺序结构,那么在使用的过程中会导致在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就说明队列不为满 那就剩空的情况

当然方法不止这三种,欢迎留言讨论。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值