数据结构与算法课程笔记(五)

本文详细介绍了链式和顺序存储结构在队列实现中的应用,包括链式队列的链式存储结构、循环顺序队列的实现,以及栈与队列的简单应用。通过实验步骤和调试验证了队列的插入和删除操作,展示了两种结构的异同。还涉及了逆序队列算法和字符串回文检测。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、实验目的

(1) 链式存储结构的队列的特点与实现;
(2) 循环顺序存储结构的队列的特点与实现;
(3) 栈和队列的简单应用;

二、实验环境

Windows 7以上版本的操作系统, VS2010以上编程环境。

三、实验内容和步骤

本实验项目包含如下文件:
LinkQueue.h和LinkQueue.cpp分别是实现队列链式存储结构的头文件和源代码;
SqQueue.h和SqQueue.cpp分别是实现队列顺序存储结构的头文件和源代码;
LinkStack.h和LinkStack.cpp分别是实现栈链式存储结构的头文件和源代码;
SqStack.h和SqStack.cpp分别是实现栈顺序存储结构的头文件和源代码。

链式队列示意图:(下图包含头结点。课本P104页图3.20没有头结点,程序较复杂。本程序使用头结点的好处是可以在入队和出队时简化程序逻辑。)
在这里插入图片描述
验证题:(根据附件中的项目,上机验证下面各题)
根据课件目录提供的 .cpp 和 .h 文件建立项目。
1. 队列的 链式存储 结构实现。
1)在语句 EnQueue(Q1,‘a’); 处按“F9”设置断点①,按“F5”调试程序至断点处暂停(暂停序号0),然后按“F10”调试程序3次,每次程序暂停时记录数据。调试结束时按“Shift+F5”结束调试过程。
链队列队头元素位置: Q1.front->next
链队列队尾元素位置:Q1.rear
链队列队空的标志: Q1.front == Q1.rear 或 Q1.front->next == NULL

暂停序号队头元素队尾元素队列中全部元素
0
1‘a’’a’’a’
2‘a’’b’‘a’, 'b’
3‘a’’c’‘a’, ‘b’, 'c’

2)取消其它断点,在语句 DeQueue(Q1, temp); 处按“F9”设置断点②,按“F5”调试程序至断点处暂停(暂停序号0),然后按“F10”调试程序3次,每次程序暂停时记录数据。

暂停序号队头元素队尾元素队列中全部元素
0‘a’‘c’’a’, ‘b’, ‘c’
1‘b’‘c’’b’, ‘c’
2’c’‘c’’c’
3

2. 队列的 顺序存储 结构的实现(少用一个存储单元实现循环队列)。
1)取消其它断点,在语句**EnQueue(Q2,‘a’);**处按“F9”设置断点③,按“F5”调试程序至断点处暂停(暂停序号0),然后按“F10”调试程序5次,每次程序暂停时记录数据。观察第5次调试时队列中数据,分析入队EnQueue(Q2,‘e’);是否成功,并说明为什么?
循环队列队头元素位置:Q2.front
循环队列队尾元素位置: (Q2.rear - 1 + MaxSize) % MaxSize
循环队列容量: MaxSize - 1

暂停序号frontrear队列中全部元素
000
101’a’
202‘a’, 'b’
303‘a’, ‘b’, 'c’
404‘a’, ‘b’, ‘c’, 'd’
504‘a’, ‘b’, ‘c’, ‘d’

答:入队EnQueue(Q2,‘e’);失败,因为队列容量MaxSize-1为4,第4次调试时队列已满。
2)取消其它断点,在语句 DeQueue(Q2, temp); 处按“F9”设置断点④,按“F5”调试程序至断点处暂停(暂停序号0),然后按“F10”调试程序4次,每次程序暂停时记录数据。

注意:出队时,并不会在内存中清除掉实际的元素,这是顺序存储(数组)的特点。队列由 front 和 rear 指示即可。

循环队列队空的标志: Q2.front == Q2.rear

暂停序号frontrear队列中全部元素
004’a’, ‘b’, ‘c’, ‘d’
114’b’, ‘c’, ‘d’
224’c’, ‘d’
334’d’
444

3)取消其它断点,在语句 EnQueue(Q2,‘j’); 处按“F9”设置断点⑤,按“F5”调试程序至断点处暂停,然后按“F10”调试程序1次,程序暂停时记录数据。观察队列中数据,分析入队 EnQueue(Q2,‘j’); 是否成功,并说明为什么?
循环队列队满的标志:(Q2.rear + 1) % MaxSize == Q2.front

暂停序号frontrear队列中全部元素
043‘f’, ‘g’, ‘h’. ‘i’
143‘f’, ‘g’, ‘h’. ‘i’

答:入队EnQueue(Q2,‘j’);失败,因为循环队列堆满的标志成立,无法再入队。
通过上述验证过程,总结链式结构和顺序结构在入队、出队操作时的异同?
答:
相同点:
入队操作:在队尾位置进行,需要更新队尾rear;
出队操作:在对头位置进行,需要更新对头front;
不同点:
链式结构最后一个元素出队时,在更新对头指针的同时也需更新队尾指针。
顺序结构入队操作只需要更新队尾rear;出队操作只需更新对头front。

