ImageVerifierCode 换一换
格式:DOCX , 页数:49 ,大小:87.97KB ,
资源ID:28131681      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/28131681.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(算法竞赛入门经典授课教案第6章数据结构基础.docx)为本站会员(b****8)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

算法竞赛入门经典授课教案第6章数据结构基础.docx

1、算法竞赛入门经典授课教案第6章数据结构基础第6章数据结构基础【教学内容相关章节】6. 1栈和队列 6. 2链表 6. 3二叉树 6. 4图【教学目标】(1) 熟练掌握栈和队列及其实现;(2) 了解双向链表及其实现;(3) 掌握对比测试的方法:(4) 掌握随机数据生成方法:(5) 掌握完全二叉树的数组实现:(6) 了解动态内存分配和释放方法及其注意事项:(7) 掌握二叉树的链式表示法:(8) 掌握二叉树的先序、后序和中序遍历和层次遍历;(9) 掌握图的DFS及连通块计数;(10) 掌握图的BFS及最短路的输出:(11) 掌握拓扑排序算法:(12) 掌握欧拉回路算法。【教学要求】掌握栈和队列及其实

2、现;掌握对比测试的方法:掌握随机数据生成方法;掌握完全二叉 树的数组实现和链式表示法:掌握二叉树的先序.后序和中序遍历和层次遍历;掌握图的 DFS和BFS遍历:掌握拓扑排序算法:掌握欧拉回路算法。【教学内容提要】本章介绍基础数据结构,包括线性表、二叉树和图。有两种特殊的线性表:栈和队列。 对于树型结构主要讨论二叉树,还有二叉树的先序、中序和后序的遍历方式。对于图主要讨 论图的DFS和BFS的遍历方法。这些内容是很多高级内容的基础。如果数据基础没有打好, 很难设计正确、髙效的算法。【教学垂点、难点】教学重点:(1) 掌屋栈和队列及其实现:(2) 掌握对比测试的方法:(3) 掌握随机数据生成方法:

3、(4) 掌握完全二叉树的数组实现和链式表示法:(5) 掌握二叉树的先序.后序和中序遍历和层次遍历:(6) 掌握图的DFS和BFS遍历:(7) 掌握拓扑排序算法和欧拉回路算法。教学难点:(1) 掌握完全二叉树的数组实现和链式表示法:(2) 掌握二叉树的先序.后序和中序遍历和层次遍历:(3) 掌握图的DFS和BFS遍历:(4) 掌握拓扑排序算法和欧拉回路算法。【课时安排(共9学时)】6. 1栈和队列 6. 2链表 6. 3二叉树 6. 4图(1学时)6.1栈和队列线性表是“所有元素排成一行”的数拯结构。除了第一个元素之外,所有元素都有一个 “前一个元素S除了最后一个元素外,所有元素都有“后一个元素

4、化线性结构是重要的算法和数据结构的基础。下而介绍两种特姝的线性表:栈和队列。6.1.1卡片游戏桌上有叠牌,从第一张牌(即位于顶而的牌)开始从上往下依次编号为1n。当至少 还剩两张牌时进行以下操作:把第一张牌扔掉,然后把新的第一张放一整叠牌的最后。输入 m输出每次扔掉的牌,以及最后剩下的牌匚样例输入:7样例输出:1 3 5 7 4 2 6【分析】本题中牌像在排队。每次从排头拿到两个,其中第二个再次排到尾部。这种数据结构称 为队列。在数据结构称为FIFO (First in First out,先进先出)表。用一个数组queue来实现这个队列,可设两个指针front和rear0完整的程序如下:in

5、clude const int MAXN = 50;int queueMAXN;int mainO int n, front, rear;scanf (W &n);for(int i = 0; i n; i+) queuei = i+1; /初始化队列front 二 0;/队首元素的位置rear = n;/队尾元素的后一个位置while(front rear) 当队列非空printf (?,%d 、queueLfront+);/输出并抛弃队首元素queue rear+ = queuefront+;/队首元素转移到队尾return 0;注意:上而的程序有bug。如果在最后把rear的值打印出来,

