05_队列

队列

本质:线性表
原理:先进先出
队列的2种设计:

  • 顺序表设计,称为顺序队列
  • 链式设计,称为链式队列

在这里插入图片描述
在这里插入图片描述

1 顺序队列

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
设计改进:循环队列

在这里插入图片描述

线性表本身不是环,但是解决问题需要考虑成环的问题:

1.约瑟夫环
在这里插入图片描述

2.魔法阵

在这里插入图片描述

2 循环队列:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

结构定义:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

API实现
//队列:先进先出的一种线性结构,入队的一端称为队尾,出队的一端称为对头
//队列的存储方式有两种:顺序结构(顺序队列)。链式结构(链式队列)

//顺序队列一定会设计成环形队列,原因是线性队列的入队O(1),出队为O(n)
//环形队列的入队和出队都为O(1)

//判满:尾指针再走一步就到头指针;浪费一个空间不用,主要是为了区分空和满的情况

//判满改进:可以加一个计数器,统计现在队列里有多少个元素,若元素为0,头和尾相等,队列为空;若不为0,头和尾相等,队列满;

//顺序队列主要理解两点设计:1.为什么是环形;2.为什么浪费一个空间

//队满的处理方式:1.固定长度,队满则入队失败(处理简单,不实用):和书本一致
              //  2.长度不固定,队满则扩容(实现稍微复杂)


#define SIZE 10

typedef struct
{
	int* base;//指向动态内存
	int front;//对头指针,对头元素的下标
	int rear;//队尾指针,当前可以插入数据的下标(队尾后一个元素的下标)
//  int queuesize;//队列的总容量,要做到自动扩容就必须要增加这个成员
}SqQueue,*PSqQueue;



//初始化
void InitQueue(PSqQueue ps);

//判满
static bool IsFull(PSqQueue ps);


//往队列中入数据(入队操作)
bool Push(PSqQueue ps, int val);

//获取对头元素的值,但是不删除
bool GetTop(PSqQueue ps, int* rtval);//rtval:输出参数


//获取对头元素的值,且删除
bool Pop(PSqQueue ps, int* rtval);

//判空
bool IsEmpty(PSqQueue ps);

//获取队列有效数据的个数
int GetLength(PSqQueue ps);

//清空所有的数据
void Clear(PSqQueue ps);
//销毁
void Destory(PSqQueue ps);

3 链式队列

在这里插入图片描述

在这里插入图片描述
改进一:
在这里插入图片描述
改进二:

在这里插入图片描述

结构定义:
typedef struct Node
{
	ELEM_TYPE data;//数据域
	struct Node* next;//指针域
}Node, * PNode;

//我们对头结点重新设计其结构体
typedef struct Head
{
	struct Node* front;//一直指向第一个节点
	struct Node* rear;//一直指向最后一个节点
	//int length;//如果需要频繁获取队列的有效长度,可以加上length
}Head, * PHead;
API实现:
//初始化
void Init_lqueue(PHead pq)
{
	assert(pq != nullptr);
	if (NULL == pq)
		return;

	pq->front = NULL;
	pq->rear = NULL;
	//pq->front = pq->rear = NULL;
}

//入队
bool Push(PHead pq, ELEM_TYPE val)
{
	//assert pq
	//申请新节点
	Node* pnewnode = (PNode)malloc(sizeof(Node) * 1);
	assert(pnewnode != NULL);
	pnewnode->data = val;

	//找到合适的插入位置   不需要找  因为头节点保存着尾部节点的地址

	//插入  需要考虑一个问题:插入的时候里面已经有没有数据存在
	if (pq->front == NULL)//此时是一个空队列
	{
		pnewnode->next = NULL;//=pq->front =pq->rear
		pq->front = pnewnode;
		pq->rear = pnewnode;
	}
	else
	{
		pnewnode->next = pq->rear->next;// = NULL;
		pq->rear->next = pnewnode;
		pq->rear = pnewnode;
	}

	return true;
}

//出队
bool Pop(PHead pq, int* rtval)
{
	assert(pq != NULL && rtval != NULL);
	if (pq == NULL || rtval == NULL)
		return false;

	if (pq->front == NULL)
	{
		return false;
	}


	//找到删除的位置   头删  所以不需要找

	//删除 需要考虑一个问题:删除的那个节点是不是仅剩的唯一节点
	if (pq->front->next == NULL)//如果为真 仅有一个节点存在
	{
		Node* p = pq->front;
		*rtval = p->data;//通过输出参数 将值带出去
		free(p);
		p = NULL;

		pq->front = pq->rear = NULL;
	}
	else//删除的节点肯定不是仅剩的那个(里面至少有2个节点)
	{
		Node* p = pq->front;
		*rtval = p->data;//通过输出参数 将值带出去
		pq->front = p->next;
		free(p);
		p = NULL;
	}

	return true;
}

//获取队列顶部元素
bool Top(PHead pq, int* rtval)
{
	assert(pq != NULL && rtval != NULL);
	if (pq == NULL || rtval == NULL)
		return false;

	if (pq->front == NULL)//判空  
	{
		return false;
	}

	*rtval = pq->front->data;
	return true;
}

//获取其有效长度个数
int Get_length(PHead pq)
{
	//assert
	int count = 0;

	Node* p = pq->front;
	for (p; p != NULL; p = p->next)
	{
		count++;
	}

	return count;
}

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

判满   不需要判满
//bool IsFull(PHead pq);

//清空
void Clear(PHead pq)
{
	Destroy(pq);
}

//销毁 头删
void Destroy(PHead pq)
{
	while (pq->front != NULL)
	{
		Node* p = pq->front;
		pq->front = p->next;
		free(p);
		p = NULL;
	}

	pq->front = pq->rear = NULL;
}

void Show(PHead pq)
{
	//assert

	Node* p = pq->front;
	for (p; p != NULL; p = p->next)
	{
		printf("%d ", p->data);
	}

	printf("\n");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值