神奇的酒杯课程设计报告书.docx
- 文档编号:7893896
- 上传时间:2023-01-27
- 格式:DOCX
- 页数:16
- 大小:147.41KB
神奇的酒杯课程设计报告书.docx
《神奇的酒杯课程设计报告书.docx》由会员分享,可在线阅读,更多相关《神奇的酒杯课程设计报告书.docx(16页珍藏版)》请在冰豆网上搜索。
神奇的酒杯课程设计报告书
一、题目:
(神奇的酒杯)小L在一次登山游玩不小心掉到了山底下摔断了右脚,然而庆幸的是竟让他发现了一个神奇的酒杯。
小L拿过酒杯摸一摸召唤出了酒杯里的大神,他求大神解救他的右脚。
但是大神就是大神,哪能随便施法呢,大神说:
你要是能解答我一个问题,我就搭救你。
问题是这样的:
已知有一棵树根为1,树上有N个结点编号为1~N,每个结点上有一个权值,大神可以随时改变某个结点的权值,他想求的是某棵子树上结点权值的最大值。
小L是个菜鸟,只恨算法没学好啊,只好把问题交给你了。
要求:
(1)输入第一行一个正整数N(2 多组数据,N=0结束。 第二行为N个数,分别表示1~N的结点上的权值[1,100000000]接下来的N-1行,每行包含两个数u,v,表示u,v之间有一条边。 第N+2行输入为正整数M(0<=M<=100000)。 下面的M行输入为“C x y”或“Q x”。 (x为1到N的数)。 “C x y”表示将结点x的值改变成y(y>0)。 “Q x” 表示查询以x为根的子树上结点的权值的最大值。 (2)输出: 对每个查询输出相应的最大值。 (3)所设计的数据结构应尽可能节省存储空间。 (4)程序的运行时间应尽可能少。 二、问题分析: 此程序需要完成如下要求: 已知有一棵树根为1,树上有N个结点编号为1~N,每个结点上有一个权值,大神可以随时改变某个结点的权值,他想求的是某棵子树上结点权值的最大值。 实现本程序需要解决以下几个问题: 1、应该选择怎样的存储结构。 2、如何通过给定的二叉树的边信息,建立二叉树。 3、如何将结点x的权值改变成y。 4、怎样查询以x为根的子树上结点的权值的最大值。 5、怎样确定所需要的操作是改变权值还是查询权值的最大值。 输入要求: 输入第一行一个正整数N(2 多组数据,N=0结束。 第二行为N个数,分别表示1~N的结点上的权值[1,100000000]接下来的N-1行,每行包含两个数u,v,表示u,v之间有一条边。 第N+2行输入为正整数M(0<=M<=100000)。 下面的M行输入为“C x y”或“Q x”。 (x为1到N的数)。 “C x y”表示将结点x的值改变成y(y>0)。 “Q x” 表示查询以x为根的子树上结点的权值的最大值。 输出要求: 对每个查询输出相应的最大值。 三、数据结构的选择和概要设计: 数据结构的选择 根据题目要求,存储结构既要保存二叉树边所连接的两个端点,又要保存二叉树中结点的权值。 所以,在这里我选择了静态链表的存储结构。 链表结点的地址表示二叉树结点的序号,链表结点中的data域表示二叉树结点的权值。 存储结构模型如下图: 1 lchild data rchild 2 lchild data rchild . lchild data rchild n lchild data rchild 概要设计: 1、如何通过给定的二叉树的边信息,建立二叉树。 在输入时,二叉树的边的信息用这条边所连接的两个端点的序号(a,b)表示。 在建立二叉树的函数中,将结点b的地址赋值给结点a的孩子结点指针域。 2、如何将结点x的权值改变成y。 对于将结点x中的权值改变为y这个操作非常简单,可以直接将结点x中的data域赋值为y即可。 3、怎样查询以x为根的子树上结点的权值的最大值。 对于这个问题,可以采用遍历的方法,并找出最大值。 当要查询以x为根的子树上结点的权值时,将结点x的地址作为参数输入到遍历函数中,调用先序递归遍历函数。 并设置一个全局的静态变量max,用来找出子树中权值的最大值。 设max初始值为0,遍历子树中的权值。 当max小于这个结点的权值时,将max的值赋值为该结点的权值;当max不小于这个结点的权值时,不做任何操作。 4、怎样确定所需要的操作是改变权值还是查询权值的最大值。 对于这个问题,可以设置一个菜单选项。 根据输入决定将要做的操作。 程序包含的函数有: 主函数: main(); 建二叉树函数: bitree*creatree(); 改变指定结点的权值函数: bitree*change_bt(intx,inty); 查询以x为根的子树上结点的权值的最大值函数: voidpreorder(bitree*t); 程序的流程图如下: (c)(q) (t) 4、算法思想: 此程序中最主要的问题就是,如何建立二叉树和查询以x为根的子树上结点的权值的最大值。 建二叉树的算法思想: 按提示输入二叉树的结点个数,接着再按提示输入二叉树的结点权值。 此程序的核心在于,当输入边的信息时,建立二叉树。 在这,我的算法思想是,当输入的边的信息是(a,b)时,首先检查结点a的左孩子的指针域是否为空,若为空,则将a的左孩子的指针域赋值为结点b的地址。 操作如下: for(i=0;i { scanf("%d%d",&a,&b); if(bt[a-1].lchild==NULL) bt[a-1].lchild=&bt[b-1]; else bt[a-1].rchild=&bt[b-1]; } 查询以x为根的子树上结点的权值的最大值的算法思想: 对于这个问题,采用遍历的方法,并找出最大值。 当要查询以x为根的子树上结点的权值时,将结点x的地址作为参数输入到遍历函数中,调用先序递归遍历函数。 并设置一个全局的静态变量max,用来找出子树中权值的最大值。 设max初始值为0,遍历子树中的权值。 当max小于这个结点的权值时,将max的值赋值为该结点的权值;当max不小于这个结点的权值时,不做任何操作。 操作如下: t=&bt[x-1]; if(t) { if(max max=t->data; preorder(t->lchild); preorder(t->rchild); } 5、详细设计和主要代码段: 1、存储结构的确定: 根据题目要求,存储结构既要保存二叉树边所连接的两个端点,又要保存二叉树中结点的权值。 所以,在这里我选择了静态链表的存储结构。 设计如下: typedefstructnode { intdata; node*lchild,*rchild; }bitree; 2、首先需要解决的问题是如何按照题目的要求建立二叉树: 按提示输入二叉树的结点个数,接着再按提示输入二叉树的结点权值。 此程序的核心在于,当输入边的信息时,建立二叉树。 在这,我的设计是,当输入的边的信息是(a,b)时,首先检查结点a的左孩子的指针域是否为空,若为空,则将a的左孩子的指针域赋值为结点b的地址。 详细设计流程图如下: for(i=0;i {scanf("%d",&bt[i].data);} (a,b) YN 源代码如下: bitree*creatree() { inti,a,b; printf("输入二叉树的结点个数! \n"); scanf("%d",&n); printf("输入结点的权值(%d个)! \n",n); for(i=0;i { scanf("%d",&bt[i].data); bt[i].lchild=bt[i].rchild=NULL; } printf("输入二叉树边的关系(%d个)! \n",(n-1)); for(i=0;i { scanf("%d%d",&a,&b); if(bt[a-1].lchild==NULL) bt[a-1].lchild=&bt[b-1]; else bt[a-1].rchild=&bt[b-1]; } returnbt; } 3、改变指定结点的权值函数: 对于将结点x中的权值改变为y这个操作非常简单,可以直接将结点x中的data域赋值为y即可。 源代码如下: bitree*change_bt(intx,inty) { bt[x-1].data=y; returnbt; } 4、查询以x为根的子树上结点的权值的最大值函数: 对于这个问题,采用遍历的方法,并找出最大值。 当要查询以x为根的子树上结点的权值时,将结点x的地址作为参数输入到遍历函数中,调用先序递归遍历函数。 并设置一个全局的静态变量max,用来找出子树中权值的最大值。 设max初始值为0,遍历子树中的权值。 当max小于这个结点的权值时,将max的值赋值为该结点的权值;当max不小于这个结点的权值时,不做任何操作。 YN 并且递归调用函数。 源代码如下: voidpreorder(bitree*t) { if(t) { if(max max=t->data; preorder(t->lchild); preorder(t->rchild); } } 6、上机调试情况记录 1、语法错误及其修改: 出现的语法问题主要在于子函数和变量的定义,括号的配对,关键字和函数名称的书写,和一些库函数的规范使用。 这些问题均可以根据编译器的警告提示,对应的将其解决。 2、逻辑问题的修改和调整: 在递归调用preorder(bitree*t)函数时,max没有设置为静态变量。 使得程序每次递归调用时都被初始化为0,使得程序实现不了查询以x为根的子树上结点的权值的最大值的功能。 后来将max修改为全局静态变量后,程序每次递归调用函数时,max不会再次被初始化,使得程序实现了查询以x为根的子树上结点的权值的最大值功能。 3、空间性能的调整: 在preorder(bitree*t)函数中,一开始使用的是,先定义了一个全局数组Z_C[m],存储遍历时的data域的值,然后再在Z_C[m]数组中找出最大的权值。 后来考虑到这样浪费了m个int型的存储空间。 决定使用一个静态变量max。 设max初始值为0,遍历子树中的权值。 当max小于这个结点的权值时,将max的值赋值为该结点的权值;当max不小于这个结点的权值时,不做任何操作。 7、测试用例、结果及其算法性能分析 当输入的数据为: 结点数为3 权值为231645 边的信息为: 12 13 操作为: Q2 Q3 C234 Q2 当输入的数据为: 结点数为6 权值为2316456356 边的信息为: 12 23 24 45 46 操作为: Q5 Q3 C512 Q2 当输入的数据为: 结点数为3 权值为231645 边的信息为: 12 23 操作为: Q2 Q3 C234 Q2 算法性能分析: 1、时间性能: 本程序的时间性能较好。 所有函数中仅有一层for循环,没有任何嵌套循环,所以本程序的时间性能为O(n)。 2、空间性能: 解决本问题,采用的是静态链表,所以空间性能为O(n)。 除此以外,还定义了全局变量n,用来存放结点的个数;还有,定义了一个全局静态变量max。 所以此程序的空间性能还是O(n)。 八、用户使用说明 本程序在运行过程中带有提示性语句。 由于本程序需要输入的数据比较多,输入时要按照提示进行,如果输入错误,提示输入错误并不录入。 所以,在运行时,只要按照提示输入就行了。 9、参考文献 [1]王昆仑,李红.数据结构与算法.北京: 中国铁道出版社,2006年5月。 [2]李红,王昆仑."数据结构与算法"实验指导合肥: 合肥学院教务处2006年5月。 10、附录(完整源程序) #include #definem20 staticintmax=0; intn; typedefstructnode { intdata; node*lchild,*rchild; }bitree; bitreebt[m]; bitree*creatree() { inti,a,b; printf("输入二叉树的结点个数! \n"); scanf("%d",&n); printf("输入结点的权值(%d个)! \n",n); for(i=0;i { scanf("%d",&bt[i].data); bt[i].lchild=bt[i].rchild=NULL; } printf("输入二叉树边的关系(%d个)! \n",(n-1)); for(i=0;i { scanf("%d%d",&a,&b); if(bt[a-1].lchild==NULL) bt[a-1].lchild=&bt[b-1]; else bt[a-1].rchild=&bt[b-1]; } returnbt; } bitree*change_bt(intx,inty) { bt[x-1].data=y; returnbt; } voidpreorder(bitree*t) { if(t) { if(max max=t->data; preorder(t->lchild); preorder(t->rchild); } } voidmain() { inta,b,n; charch; creatree(); while (1) { printf("输入操作方式(c/q/t)! \n"); scanf("%s",&ch); if(ch=='c') { printf("请输入需要改变的结点和权值(a,b)! \n"); scanf("%d%d",&a,&b); change_bt(a,b); } if(ch=='q') { printf("输入想要查询的子树的根结点序号! \n"); scanf("%d",&n); bitree*t; t=&bt[n-1]; preorder(t); printf("最大的权值为%d\n",max); max=0; } if(ch=='t') break; } }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 神奇 酒杯 课程设计 报告书
![提示](https://static.bdocx.com/images/bang_tan.gif)