6、rear比n大。即在程序 运行的后期,queuerear+ =queuefront+读写了非法内存。也可以采取将数组空间开大 些,或采取一种称为循环队列的技术,重用已出队元素占用的空间。C+提供了一种更加简单的处理方式一一STL队列。下面是代码:include frinclude using namespace std;queue q;int mainO int n, front, rear;q. push(i+l) ; /初始化队列当队列非空/打印队首元素/抛弃队首元素/把队首元素加入队尾/抛弃队首元素scanf f &n);for(int i = 0; i n; i+) while(!q.

7、 empty () printf (?,%d , q. front (); q pop 0 ;q. push(q. front ();Q- Pop 0 ;return 0;上而的程序的可读性大大增强了,体现在“queue: front见名知义的命名,使用了 C+ STL。除此之外,上而的代码还有两个附加的好处。首先,不需要事先知道n的大小: 其次,可以少用两个变front和rear0减少魔术数(magic number)和变量个数都是提 高代码可读性.减少错误可能性的重要手段。说明:(1)任ACH竞赛中,需要用到数组.字符串.队列.堆栈、链表、平衡二叉检索 树等数据结构和排序、搜索等算法,以提

8、髙程序的时间、空间运行效率,这些数据结构,如 果需要手工来编写,那是相当麻烦的事情。(2)ANSI C+中包含了一个 C+ STL (Standard Template Library) 即 C卄标准模板 库,又称为C卄泛型库,它在std命名空间中左义了常用的数据结构和算法,使用起来十分 方便。(3)C+ STL 组件STL组件三种类型的组件:容器、迭代器和算法,它们都支持泛型程序设计标准。容器主要有两类:顺序容器和关联容器。顺序容器(vector, list, queue, string等) 一系列元素的有序集合关联容器(set、multisets map和mulimap)包含査找元素的键值

9、。迭代器的作用是遍历容器。STL算法库包含四类算法:排序算法.不可变序算法、变序性算法和数值算法。(4)queue队列容器queue队列容器是一个先进先岀(First In First Out, FIFO)线性存储表,元素的插 入只能在队尾、元素的删除只能在队首。使用queue需要声明头文件包含语句“#include queue文件在C: Program FilesMicrosoft Visual StudioVC98Include 文件夹里。queue队列的操作有入队pushO (即插入元素)、岀队pop()(即删除元素)、读取队首 元素front 0 .读取队尾元素backO.判断队列是否

10、为空empty 0和队列当前元素的数目 sizeO o下而给出一个程序来说明queue队列的使用方法。include include using namespace std;int mainO 定义队列,元素类型是整型queue q;/入队,即插入元素q. push(l);q. push (2);q. push (3);q. push (9);返回队列元素数咼coutq size () endl;队列是否为空,是空,则返回逻辑真,否则返回逻辑假 coutq. empty () endl;/读取队首元素coutq. front 0 endl;/读取队尾元素coutq. back () endl;

11、/所有元素出列(删除所有元素)while (q. empty () !=true) coutq front 0 ;/队首元素出队(删除队首元素)Q- Pop 0 ;/回车换行coutendl;return 0;运行结果:401912 3 96.1.2铁轨某城市有一个火车站,铁轨铺设如图6-1所示。有n打车厢从A方向驶入车站,按进站 顺序编号为1你的任务是让它们按照某种特左的顺序进入B方向的铁轨并驶出车站。 为了重组车厢,你可以借助中转站C。这是一个可以停放任意多节车厢的车站,但由于末端 封顶,驶入C的车厢必须按照相反的顺序驶岀C。对于每个车厢,一旦从A移入C,就不能 再回到AT: 一旦从C移入

12、B,就不能回到CTo换句话说,在任意时刻,只有两种选择: A-C 和 C-Bc样例输入:512 3 4 5554 12 366 5 4 3 2 1样例输岀:YesNoYes【分析】在中转站C中,车厢符合后进先出的原则,称为栈,即LIFO (Last In First Out)表。 由于它只有一端生成,实现栈时只需要一个数组stack和栈顶指针(始终指向栈顶元素)。完整的程序如T*:Sinclude const int MAXN = 1000 + 10;int n, targetMAXN;int mainO while(scanf(”d, &n) = 1) int stackMAXN, top

13、= 0;int A = 1, B = 1;for(int i = 1; i = n; i+)scanf f &target i);int ok = 1;while(B = n) if(A = targetB) A+; B+; else if(top & stacktop = targetEB) top-; B+; else if(A = n) stack+top = A+;else ok = 0; break; printf(%sn, ok ? Yes : No);return 0;说明:为了方便起见,使用的数组下标均从1开始。例如,target1是指目标序列中 第一个车厢的编号,而stack

14、El是栈底元素(这样,栈空当且仅当top二0)。下而给出STL栈来实现的程序:include include using namespace std;const int MAXN = 1000 + 10;int n, targetMAXN;int mainO while(scanf(z,%d,/, &n) = 1) stack s;int A = 1, B = 1;for (int i = 1; i = n; i+) scanf&targeti);int ok = 1;while(B = n) 辻(A = target LB) A+; B+; else if (!s empty() &s. t

15、op 0=targetB)s pop 0 ;B+; else i.f(A = n) s; push (A+);else ok = 0; break; printf(”sn, ok ? Yes : No);return 0;说明:(1) stack栈容器是一种C+ STL中的容器,它是一个后进先出(Last InFirst Out, LIFO)的线性表,插入和删除元素都只能在表的一端进行。插入元素的一端称为栈顶 (Stack Top),而另一端称为栈底(Stack Bottom)插入元素称为入栈(Push),元素的删 除则称为出栈(Pop)o(2)要使用stack,必须声明头文件包含语句“#in

16、cludestack。stack文件在C: Program F订esMicrosoft Visual StudioVC98Include 文件夹中。(3)栈只提供入栈、出栈、栈顶元素访问和判断是否为空等几种方法。釆用pushO方 法将元素入栈:采用pop()方法出栈:釆用top()方法访问栈顶元素;采用empty0方法判 断栈是否为空,如果为空,则返回逻辑真,否则返回逻假。当然,可以采用sizeO方法返 回当前栈中有几个元素。下而的程序是对栈各种方法的示例:include include using namespace std;int mainO /立义栈s,其元素类型是整型stack s;/

17、元素入栈,即插入元素s. push(l);s. push (2);s. push (3);s. push (9);/读取栈顶元素couts top 0 endl;/返回栈元素数量couts size () endl;判断栈是否为空couts empty () endl;/所有元素出栈(删除所有元素)while(s. empty 0 !=true) /栈非空COUtS. top () V ” ; /读取栈顶元素s. pop(); /出栈(即删除栈顶元素)/回车换行coutendl;return 0;运行结果:94099 3 2 16.2链 表在多数情况下,线性表都用它的顺序存储结构一一数组很轻松

18、实现,但对有些问题有时 用它的链式存储结构一一链表更好。6. 2.1初步分析例6-1移动小球。你有一些小球,从左到右依次编号为1,2, 3,-sn,如图6-2所示。图6-2链表的初始状态可以执行两种指令。其中,A X Y表法把小球X移动到小球Y左边,B X Y表示把小球 X移动到小球Y右边。指令保证合法,即X不等于人例如,在初始状态下执行A 1 4后,小球被移动小球4的左边,如图6-3所示。图6-3 次操作后的链表状态如果再执行B 3 5,结点3将会移到5的右边,如图6-4的所示。图6-4两次操作后的链表状态输入小球个数m指令条数m和n条指令,从左到右输出最后的序列。注意,n可能髙 达5000

19、00,而m可能高达100000.样例输入:6 2A 1 4B 3 5样例输出:21 4 5 3 6【分析】各个小球在逻辑上是相邻的,因此可考虑把它们放在一个数组A中,所以完整的程序如 下:include const int MAXN = 1000;int n, AMAXN;int find(int X) for(int i = 1; i = n; i+)辻(Ai = X) return i;return 0;void shift_circular_left(int a, int b) int t = Aa;for(int i = a; i a; i) Ai二 Ai-1;Aa = t;int m

20、ainO int m, X, Y, p, q;char type9;scanf (,z%d%d/z, &n, &m);for (int i = 1; i = n; i+) /初始化数组Ai = i;for(int i = 0; i P)shift_circular_left (p, qT) ; /Ap到 AqT往左循环移动else shift_circular_right (q, p); /Aq到 Ap往右循环移动 else if (q p) shift_circular_left (p, q) ; /Ap到 Aq往左循环移动else sh辻t_circular_right (q+1, p)

21、; /Aq+1到 Ap往右循环移动for(int i=l; i = n; i+)printf (z,%d 、Ai);printf (,zn/z);return 0;对于上而的程序,当数据量很大时.代码是否会超时。一般来说,可以用两种方法判断: 测试和分析。讣时测试的方法在前而已讲过,它的优点是原理简单、可操作性强,缺点在于必须事先 程序写好一一包括主程序和测试数据生成器如果算法非常复杂,这是相当花时间的。另一种方法是写程序之前进行算法分析,估算时间效率,这种方法在第8章会详细分析。 不过现在可以直观分析一下:如果反复执行B 1 n和A 1 2,每次都移动几乎所有元素。元 素个数和指令条数都那么

22、大,移动总次数将是相当可观的。6. 2.2链式结构第二种方法是强调小球之间的相对顺序,而非绝对顺序。用lefti和righti分别表 示编号为i的小球左边和右边的小球编号(如果是0,表示不存在),则在移动过程中可以 分成两个步骤:把X移岀序列:把X重新插入序列。第一步让1 eft X rightX相互连接即可,如图6-5所示。注意,其他所有的left和right都不会变化。图6-5在链表中删除结点第二步类似。对于A指令,需要修改leftY的right值和Y的left值,如图6-6所图6-6在链表中插入结点(情况A)而对于B指令,需要修改Y的right值和right Y的left的值,如图6-7

23、所示。图6-7在链表中插入结点(情况B)不管在哪种情况下,最后都需要修改X自己的left和righto对于特殊情况下,对于 最左的小球X,它的leftEX的值为0,但可以假想最左的小球左边有一个编号为0的虚拟 的小球。那么对最右的小球的右边的虚拟小球编号为n+1。核心的代码如下:scanfC%s%d%d, type, &X, &Y);link(leftEX, rightX);if (type 01 = A) linkdeftEY, X); /这一行和下一行不能搞反link(X, Y);else link(X, right Y) ; /这一行和下一行不能搞反link(Y, X);函数link(X

24、, Y)的作用是赋值right X二Y,然后leftY=Xo完整的程序如下:include const int MAXN = 1000;int n, leftMAXN, rightMAXN;void link(int X, int Y) rightX = Y; leftY = X;int mainO int m, X, Y;char type9;scanf (z/%d%dz &n, &m);for(int i = 1; i = n; i卄)leftti二 i-1; righti二 i+1;for(int i = 0; i m; i+) scanf C%s%d%d, &type, &X, &Y)

