数据结构课设报告.docx
- 文档编号:6905646
- 上传时间:2023-01-12
- 格式:DOCX
- 页数:45
- 大小:490.66KB
数据结构课设报告.docx
《数据结构课设报告.docx》由会员分享,可在线阅读,更多相关《数据结构课设报告.docx(45页珍藏版)》请在冰豆网上搜索。
数据结构课设报告
二、计算命题公式的真值
1.问题描述
所谓命题演算公式是指由逻辑变量(其值为TRUE或FALSE)和逻辑运算符∧(AND)、∨(OR)和┐(NOT)按一定规则所组成的公式(蕴含之类的运算可以用∧、∨和┐来表示)。
公式运算的先后顺序为┐、∧、∨,而括号()可以改变优先次序。
已知一个命题演算公式及各变量的值,要求设计一个程序来计算公式的真值。
要求:
1)利用二叉树来计算公式的真值。
首先利用堆栈将中缀形式的公式变为后缀形式;然后根据后缀形式,从叶结点开始构造相应的二叉树;最后按后序遍历该树,求各子树之值,即每到达一个结点,其子树之值已经计算出来,当到达根结点时,求得的值就是公式之真值。
2)逻辑变元的标识符不限于单字母,而可以是任意长的字母数字串。
3)根据用户的要求显示表达式的真值表。
2.需求分析
2.1、命题演算公式的定义
命题演算公式是指由逻辑变量(其值为TRUE或FALSE)和逻辑运算符∧(AND)、∨(OR)和┐(NOT)按一定规则所组成的公式(蕴含之类的运算可以用∧、∨和┐来表示)。
2.2、运算规则
公式运算的先后顺序为┐、∧、∨,而括号()可以改变优先次序。
2.3、输入输出
输入一个中缀表达式,将此表达式转换为后缀表达式,并以此给变量赋值,求出该逻辑表达式的真值。
3.概要设计
3.1、存储数据所用数据结构
3.1.1、用字符数组ab[100]存放用户输入的中缀表达式并将其转换为用Data结构体数组a[100]存放的中缀表达式;
抽象数据类型定义如下:
typedefstruct
{
charbiao[100];
intnum;
}Data;
typedefstruct//栈
{
charstack[MaxSize];
inttop;
}SeqStack;
3.1.2、用Data结构体数组b[100]存放转换后的后缀表达式;
3.1.3、用BiTreeNode结构体存放二叉树的结点;
抽象数据类型定义如下:
typedefstructNode
{
DataTypedata[100];
structNode*leftChild;
structNode*rightChild;
structNode*parent;
}BiTreeNode;
3.1.4、用Stack结构体存放二叉树结点的栈类型。
抽象数据类型定义如下:
typedefstruct
{
BiTreeNode*address[1000];
inttop;
}Stack;
3.2、基本计算步骤
3.2.1、利用堆栈将中缀形式的公式变为后缀形式;
3.2.2、根据后缀形式,从叶结点开始构造相应的二叉树;
3.2.3、按后序遍历该树,求各子树之值,即每到达一个结点,其子树之值已经计算出来,当到达根结点时,求得的值就是公式之真值。
3.3、基本要求
3.3.1、逻辑变元的标识符不限于单字母,而可以是任意长的字母数字串。
3.3.2、根据用户的要求显示表达式的真值表。
3.4、简要流程图
3.5、算法设计
本设计从总体上划分为以下四个模块:
3.5.1、主函数main()模块
本模块的功能是实现逻辑表达式的输入以及各函数的调用和逻辑表达式计算结果的输出,并控制程序的开始与结束。
通过调用houzhui(a,b,s)来实现中缀转变为后缀;通过调用CreatTree(b,n)来实现从叶子结点开始构造一棵二叉树;通过调用PostOrder(t,b,n)来实现对二叉树的后续遍历并计算出逻辑表达式的真值。
3.5.2、中缀表达式转为后缀表达式inthouzhui(Datazhongzhui[],Data*b,SeqStacks)模块
本模块的功能是利用堆栈来实现把中缀逻辑表达式转换为后缀逻辑表达式,本模块所用函数及抽象数据类型均在houzhui.h这个头文件中,此模块将转换之后的后缀表达式数组的个数返回给主函数。
3.5.3、构造二叉树BiTreeNode*CreatTree(Data*b,intn)模块
此模块利用堆栈来实现从叶子结点构造二叉树。
通过调用SInitiate(&S)来实现对堆栈的初始化;通过调用Pop(&S)和Push(&S,p)来分别实现堆栈的出栈与入栈操作。
最终返回创建的二叉树的根结点指针。
3.5.4、后续遍历二叉树并计算真值intPostOrder(BiTreeNode*t,Datab[],intn)模块
此模块利用对二叉树的后续遍历来实现逻辑表达式的真值的计算。
通过递归调用PostOrder函数来最终计算出真值,并返回计算结果。
首先调用
3.5.5、各模块之间的关系图如下
其次调用
最后调用
4.详细设计
4.1、中缀表达式转为后缀表达式inthouzhui(Datazhongzhui[],Data*b,SeqStacks)
本模块主要思想如下:
(1)设置一个堆栈,初始时将栈顶元素置为#;
(2)顺序读入中缀表达式的a[j].biao[0],当读到的数据为操作数时就将其所在的a[j].biao中所有元素存入到对应的b[j].biao中,并接着读a[j+1].biao[0];(3)当读到的元素为运算符且它的优先级低于当前栈顶元素的优先级,将当前栈顶元素退栈并存入到对应的b[j].biao[0]中;当读到的元素为运算符且它的优先级高于当前栈顶元素的优先级,将读到的元素进栈,并接着读下一个a[j].biao[0];若读到的元素为’(’,则将其入栈;若读到的元素为’)’,而栈顶元素为’(’,则将栈顶元素出栈;若读到的元素为’#’,而栈顶元素为’#’,则算法结束。
详细代码如下:
inthouzhui(Datazhongzhui[],Data*b,SeqStacks)
{
charcurrent,d,d1;//定义后缀数组
intcount=0,j=0,i=0;
while(zhongzhui[j].biao[0]!
='\0')//取中缀字符
{
current=zhongzhui[j].biao[0];//取当前为中缀字符
if(!
if_operator(current))//判断字符是运算变量
{
for(i=0;zhongzhui[j].biao[i]!
='\0';i++)b[count].biao[i]=zhongzhui[j].biao[i];
b[count].num=count;
count++;
j++;
}
if(if_operator(current)&¤t!
='(')//判断字符是运算符且不为左括号
{
StackTop(s,&d);
while(priority(d)>priority(current))//当前字符的优先级小于栈顶元素的优先级
{
StackPop(&s,&d1);
b[count].biao[0]=d1;
b[count].num=count;
count++;
StackTop(s,&d);
}
if(priority(d) StackPush(&s,current); if(priority(d)==priority(current)&&d=='('&¤t==')')//当前字符的优先级等于栈顶元素的优先级 StackPop(&s,&d1); if(priority(d)==priority(current)&&d! ='#'&&d! ='(') StackPush(&s,current); if(priority(d)==priority(current)&&d=='#'&¤t=='#')//当前字符的优先级等于栈顶元素的优先级 break; j++; } if(if_operator(current)&¤t=='(')//判断字符是运算符且为左括号 { StackPush(&s,current); j++; } } returncount;//返回后缀数组的地址 } 4.2、构造二叉树BiTreeNode*CreatTree(Data*b,intn) 本模块主要思想如下: (1)初始化一个堆栈,用来存放二叉树的结点; (2)顺序读入中缀表达式的a[j].biao[0],当读到的数据为操作数时就将其所在的a[j].biao中所有元素存入到对应的二叉树结点的data数组中,并将该结点的左孩子指针、右孩子指针和双亲指针均赋为NULL,将该结点入栈;(3)读入中缀表达式的a[j].biao[0],当读到的数据为’&’或’|’时,将当前栈顶元素出栈,将其赋予新的二叉树结点的右孩子指针,继续出栈当前栈顶元素,将其赋予新的二叉树结点的左孩子指针,将当前结点赋给右孩子的双亲指针,再将新结点入栈;(4)、读入中缀表达式的a[j].biao[0],当读到的数据为’! ’时,将当前栈顶元素出栈,将其赋予新的二叉树结点的右孩子指针,将当前结点赋给右孩子的双亲指针,再将新结点入栈。 详细代码如下: BiTreeNode*CreatTree(Data*b,intn) { inti,j; BiTreeNode*p,*q,*o; StackS; SInitiate(&S);//初始化堆栈 for(i=0;i { p=(BiTreeNode*)malloc(sizeof(BiTreeNode));//申请二叉树结点空间 memset(p->data,0,sizeof(p->data));//清零申请结点的data域 for(j=0;b[i].biao[j]! ='\0';j++) p->data[j]=b[i].biao[j];//将变量赋给结点P的data域 p->rightChild=NULL;//初始化左右子树以及双亲指针 p->leftChild=NULL; p->parent=NULL; if(b[i].biao[0]=='! ')//变量为! 时,栈顶元素为该结点的右孩子 { q=Pop(&S); p->rightChild=q;//将弹出后的结点作为右孩子 q->parent=p; Push(&S,p);//将该结点入栈 } elseif(b[i].biao[0]=='|'||b[i].biao[0]=='&')//变量为&或|时,栈顶元素为该结点的右孩子,下一个元素为该结点的左孩子 { q=Pop(&S);//弹出q作为右孩子 o=Pop(&S);//弹出0作为左孩子 q->parent=p; o->parent=p; p->leftChild=o; p->rightChild=q; Push(&S,p);//将该结点入栈 } elsePush(&S,p);//如果变量为运算变量,则将该结点入栈 } p=Pop(&S);//弹出构造好的二叉数的根结点指针,并返回 returnp; } 4.3、后续遍历二叉树并计算真值intPostOrder(BiTreeNode*t,Datab[],intn) 本模块主要思想如下: (1)后续遍历所创建的二叉树,读出对应的data域对应的真值; (2)若结点的data域为运算变量,则直接返回该变量所对应的真值;(3)若结点的data域为’! ’,则对该结点的右孩子结点对应真值a1求反,并返回计算结果;(4)若结点的data域为’&’,则对该结点的左孩子结点对应的真值a和左孩子结点对应的真值a1进行与操作,并返回计算结果;(5)若结点的data域为’|’,则对该结点的左孩子结点对应的真值a和左孩子结点对应的真值a1进行或操作,并返回计算结果。 详细代码如下: intPostOrder(BiTreeNode*t,Datab[],intn)//后序遍历该树并计算逻辑表达式的真值 { inti=0,p,a,a1,j,k; if(t! =NULL) { a=PostOrder(t->leftChild,b,n);//遍历左子树并返回对应的真值 a1=PostOrder(t->rightChild,b,n);//遍历右子树并返回对应的真值 for(i=0;i { for(j=0;b[i].biao[j]! ='\0';j++) { if(b[i].biao[j]==t->data[j])k=b[i].num; elsebreak; } } p=c[k];//找到真值 if(t->data[0]=='! ')//变量为! 时对右子树真值取反 { if(a1==0)return1; if(a1==1)return0; } elseif(t->data[0]=='&')//变量为&时对左子树真值与右子树真值进行与运算,只有真值均为1时返回1 { if(a==1&&a1==1)return1; elsereturn0; } elseif(t->data[0]=='|')//变量为|时对左子树真值与右子树真值进行或运算,只有真值均为0时返回0 { if(a==0&&a1==0)return0; elsereturn1; } elsereturnp;//如果该变量为运算变量则直接返回该变量对应的真值 } return-1; } 5.测试结果 组数 测试输入 测试目的 正确输出 实际输出 错误原因 当前状态 1 A&(B|C) 测试括号匹配是否正确 ABC|& ABC| 中缀表达式存储错误,没有正确处理括号的匹配 已 改 正 2 A&(B|C)&E&F|G A: 1,B: 0,C: 0,E: 1, F: 1,G: 0 测试计算结果是否正确 0 0 无 错 误 通 过 3 Man&(women|child) &lady&boy|male Man: 1,women: 0, Child: 0,lady: 1, Boy: 1,male: 0 测试当多字符表示一个变量时计算结果是否正确 0 0 无 错 误 通 过 测试数据2运行截屏如下: 测试数据3运行截屏如下: 6.分析与探讨 6.1、遇到的问题及解决方法 在本程序的调试过程中主要遇到了以下两个问题: 1、中缀表达式转换为后缀表达式时,在中缀表达式中不含括号时结果是对的,但是当中缀表达式中包含括号时程序是错误的,经过单步跟踪调试发现出错的地方时在用Data结构体存储中缀表达式时没有考虑到包含括号这样的情况,改之正确。 2、后续遍历二叉树时计算结果输出始终为1,经过单步跟踪调试发现错误时由于在取遍历到的变量对应的真值时出错,改正去得真值的方法后调试正确,输出结果正确。 6.2、时间复杂度与空间复杂度 本程序的时间与空间复杂度主要源于以下三个函数: inthouzhui();时间复杂度O(n)空间复杂度O(n) BiTreeNode*CreatTree();时间复杂度O(2^n)空间复杂度O(n) PostOrder();时间复杂度O(2^n)空间复杂度O(n) 6.3、其他算法及意见 本程序中还可以用二维数组来存放中缀表达式及后缀表达式,并且可以以动态申请的方式,这样可以节省内存空间,同样也可以利用链式堆栈来替代顺序堆栈。 7、附录 程序文件名清单: 逻辑表达式真值.c//计算逻辑表达式程序的c语言文件 houzhui.h//将中缀表达式转换为后缀表达式函数所在头文件 参考文献: [1]朱战立,数据结构——使用C语言,西安交通大学出版社,2004年 五、迷宫问题 1.问题描述 以一个m*n的长方阵表示迷宫,0和1分别表示迷宫中的通路和障碍。 设计一个程序,对任意设定的迷宫,求出一条从入口到出口的通路,或得出没有通路的结论。 基本要求: (1)首先实现一个以链表作存储结构的栈类型,然后编写一个求解迷宫的非递归程序。 求得的通路以三元组(i,j,d)的形式输出,其中(i,j)指示迷宫中的一个坐标,d表示走到下一坐标的方向。 (2)测试几组数据,数据的规模由小变大,即网格越来越小,障碍越来越复杂。 拓展要求: 实现该问题的可视化界面,用鼠标点击即可一步步走出迷宫。 提示: 计算机解迷宫问题通常采用“穷举求解”方法 2.需求分析 2.1、迷宫的表示方法 以一个m*n的长方阵表示迷宫,0和1分别表示迷宫中的通路和障碍。 2.2、实现方法 计算机解迷宫问题通常采用“穷举求解”方法。 2.3、输入输出 以一个二维数组的形式输入迷宫,求得的通路以三元组(i,j,d)的形式输出,其中(i,j)指示迷宫中的一个坐标,d表示走到下一坐标的方向。 3.概要设计 3.1、数据结构的设计 3.1.1、用链式堆栈来存储在迷宫中寻找路径所走过的结点,方便在找不到前进路径的时候进行出栈回溯; 3.1.2、用一个Data结构体来存放堆栈中对应数据域元素的属性,方便对对应的元素进行操作; 3.1.3、用一个二维数组来存放以矩阵形式表示的迷宫,方便对迷宫路径的寻找及方向的标记与表示。 3.2、算法的设计 本程序主要分为以下三个部分: 3.2.1、主函数main()模块 本模块主要是实现用户可视界面及迷宫的输入,利用二维数组来存放用户输入的迷宫的内容,通过调用函数search和printpath来实现路径的寻找与输出。 3.2.2、寻找路径search()模块 本模块主要是实现找到从迷宫入口到迷宫出口的路径,并记录下在每个结点进行寻找时到下一个结点的方向,返回查找是否成功。 函数接口为: search(a,p,q,r,S)。 3.2.3、输出路径printpath()模块 本模块主要是实现对找到的路径进行输出,以三元组(i,j,d)的形式输出,其中(i,j)指示迷宫中的一个坐标,d表示走到下一坐标的方向。 函数接口为: printpath(s)。 调用关系图如下: StackInitiate、StackPush、 StackNotEmpty、StackTop Search 主函数 StackNotEmpty、StackPop Printpath 3.3、抽象数据类型的设计 3.3.1、链式堆栈结点 typedefstructsnode { Datadata; structsnode*next; }LSNode; 3.3.2、Data结构体 typedefstruct { introw;//行坐标 intcol;//列坐标 intdir;//1代表←,2代表→,3代表↓,4代表↑,0代表无效 }Data; 3.4、简要流程图 是 否 4.详细设计 4.1、查找路径模块 此模块的主要算法思想如下: 用一个已经初始化的链式堆栈来存放迷宫中已经搜索过的结点。 首先将入口结点进栈,然后将此结点的值赋为-1,表示该结点已经被搜索过;接着判断堆栈是否为空,如果堆栈非空,则取栈顶元素,判断该元素的四个方向是否有通路,如果有通路,则将下一个结点入栈,并将其值赋为-1;如果没有通路则将当前栈顶元素出栈回溯至上一个结点,接着进行上述判断。 如果栈顶元素的下一个结点恰好为迷宫出口,则算法结束。 最后判断建立的堆栈是否为空,如果为空,则没有查找的路径;如果不为空,则输出堆栈中存放的路径。 具体代码如下: intsearch(intb[100][100],intx,inty,intx1,inty1)//寻找路径 { Datadata; inti,j; StackInitiate(&s); b[x][y]=-1;//标记入口 data.row=x; data.col=y; data.dir=0; StackPush(s,data);//入口进栈 while(StackNotEmpty(s)) { StackTop(s,&data); i=data.row; j=data.col; if(b[i][j-1]==0&&i>=0&&j>=1) { b[i][j-1]=-1; data.row=i; data.col=j-1; data.dir=1; StackPush(s,data); if(i==x1&&(j-1)==y1)break; } elseif(b[i][j+1]==0&&i>=0) { b[i][j+1]=-1; data.row=i; data.col=j+1; data.dir=2; StackPush(s,data); if(i==x1&&(j+1)==y1)break; } elseif(b[i+1][j]==0) { b[i+1][j]=-1; data.row=i+1; data.col=j; data.dir=3; StackPush(s,data); if((i+1)==x1&&j==y1)break; } elseif(b[i-1][j]==0&&i>=1) { b[i-1][j]=-1; data.row=i-1; data.col=j; data.dir=4; StackPush(s,data); if((i-1)==x1&&j==y1)break; } elseStackPop(s,&data); } if(StackNotEmpty(s))return1; elsereturn0; } 4.2、输出路径模块 此模块的主要算法思想如下: 首先从堆栈中取出栈中所有元素存放在结构体数组中,由于堆栈是后进先出的,所以在输出时从该结构体数组的最后一个元素开始输出。 输出时先输出路径上每个结点的行坐标与列坐标,接着根据数据来判断该结点的方向,输出相对应的方向。 详细代码如下: voidprintpath(LSNode*head) { Datadata,a[100]; inti=0,n=0; while(StackNotEmpty(head)) { StackPop(head,&data); a[i]=data; n=i; i++; } for(i=n;i>0;i--)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 报告
![提示](https://static.bdocx.com/images/bang_tan.gif)