四、编程题:(根据附件中的项目,上机验证下面各题目)

阅读Content.cpp文件中的void Reverse(LinkQueue Q)函数,回答下列问题:
1. 该函数的功能是什么?利用下面的主函数替代原来文件的主函数,观察运行结果验证你的结论。//利用栈结构逆置队列

int main()
{
	LinkQueue Q;
	InitQueue(Q);
	for(int i=0; i<4; i++)		
        EnQueue(Q, 'a'+i);
	TraverseQueue(Q);
	Reverse(Q);
	TraverseQueue(Q);
	return 0;
}

答:Reverse(LinkQueue Q)函数的功能是逆置队列
运行结果如下:

在这里插入图片描述
2. 函数中两个循环的作用分别是什么?

while( !QueueEmpty(Q) )	
{
	DeQueue(Q, t);
	Push(S,t);
} //作用:将队列Q中全部的数据逐一出队,并压入栈S中
while( !StackEmpty(S) )	
{
	Pop(S, t);
	EnQueue(Q,t);
} //作用:将栈S中全部的数据逐一出栈,并入队Q中

3. 参考void Reverse(LinkQueue Q)函数,定义新的函数:
bool Palindrome_Test(char *str)
判断字符串str是否回文序列,若是则返回true,否则返回false。写出程序或用文字描述算法的执行步骤。

int main()
{
  char str[20];
  cout << "输入一个字符串:";
  cin >> str;
  if (Palindrome_Test(str))
    cout << str << "是回文" << endl;
  else
    cout << str << "不是回文" << endl;
  return 0;
}

【算法步骤】
① 将串str分别入队Q中和入栈S中
② 将Q的队头元素出队至变量t1中,将S的栈顶元素出栈至变量t2中
③ 若t1==t2,重复步骤②;若t1!=t2,则退出循环,返回false
④ 返回true

Palindrome_Test(char *str)函数定义如下:

bool Palindrome_Test(char *str)
{
	LinkStNode *S;
	InitStack(S);
	LinkQueue Q;
	InitQueue(Q);
	ElemType t1, t2;
	for (int i = 0; str[i] != '\0'; i++) {
		Push(S, str[i]);
		EnQueue(Q, str[i]);
	}
	while (!StackEmpty(S)){
		Pop(S, t2);
		DeQueue(Q, t1);
		if (t1 != t2)
			return false;
	}
	return true;
}

课后练习:
利用本课资源,实现舞伴匹配问题。
【问题描述】:
舞会上男士和女士各成一队。舞曲开始时,依次从每只队伍的队头位置各出一人匹配舞伴。若两支队伍初始人数不同时,较长队伍中未匹配者等待下一支舞曲。编写程序给出每人至少跳一支舞曲的舞伴匹配方案。
【算法分析】:
 用循环队列存储元素(队员)
 匹配成功即是出队操作
 人数少的队伍出队后还要再入队
【算法描述】:
① 创建两个队列Q1、Q2,元素类型为String;
② 两个队伍分别出队t1、t2,此时(t1,t2)匹配成功;
③ 较短队伍刚刚出队的元素要再入队;
④ 重复第2、3步,直到人数多的队伍空。
【运行效果参考】:
在这里插入图片描述
源代码如下:

#include <iostream>
using namespace std;

#define MaxSize1 4
#define MaxSize2 9

//入队函数
bool EnQueue(char Q[], char item, int front, int &rear, int MaxSize)
{
	if ((rear + 1) % MaxSize == front) {
		cout << "队满";
		return false;
	} //判队满
	Q[rear%MaxSize] = item; //新元素放尾指针位置
	rear = (rear + 1) % MaxSize; //尾指针后移
	return true;
}

//出队函数
bool DeQueue(char Q[], char &item, int &front, int rear, int MaxSize)
{
	if (rear == front) {
		cout << "队空";
		return false;
	} //判队空

	item = Q[front]; //删除队头元素
	front = (front + 1) % MaxSize; //头指针后移
	return true;
}

int main()
{
	char item1, item2;
	char Q1[MaxSize1];
	char Q2[MaxSize2];
	int front1 = 0, rear1 = MaxSize1;
	int front2 = 0, rear2 = MaxSize2;
	for (int i = 0; i < (MaxSize1 - 1); i++)
		EnQueue(Q1, 'A' + i, front1, rear1, MaxSize1);
	for (int i = 0; i < (MaxSize2 - 1); i++)
		EnQueue(Q2, 'a' + i, front2, rear2, MaxSize2);
	cout << "Q1: ";
	for (int i = 0; i < MaxSize1 - 1; i++)
		cout << Q1[i] << " ";
	cout << endl << "Q2: ";
	for (int i = 0; i < MaxSize2 - 1; i++)
		cout << Q2[i] << " ";
	cout << endl << "匹配结果:" << endl;

	for (int i = 0; front2 != rear2; i++){
		DeQueue(Q1, item1, front1, rear1, MaxSize1);
		DeQueue(Q2, item2, front2, rear2, MaxSize2);
		cout << item2 << "与" << item1 << "配对" << endl;
		if (front1 == rear1){
			front1 = 0; rear1 = MaxSize1 - 1;
		}
	}
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青云客_Hugh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值