循环队列-基础数据结构

队列:也是一种受到限制的线性表,一端进行入队,另一端进行出队,我们将入队的一端一般称作队尾,另一端称作队头。如果没有元素叫做空队。

队列的特点:先进先出(FIFO)

 顺序表实现的队列为什么叫循环队列?

关于循环队列的三个难点:(重点)

第一个难点:怎么让队列也可以实现入队和出队的时间复杂度都为 O(1)

 

   此时,入队的时间复杂度为多少?(入106) O(1)    不需要挪动元素

              出队的时间复杂度为多少?(出101) O(n)    需要挪动元素

所以,解决方案就是,删除元素的时候,记得不要去挪动数据,而是让队头指针往后挪动一步(想象成环形,数据不动,指针动)。

注意:这个循环只是一个概念,真实不存在,也就是说,这个循环是我们臆想出来的

 第二个难点:这时候在第一个问题的解决方案上,会发现一个bug:判空判满条件一致,所以有什么好方法,可以将判空判满条件区分开?

第一种:加一个计数器count(保存有效值的个数)

判空:队头指针==队尾指针 && count==0          判满:队头指针==队尾指针 && count !=0

第二种:在队尾处,浪费一个空间不用,这个浪费的空间不再存储有效值,而是当做一个标记位

判空:队头指针==队尾指针 判满:队尾指针向后再走一步,遇到了队头指针此时我们认为已经满了

注意:浪费的标记位是不固定的!如下图所示:

       

第三个难点:怎么求有效长度?

length = ( rear - front + MAX_SIZE ) % MAX_SIZE     (一定要记住这个公式!!!)

(+ MAX_SIZE是为了防止rear - front为负;% MAX_SIZE是为了防止rear - front不为负而加多了 MAX_SIZE)

接下来写代码,先写循环队列的头文件queue.h (注意:队列是不可以扩容的,所以在写之前就要申请稍微大一点的空间)

#pragma once

#define MAX_SIZE 100
//循环队列结构体设计
typedef int ELEM_TYPE;

typedef struct Queue
{
	ELEM_TYPE* base; //这个指针用来接受malloc从堆里申请的数组
	int front; //队头指针(实际上保存的是数组下标,int)
	int rear; //队尾指针(实际上保存的是数组下标,int)
}Queue, *PQueue;

//增删改查

//初始化
void Init_queue(PQueue pq);

//入队
bool Push(PQueue pq, ELEM_TYPE val);

//出队(还要获取出队的值,需要借助一个输出参数rtval)
bool Pop(PQueue pq, ELEM_TYPE* rtval);

//获取队头值
bool Top(PQueue pq, ELEM_TYPE* rtval);

//判空
bool IsEmpty(PQueue pq);

//判满
bool IsFull(PQueue pq);

//获取有效值长度
int Get_length(PQueue pq);

//查找
int Search(PQueue pq, ELEM_TYPE val);

//清空
void Clear(PQueue pq);

//销毁
void Destory(PQueue pq);

//打印
void Show(PQueue pq);

再写queue.cpp文件

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include"queue.h"

//初始化
void Init_queue(PQueue pq)
{
	//assert
	pq->base = (ELEM_TYPE*)malloc(MAX_SIZE * sizeof(ELEM_TYPE));
	assert(pq->base != NULL);
	pq->front = 0;
	pq->rear = 0;
}

//入队  
bool Push(PQueue pq, ELEM_TYPE val)
{
	//assert
	if (IsFull(pq))
	{
		return false;
	}
	pq->base[pq->rear] = val;
	pq->rear = (pq->rear + 1) % MAX_SIZE;
	return true;
}

//出队
bool Pop(PQueue pq, ELEM_TYPE* rtval)
{
	//assert   pq  trval

	*rtval = pq->base[pq->front];
	//pq->front++; //error
	pq->front = (pq->front + 1) % MAX_SIZE;

	return true;
}

//获取队头值
bool Top(PQueue pq, ELEM_TYPE* rtval)
{
	//assert   pq  trval

	*rtval = pq->base[pq->front];
	
	return true;
}

//判空
bool IsEmpty(PQueue pq)
{
	return pq->front == pq->rear;
}

//判满(队尾指针再向后走一步遇到队头,则判满)
bool IsFull(PQueue pq)
{
	//assert
	return pq->front == (pq->front + 1) % MAX_SIZE;
}

//获取有效值长度
int Get_length(PQueue pq)
{
	//assert
	return  (pq->rear - pq->front + MAX_SIZE) % MAX_SIZE;
}

//查找
int Search(PQueue pq, ELEM_TYPE val)
{
	//assert
	for (int i = pq->front; i != pq->rear; i=(i+1) % MAX_SIZE)
	{
		if (pq->base[i] == val)
		{
			return i;
		}
	}
	return -1;
}

//清空
void Clear(PQueue pq)
{
	pq->front = pq->rear ;
}

//销毁
void Destory(PQueue pq)
{
	free(pq->base);
	pq->base = NULL;
	pq->front = pq->rear = 0;
}

//打印
void Show(PQueue pq)
{
	for (int i = pq->front; i != pq->rear; i = (i + 1) % MAX_SIZE)
	{
		printf("%d ", pq->base[i]);
	}
	printf("\n");
}

在主函数中进行代码测试

#include<stdio.h>
#include <stdlib.h>
#include<assert.h>
#include<vld.h>
#include"queue.h"


//循环队列模的测试用例
int main()
{
	Queue head;
	Init_queue(&head);

	for (int i = 1; i <= 20; i++)
	{
		Push(&head, i);
	}
    Show(&head);

	ELEM_TYPE tmp;
    Pop(&head, &tmp);
	printf("Pop = %d\n", tmp);
	Show(&head);
	printf("length = %d\n", Get_length(&head));
	
	ELEM_TYPE flag;
	Top(&head, &flag);
	printf("Top = %d\n", flag);
	Show(&head);
	printf("length = %d\n", Get_length(&head));

	Clear(&head);
	Destory(&head);

	return 0;
}

测试结果如下:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值