顺序队列----数据结构

队列的概念

队列,符合先进先出特点的一种数据结构,是一种特殊的线性表,但它不像线性表一样可以任意插入和删除操作,而是只允许在表的一端插入,也就是在队列的尾部进行插入;只允许在表的另一端进行删除,也就是在队列的头部进行删除。

以下的实现是顺序队列(存储空间在内存上是连续的队列)

队列的实现

队列的结构定义

复制代码
#define MAX_SIZE 20            //队列的最大容量
typedef int DateElem;   

typedef struct _Queue
{
	DateElem date[MAX_SIZE];
	int head;				//头指针
	int tail;				//尾指针
}squeue;

队列的初始化

复制代码
void InitQueue(squeue* sq)
{
	if (!sq) return;
	sq->head = 0;
	sq->tail = 0;
}

销毁(清空)队列

和队列的初始化有点类似哈哈。

复制代码
bool DestoryQueue(squeue* sq)
{
	if (!sq) return false;

	sq->head = 0;
	sq->tail = 0;
	return true;
}

判满

复制代码
bool IsFull(squeue* sq)
{
	if(!sq) return false;    //防御性编程

	if (sq->tail >= MAX_SIZE ) //每入队一个元素,sq->tail++,入队了MAX_SIZE个元素刚好sq->tail等于MAX_SIZE
	{
		return true;
	}
	else
	{
		return false;
	}
}

判空

可以从 队列的初始状态(空队列)入队后再出队中找到判空的条件。

复制代码
bool IsEmpty(squeue* sq)
{
	if (!sq) return false;

	if (sq->head == sq->tail) //两个指针之间没有元素
	{
		return true;
	}
	else
	{
		return false;
	}
}

入队

复制代码
bool EnterQueue(squeue* sq, DateElem e)
{
	if (IsFull(sq))
	{
		cout << "无法插入元素"<<e<<",队列已满。" << endl;
		return false;
	}

	sq->date[sq->tail ] = e;  //尾部插入
	sq->tail++;               //尾指针指向下一块未被使用区域 
	return true;
}

出队

出队的方式有两种,一种是乾坤大挪移,每出队一个元素都要将后面所有的元素往前挪,十分浪费时间。另一种是舍弃空间来达到快速出队元素。

第一种

复制代码
bool PopQueue(squeue* sq, DateElem* date)
{
	if (!sq || IsEmpty(sq)) return false;

	*date = sq->date[sq->head];         //返回出队的元素
	for (int i = sq->head + 1; i < sq->tail; i++)
	{
		sq->date[i - 1] = sq->date[i]; //从第二个结点开始,将第二个结点赋值给第一个结点......
	}
	sq->tail--;    //别忘记
	return true;
}

第二种

复制代码
bool PopQueue2(squeue* sq,DateElem *date)
{
	if (!sq || IsEmpty(sq)) return false;

	//不是无限制的出队
	if (sq->head >= MAX_SIZE) return false;

	*date = sq->date[sq->head];
	sq->head++;
	return true;
}

本来头指针一直指向下标为 0 的地方,但是这种出队方式会导致头指针一直向后移动,出现"假溢出",明明队列还有空间存储,可是却无法插入元素了。如下图:

造成了空间的浪费,不过在比赛时为了通过题目,这点空间浪费无所谓,使用顺序队列非常容易构建。

打印队列

和链表的打印一样。

复制代码
bool PrintQueue(squeue* sq)
{
	if (!sq) return false;

	for (int i = sq->head; i < sq->tail; i++)
	{
		printf("%d ", sq->date[i]);
	}
	return true;
}

获取队首元素

复制代码
int GetHeadElem(squeue* sq)
{
	if (!sq || IsEmpty(sq)) return 0; //指针存在 或者 队列不为空
	
	return sq->date[sq->head];        //在队头不出队的清况下,返回队首元素
}

获取队列长度

复制代码
int GetLength(squeue* sq)
{
	if (!sq) return 0;

	return sq->tail - sq->head; //最开始为空队列sq->tail - sq->head 为 0 ,依次类推得到长度
}

主函数

我已经写好了测试的方法,可以尽情调试看看代码的正确性。

复制代码
int main(void)
{
	squeue* sq = new squeue;
	DateElem* s = new DateElem;
	InitQueue(sq);
	DateElem e = 0;

	int choose = -1;
	while (choose != 0)
	{
		cout << "1.入队" << endl
			<< "2.出队" << endl
			<< "3.打印队列" << endl
			<< "4.获取队首元素" << endl
			<< "5.获取队列长度" << endl
			<< "6.销毁队列" << endl
			<< "0.退出" << endl;
		cin >> choose;

		switch (choose)
		{
		case 1:
			cout << "请输入要入队的元素:";
			cin >> e;
			if (EnterQueue(sq, e))
			{
				cout << "入队成功" << endl;
			}
			else
			{
				cout << "入队失败" << endl;
			}
			break;
		case 2:
			if (PopQueue(sq, s))
			{
				cout << "出队的元素是:" << *s << endl;
			}
			else
			{
				cout << "出队失败" << endl;
			}
			break;
		case 3:
			cout << "队列中的元素是:";
			PrintQueue(sq);
			cout << endl;
			break;
		case 4:
			cout << "队首元素是:" << GetHeadElem(sq) << endl;
			break;
		case 5:
			cout << "队列的长度是:" << GetLength(sq) << endl;
			break;
		case 6:
			if (DestoryQueue(sq))
			{
				cout << "队列已销毁" << endl;
			}
			else
			{
				cout << "队列不存在" << endl;
			}
			break;
		case 0:
			cout << "退出成功" << endl;
			break;
		default:
			cout << "输入非法" << endl;
			break;

		}
	}


	return 0;
}

好了再见!

相关推荐
想放学的刺客7 小时前
整理了120道单片机嵌入式面试题与答案,覆盖了硬件电路和C语言等核心领域。
c语言·c++·stm32·单片机·嵌入式硬件·mcu·51单片机
舟舟亢亢7 小时前
算法总结——二叉树【hot100】(上)
java·开发语言·算法
weixin_477271699 小时前
根象:树根。基石。基于马王堆帛书《周易》原文及甲骨文还原周朝生活活动现象(《函谷门》原创)
算法·图搜索算法
普通网友9 小时前
多协议网络库设计
开发语言·c++·算法
努力努力再努力wz9 小时前
【Linux网络系列】:TCP 的秩序与策略:揭秘传输层如何从不可靠的网络中构建绝对可靠的通信信道
java·linux·开发语言·数据结构·c++·python·算法
汉克老师9 小时前
GESP2024年3月认证C++二级( 第二部分判断题(1-10))
c++·循环结构·分支结构·gesp二级·gesp2级
daxi1509 小时前
C语言从入门到进阶——第9讲:函数递归
c语言·开发语言·c++·算法·蓝桥杯
持续学习的程序员+110 小时前
强化学习Q-chunking算法
算法
Polaris北10 小时前
第二十七天打卡
开发语言·c++·算法
风吹乱了我的头发~11 小时前
Day30:2026年2月20日打卡
算法