第三章 栈和队列(3.5.3)

3.5.3 链队-队列的链式表示和实现

链队是指采用链式存储结构实现的队列。通常链队用单链表来表示,如图所示。一个链队显然需要两个分别指示队头和队尾的指
针(分别称为头指针和尾指针)才能唯一确定。这里和线性表的单链表一样,为了操作方便起见,给链队添加一个头结点,并令头指针始终指向头结点。

img

1.队列的链式存储结构的表示

//----单链队列----队列的链式存储结构
typedef struct QNode {
	QElemType data;
	struct QNode* next;
}QNode, * QueuePtr;
typedef struct {
	QueuePtr front;//队头指针
	QueuePtr rear;//队尾指针
}LinkQueue;

2.链队操作的实现

2.1.初始化

定义:

链队的初始化操作就是构造一个只有一个头结点的空队

算法步骤:
  1. 生成新结点作为头结点,队头和队尾指针指向此结点
  2. 头结点的指针域置空
算法描述
Status InitQueue(LinkQueue &Q) 
{
	//构造一个空队列 
	Q.front = Q.rear = new QNode;  // 生成新结点作为头结点,队头和队尾指针指向此结点
	Q.front->next = NULL;   // 头结点指针域置空
	return ok;
}

2.2入队

定义:

和循环队列的入队操作不同的是,链队在入队前不需要判断队是否满,需要为入队元素动态分配一个结点空间,如图(b)和(c)所示。

算法步骤:

①为入队元素分配结点空间,用指针p指向。

②将新结点数据域置为e。

③将新结点插入到队尾

④修改队尾指针为p

算法描述:
Status EnQueue(LinkQueue &Q, int e) 
{
	//插入e为Q的新的队尾元素
	QNode *s;
	s = new QNode;
	if (!s) 
	{
		return 0;  //存储分配失败 
	}
	s->data = e;
	s->next = NULL;
	Q.rear->next = s;  // 将新节点插入到队尾
	Q.rear = s;     //修改尾指针 
	return 1;
}

3.出队

定义:

和循环队列一样,链队在出队前也需要判断队列是否为空,不同的是,链队在出队后需要释放出队头元素的所占空间,如图(d)所示。

算法步骤:

①判断队列是否为空,若空则返回 ERROR。

②临时保存队头元素的空间,以备释放。

③修改队头指针,指向下一个结点。

④判断出队元素是否为最后一个元素,若是,则将队尾指针重新赋值,指向头结点。

⑤释放原队头元素的空间。

算法描述:
int DeQueue(LinkQueue &Q, int &e) 
{
	QNode *p;
	if (Q.front == Q.rear) 
	{
		return 0;//队列为空 
	}
	p = Q.front->next;   // 指针p指向队列的第一个元素
	e = p->data;
	Q.front->next = p->next;   // 修改头结点的指针域
	if (Q.rear == p) 
	{
		Q.rear = Q.front;
	}   // 最后一个元素被删除,队尾指针指向头结点
	delete p;  // 释放原队头元素所占的空间
	return 1;
}

2.4 取队头元素

定义:

与循环队列一样,当队列非空时,此操作返回当前队头元素的值,队头指针保持不变。

算法描述:
int GetHead(LinkQueue Q)
{
	// 返回Q的队头元素, 不修改队头指针
	if (Q.front != Q.rear)   //队列非空
		return Q.front->next->data;  // 返回队头元素的值,队头指针不变
}
代码
#include <iostream>

#define MAXQSIZE 100

using namespace std;

// 定义顺序队列
typedef struct 
{
	int *base;   //分配存储空间 
	int front;  //队头指针 
	int rear;  //队尾指针 
}SqQueue;


//初始化循环队列 
int InitQueue(SqQueue &Q) 
{
	Q.base = new int[MAXQSIZE];   //分配存储空间
	if (!Q.base) 
		return 0;     // 存储空间分配失败 
	Q.front = Q.rear = 0;
	

	return 1;

}

// 求队列的长度
int QueueLength(SqQueue Q)
{
	return ((Q.rear - Q.front) + MAXQSIZE) % MAXQSIZE;
}


// 入队操作
int EnQueue(SqQueue &Q, int e) 
{
	//首先判断队列是否已满
	if ((Q.rear + 1) % MAXQSIZE == Q.front) 
	{
		return 0;
	}
	Q.base[Q.rear] = e;  // 新元素插入队尾
	Q.rear = (Q.rear + 1) % MAXQSIZE;   // 队尾指针加1
	return 1;
}

//出队操作
 int DeQueue(SqQueue &Q, int &e) 
 {
	if (Q.front == Q.rear)
	{
		return 0;
	}
	e = Q.base[Q.front];  // 保存队头元素
	Q.front = (Q.front + 1) % MAXQSIZE;  // 队头指针加1
	

	return 1;

}

// 取队头元素
int GetHead(SqQueue Q)// 返回Q的队头元素, 不修改队头指针
 {
	 if (Q.front != Q.rear)   // 队列非空
		 return Q.base[Q.front];  // 返回队头元素的值,队头指针不变
 }
	 
//遍历队列
void TraveQueue(SqQueue Q) 
{
	int len = QueueLength(Q);
	for (int i = 0; i < len; i++) 
	{
		int e;
		DeQueue(Q, e);
		printf("%d ", e);
	}
}

int main() 
{
	SqQueue Q;

	if (InitQueue(Q)) 
	{
		printf("队列初始化成功!\n");
	}
	else 
	{
		printf("队列初始化失败!\n");
	}
	printf("队列的初始长度是:%d\n", QueueLength(Q));
	 
	// 入队
	int n;
	printf("请输入队元素的个数:");
	scanf("%d", &n);
	for (int i = 0; i < n; i++) 
	{
		int e;
		printf("请输入第%d个元素的值:", i + 1);
		scanf("%d", &e);
		EnQueue(Q, e);
	}
	printf("队列的长度是:%d\n", QueueLength(Q));
	
	printf("遍历队列:");
	TraveQueue(Q);
	 
	printf("\n队头元素:%d\n", GetHead(Q));
	 
	// 出队
	for (int i = 0; i < 2; i++)
	{
		int e;
		DeQueue(Q, e);
		printf("第%d个出队元素的值:%d\n", i + 1, e);
	}
	printf("队列的长度是:%d\n", QueueLength(Q));
	
	system("pause");
	
	return 0;

}
posted @     阅读(96)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示