




已阅读5页,还剩18页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
数据结构课程设计报告 班 级 计科三班 学 号 191123 姓 名 指导老师 郭 艳 日 期 2014年6月19日计算命题演算公式的真值1、 需求分析 所谓命题演算公式是指由逻辑变量(其值为TRUE 或FALSE)和逻辑运算符(AND)、(OR)和(NOT)按一定规则所组成的公式(蕴含之类的运算可以用、和来表示)。公式运算的先后顺序为、,而括号()可以改变优先次序。已知一个命题演算公式及各变量的值,要求设计一个程序来计算公式的真值。要求:(1)利用二叉树来计算公式的真值。首先利用堆栈将中缀形式的公式变为后缀形式;然后根据后缀形式,从叶结点开始构造相应的二叉树;最后按后序遍历该树,求各子树之值,即每到达一个结点,其子树之值已经计算出来,当到达根结点时,求得的值就是公式之真值。(2)逻辑变元的标识符不限于单字母,而可以是任意长的字母数字串。(3)根据用户的要求显示表达式的真值表。2、 设计1、 设计思想 (1) 数据结构设计 (1) 线性堆栈1的数据结构定义 typedef char DataType ; typedef struct DataType stackMaxStackSize; int top; SeqStack1; 用线性堆栈主要是用来存储输入的字符,它的作用就是将中缀表达式变成后缀表达式。 (2) 线性堆栈2的数据结构定义 typedef struct snode DataType data; Struct snode *next; LSNode; 用于检测表达式的括号匹配。 (3) 定义二叉树的结点BiTreeNode typedef struct Node DataType dataMaxStackSize; struct Node *leftChild; struct Node *rightChild; struct Node *parent; BiTreeNode; (3)算法设计 首先实现将中缀表达式变成后缀表达式: 在将中缀表达式变成后缀表达式的时候会用到堆栈,因此首先需要初始化一个堆栈。又由于逻辑变元可能是字符也可能是字符串,所以它又不同于将单字符的逻辑变元的中缀表达式变成后缀表达式。我的设计是这样的,我将中缀表达式变成后缀表达式的过程分成了两部:化简(将一维的复杂的中缀表达式变成一维的简单的中缀表达式,并将字符串逻辑变元存放在二维数组中),转化(将化简后的中缀表达式变成后缀表达式)。 然后用后缀表达式构造出二叉树:在这个过程中,我用到了之前所定义的存放树的堆栈。具体实现为:扫描后缀表达式,如果遇到逻辑变元然后将这个变元变成一个树节点,它的实现就是将该逻辑变元赋给树的data域,然后将它的左右子树赋为NULL,然后将这个树节点压入相应的堆栈;接着继续扫描,如果遇到的是单目运算符(非号“!”)也将它构造成一个树节点然后从堆栈里面弹出一个树形节点,将弹出的元素的作为它的左子树,右子树设置为NULL,然后将这个树节点压入相应的堆栈;如果扫描到的是双目运算符(与号“&”或者或号“|”)将它也构造成一棵树,然后将这个树节点压入相应的堆栈,然后从栈中弹出两个元素,一个作为它的左子树,一个作为它的右子树,如此重复n(n为后缀表达式的长度)次。 最后打印真值表: 打印真值表也用到了前面的简单的后缀表达式,其实现的基本思想为和构造二叉树差不多,它实现了每到一个根节点就计算一个运算的值。在打印之前需要统计字符的个数,有m个字符则要打印2m行,因为他有这么多情况。具体实现为:用一个字符型的数组来存放每个元素的一次取值,然后扫描后缀表达式,如果遇到逻辑变元就通过这个标识将相应的取值赋给它,然后它压入堆栈;接着继续扫描,如果遇到的是单目运算符(非号“!”)则从堆栈里面弹出一个元素,并对它进行非运算,然后又将这个运算后的值压入堆栈;如果扫描到的是双目运算符(与号“&”或者或号“|”)则从栈中弹出两个元素,并对这两个元素进行相应的运算,然后将这个运算后的值压入堆栈,如此重复n(n为后缀表达式的长度)次。2、 设计表示, 函数调用关系及函数说明: main() Maketree()Print()InToPost()change()StackPush1()StackPop1StackTop()StackPop()StackPush()Precede()StackPop()StackPush() change()函数原型为: void change(char prefixStr1,char prefixStr,int length,char store10,int* row,int* k )该函数含有有六个参数,其中 prefixStr1为用户输入的中缀表达式,prefixStr为即将转化成为的简单中缀表达式,length为二维数组中存放的各个字符串的的长度store10用来存放中缀表达式中的逻辑变元,row就是逻辑变元的个数,k简化后的中缀表达式的长度。该函数的功能就是将复杂的中缀表达式变成简单的中缀表达式。 InToPost()函数原型为:void InToPost(char prefixStr,char postfixStr,SeqStack* myStack,int* n,int k)该函数函数有五个参数 prefixStr为中缀表达式,postfixStr为简化后的后缀表达式,myStack为在转化过程中用到的堆栈,n为后缀表达式的字符长度,k为中缀表达式的字符长度。该函数的功能就是将简单的中缀表达式变成简单的后缀表达式。 Maketree()函数原型为: void Maketree(BiTreeNode *root,TreeStack* myTree,char postfixStr,int n)该函数共有四个参数,其中root为所建立的树的根节点,myTree是在构造树时所用到的堆栈,另外两个参数和前面的同名参数具有相同意义。这个函数的功能就是将简单的中缀表达式变成简单的后缀表达式。 Precede()函数原型为: DataType Precede(DataType x1,DataType x2)该函数有两个参数,返回值类型为DataType型,其中x1和x2就是要进行优先级比较的两个两个字符。x1为栈顶元素,x2为扫描到的元素。该函数的功能就是比较x1和x2的优先级并将比较结果返回给调用函数。 Print()函数原型为:void Print(char postfixStr,char store10,int length,int row,int n,SeqStack* myStack)该函数有六个参数,其中myStack是在输出真值表过程中要用到的堆栈,其余的参数和前面介绍的函数中的同名参数具有相同的意义。该函数的功能就是打印真值表。 函数接口说明:函数的调用关系在上面的图中已经显示出来了,整个程序就是由一些子函数的集合,他们之间按所要实现的功能不同而调用不同的函数。在这些函数中除主函数外,其它函数的级别相同。3、 详细设计(1) ,定义所需要的结构体,前面已经介绍了;(2),将中缀表达式变成后缀表达式的过程分成了两部:化简(将一维的复杂的中缀表达式变成一维的简单的中缀表达式,并将字符串逻辑变元存放在二维数组中),转化(将化简后的中缀表达式变成后缀表达式)。其中化简部分将要用伪代码描述为while(prefixStr1m!=#)扫描中缀表达式while(prefixStr1m不为运算符)继续扫描,直到扫描到运算符;扫描到运算符后 构造简化的中缀表达式; 得到这个字符串的长度; 将这个字符串存放在store10中; 转化部分用伪代码描述为: 循环扫描中缀表达式 if(扫描到逻辑变元) 保存到后缀表达式中;elseStackTop(myStack,&x);res=Precede(x,扫描到的运算符);if(res=) x退栈;if(res=leftChild=x1; (4),打印二叉树,其基本思想就是每到一个根节点就计算一个值,如此重复,直到总根节点,用伪代码简单描述为: 循环赋值if(扫描到逻辑变元) 赋值进栈;elseif(扫描到双目运算符) 从栈中弹出两数对两数进行相应的运算;将运算结构进栈;;else 从栈中弹出两数; 对两数进行非运算; 将运算结构进栈; 每循环一次输出一个结构; 3、 调试分析 调试过程中遇到的问题与解决方案:首先就是中缀表达式中的逻辑变元不是单个字符而是一些字符串,这样在将中缀表达式转化成后缀表达式的时候就会比较麻烦,后来经过一番分析与调试后,用二维数组存放比较好,那样实现起来就会比较简单。然后再就是构造树,在构造树时要用到堆栈,但是前面用到的堆栈的数据类型和此时用到的又有很大的差别,在此时又要想到再换一个类型的堆栈,同时在构造树的时候有要找到合适的算法。最后就是真值表的打印,对这一模块的实现最容易想到的就是有几个逻辑变元就进行几次循环,每一重循环对应着一个变量的取值。但是经过分析这显然是行不通的,因为在事先我们并不知道会有多少个变元。最后我用到的方法就是那种最原始的方法,用一重循环去实现,每重循环都会有一个值,将这个值反复进行对2取余和对2进行整除,将取余后的值赋给相应的变元。这样总共循环2的变元素的n次方次即可。4、 用户手册 本程序经过编译,运行时只需要用户输入一个中缀表达式,也即用户想要进行的逻辑运算的表达式。 1,在输入表达式时“&”表示逻辑与;“|”号表示逻辑或,“”表示逻辑非。在输入中缀表达式后程序将自动执行并输出结构,用户不需进行干预; 2,用户在输入完所要进行运算的表达式后要记得以“#”号结尾,“#”号是判断输入结束的标识,如果用户没有以“#”号结束,那么程序的运行结果将会出错,这时用户必须重新对程序进行编译连接,然后按照要求输入表达式。5、 测试数据及结果测试数据为(以#为结尾): (a&b)|c&d #中缀表达式化为后缀表达式:ab&cd&|构造的二叉树结构为: -d -& -c -| -b -& -a - 其真值表为:a b c d (a&b)|c&d0 0 0 0 00 0 0 1 10 0 1 0 00 0 1 1 10 1 0 0 00 1 0 1 10 1 1 0 00 1 1 1 11 0 0 0 01 0 0 1 11 0 1 0 01 0 1 1 11 1 0 0 01 1 0 1 01 1 1 0 01 1 1 1 1 全国交通咨询模拟系统1 需求分析 出于不同目的的旅客对交通工具有不同的要求。例如,因公出差的旅客希望在旅途中的时间尽可能短,出门旅游的游客则期望旅费尽可能省,而老年旅客则要求中转次数最少。编制一个全国城市间的交通咨询程序,为旅客提供两种或三种最优决策的交通咨询。 要求:(1)提供对城市信息进行编辑(如添加或删除)的功能。(2)城市之间有两种交通工具:火车和飞机。提供对列车时刻表和飞机航班进行编辑(增设或删除)的功能。(3)提供两种最优决策:最快到达或最省钱到达。全程只考虑一种交通工具。(4)旅途中耗费的总时间应该包括中转站的等候时间。(5)咨询以用户和计算机的对话方式进行。二设计1 设计思想(1) 数据与操作的特性 全国交通咨询模拟系统要操作的数据主要包括四类:城市的名称或代号,列车或飞机的代号,列车或飞机的运营时间,列车票或飞机票的价格。对于这些数据的操作主要有两类:增添或删除,加减计算。四类数据都有增添或删除的操作,而火车或飞机的运营时间和火车票或飞机票的价格则还有加减计算。(2)数据结构设计数据的逻辑结构:根据需求分析来看,很明显就可以看出其城市之间的交通问题是十分明显的图结构,可看作为有向图,图的顶点是城市,边是城市之间所耗费的时间(要包括中转站的等候时间)或旅费。数据的存储结构:邻接表和邻接矩阵都可作为数据的存储结构,但当邻接边不多时,宜采用邻接表,以提高空间的存储效率。因此这里采用邻接表作为数据的存储结构。(3) 算法设计 全国交通咨询模拟系统主要有三种功能:对城市信息进行编辑,对城市之间的交通方式进行编辑,提供两种最优决策(最快到达和最少花费)。对于不同的功能需求用不同的功能模块对城市信息和交通信息进行编辑。添加、修改、删除功能可用菜单方式或命令提示方式。只要能方便的对城市信息和交通信息进行管理即可,同时注意人机交互界面。2 设计表示(1) 数据类型定义 typedef struct TrafficNode char nameMAX_STRING_NUM; /班次 int StartTime,StopTime; /起止时间 int EndCity; /该有向边指向的顶点在数组中的位置,即该城市编号 int Cost; /票价 TrafficNodeDat; typedef struct VNode CityType city; int TrainNum,FlightNum; /标记下面Train数组和Flight数组里元素个数 TrafficNodeDat TrainMAX_TRAFFIC_NUM; /数组成员为结构体,记录了到达城市、起止时间、票价和班次 TrafficNodeDat FlightMAX_TRAFFIC_NUM; / int Cost; /遍历时到达该城市的耗费(时间或者费用) VNodeDat; typedef struct PNode int City; int TraNo; PNodeDat; VNodeDat AdjListMAX_VERTEX_NUM; /System Info char CityNameMAX_VERTEX_NUMMAX_STRING_NUM; /城市名,采用第一下标为该城市在本程序中的编号 int CityNum; /城市数目 PNodeDat PathMAX_VERTEX_NUM; /存储临时最小时间路径 PNodeDat MinPathMAX_VERTEX_NUM; /存储搜索到当前的最小时间路径 int MinTime,StartTime; int curPath; (2) 函数调用关系图 (3) 函数接口规格说明 函数的调用关系在上面的图中已经显示出来了,整个程序就是由一些子函数的集合,他们之间按所要实现的功能不同而调用不同的函数。在这些函数中除主函数外,其它函数的级别相同。3 详细设计 (1)主程序伪代码intmain()界面初始化; 输入操作命令;While(“命令”!=“退出”) 接受命令(用户输入要实现功能); 进入各个处理命令函数; (2)创建交通图算法的伪码描述如下:intLocateVertex(ALGaph*G,char*v)/*找出城市名在图中对应结点位置*/ for(k=0;kvexnum;k+) if(第k个结点中的城市名与传过来的城市名相同) j=k;/*记录位置*/break; 返回k的数值;intCreatGraph(ALGraph*G) if(打开城市文件,文件指针返回值为空) 输出错误文件信息;程序返回值为0; while(文件不为空) 将文件指针所指的字符串读到城市名数组cityi中; i+; 关闭文件; j=0; while(jvexnum=i; 打开航班信息文件filight.txt; 将文件中的内容以块为单位读到缓冲区数组a中; 关闭文件; a的计数变量k=0; 弧的计数变量arc_num=0; while(kverticesi.planfirstarc; m=0; while(q!=NULL) if(弧q中的邻接顶点与j相等) 将数组ai中的内容都复制到弧q中; m=1;break; q=q-nextarc; if(m=0); 开辟一个弧结点; 将数组ai中的内容都复制到新的弧结点中; 将弧结点连接到适当的位置中去; arc_num+; k+; G-planarcnum=arc_num; 打开列车信息文件train.txt; 将文件中的内容以块为单位读到缓冲区数组a中; 关闭文件; a的计数变量k=0; 弧的计数变量arc_num=0; while(kverticesi.trainfirstarc;m=0; while(q!=NULL) if(弧q中的邻接顶点与j相等) 将数组ai中的内容都复制到弧q中; m=1;break; q=q-nextarc; if(m=0); 开辟一个弧结点; 将数组ai中的内容都复制到新的弧结点中; 将弧结点连接到适当的位置中去;arc_num+; k+; G-trainarcnum=arc_num; 返回; (3)创建航班算法的伪码描述如下:creatplanefile()while(flag)/*flag为标志位,初值为1*/提示“输入航班信息”; 输入航班code; 输入航班的出发城市vt; 输入航班的到达城市vh; 输入机票价格money; 输入航班的出发时间bt; 输入航班的到达时间at; a.count.co=code; strcpy(a.count.vt,vt); strcpy(a.count.vh,vh); a.count.bt=bt; a.count.at=at; a.count.mo=money; 计数值count+1;提示“是否要继续输入航班信息:”; scanf(“%d”,&flag);if(航班文件不能以读写形式打开)提示“无法打开文件”;将计数值count写入航班车文件; for(i=0;icount;i+) if(无法将ai写入航班文件) 提示“文件无法写入”; 关闭航班文件; (4)求城市之间的最少费用算法的伪码描述如下:ExpenditureDispose() for(v=0;v城市个数;v+) 城市v还未求得最少费用;*(D+v)=城市v0到v的最少费用;将城市v的路径设置为空;if(*(D+v)INFINITY)将城市v0和v加入到城市v的路径中;城市v0到城市v0的最少费用为0;城市v0设为已求得最少费用;for(i=1;i城市个数;v+)m=INFINITY;for(w=0;w城市个数;w+)if(城市w未求得最少费用)if(*(D+w)m)v=w;m=*(D+w);if(v等于v1)根据城市v的路径输出从城市v0到城市v1所需经过的城市及路线;输出最少费用*(D+v1);返回;else将城市v设为已求得最少费用;for(w=0;m+城市v到w的最少费用)*(D+w)=m+城市v到w的最少费用;将城市w的路径改
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论