25、;1ink(leftX, rightX);if (type 0二二A) link(leftY, X); /这一行和下一行不能搞反link(X, Y);else link(X, right Y) ; /这一行和下一行不能搞反link(Y, X);for(int X = right0; X != n+1; X = rightX)printf (z,%d , X);printf (,zn/z);return 0;6. 2.3对比测试对于写好的程序,可能会花费较长的时间进行调试,所以要具备一上的调试和测试能力。 测试的任务就是检查一份代码是否正确匚如果找到了错误,最好还能提供一个让它错误 的数据。有了

26、错误数据之后,接下来的任务便是调试:找出岀错的原因。如果找到了错,最 好把它改对一一至少对于刚才的错误数拯能得到正确的结果。改对一组数据之后,可能还有其他错误,因此需要进一步测试:即使以前曾经正确的数 据,也可能因为多次改动之后反而变错了,需要再次调试。总之,在编码结朿后,为确保程 序的正确性,测试和调试往往要交替进行。确保代码正确的方法是:再找一份完成同样功能的代码与之对比,用它来和这个新程序 “对答案”(俗称对拍)。对比测试首先需要数据,而且是大虽:数据。为此,需要编写数据生成器,完整的代码如 下:include include /randO 和 stand ()需要include /ti

27、me 0 需要int n = 100, m = 100000;double random() 生成0, 1之间的均匀随机数return (double)randO / RAND_MAX;int random(int m) /生成0, mT之间的均匀随机数return (int)(random0 * (m-1) + 0 5);int mainO srand(time(NULL); /利用系统时间,初始化随机数种子printf(,z%d %dn,z, n, m);for(int i = 0; i m; i+) if (randO % 2 = 0) printf (A); else printf (

28、B) ; /随机指令种类int X, Y;for(;) X = random (n)+l ;Y = random(n)+l;if(X != Y) break; /只有X和Y不相等时才是合法的printfC %d %dn, X, Y);return 0;核心函数是stdlib. h中的randO ,它生成一个闭区间0, RAND_MAX的均匀随机整数(均 匀的含义是:该区间内每个整数被产生的概率相同),其中RAND_MAX至少为32767 (215-1), 在不同的环境下的值可能不同。严格地说,这个随机数是“伪随机数笃因为它也是由数学 公式计算出来的。6. 2.4随机数发生器上而的程序使用了 randO函数和s

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1