数据结构大实验1报告副本.docx
《数据结构大实验1报告副本.docx》由会员分享,可在线阅读,更多相关《数据结构大实验1报告副本.docx(27页珍藏版)》请在冰豆网上搜索。
数据结构大实验1报告副本
1.摘要
2.关键字
3.概述
3.1问题的定义
3.2算法输入
3.3算法输出
3.4研究的目的与意义
4.数据结构与算法设计
4.1数据结构的逻辑结构设计
4.2数据存储结构设计
4.3算法的基本思想和流程图
5.实验及测试
5.1开始菜单
5.2中缀转后缀
5.3后缀计算
5.4中缀计算
5.5括号匹配
5.6零的处理
3.7其他运算符
6.结论与展望
7.参考文献
8.附录(代码)
1.摘要
问题表达式求值是程序设计语言编译中的一个最基本问题。
人们在书写表达式时通常采用将运算符放在两个操作数中间的“中缀”表示形式,称为中缀表达式。
但是这种表达式形式对计算机处理来说是不太适合的。
在计算机领域,经常将算术表达式表示成“后缀”表表达式求值是程序设计语言编译中的一个最基本问题。
人们在书写表达式时通常采用将运算符放在两个操作数中间的“中缀”表示形式,称为中缀表达式。
但是这种表达式形式对计算机处理来说是不太适合的。
在计算机领域,经常将算术表达式表示成“后缀”表示形式,称为后缀表达式。
如:
中缀表达式3+2*(7-5)对应的后缀表达式为3275-*+。
2.关键字
栈,队列,中缀表达式,后缀表达式
3.概述:
3.1问题的定义:
实现中缀表达式到后缀表达式的转换,并实现中缀表达式和后缀表达式的计算。
3.2算法输入:
一个算数表达式,由数字,运算符,括号组成,数字范围0~9的正整数,运算符包含加减乘除,开方和取余。
3.3算法输出:
表达式中缀到后缀的转换和最终运算的结果。
3.4研究的目的与意义:
加深了我对栈和队列的理解,实现的简单的运算功能。
4.数据结构与算法设计
4.1数据结构的逻辑结构设计:
算数表达式由操作数,运算符和括号组成。
我们用队列寄存表达式的操作数,用栈来寄存运算符和左括号。
栈是“先进后出”的线性表,链栈存储结构是一条链表,他有一根始终指向栈顶的指针s,当s=NULL时栈就为空,当插入新节点时s就会指向新插入的节点,删除栈顶元素时,s会指向下一个节点。
4.2数据存储结构设计:
输入的表达式会先存储进链表中再利用函数对栈和队列进行操作。
/*定义字符类型的链表*/
typedefstructlnode
{
chardata;
structlnode*next;
}lnode,*linklist;
/*定义字符类型的栈*/
typedefstructstack
{
chardata;
structstack*next;
}stack,*linkstack;
/*定义字符类型的队*/
typedefstructqnode
{
chardata;
structqnode*next;
}qnode,*queueptr;
typedefstruct
{
queueptrfront;
queueptrrear;
}linkqueue;
4.3算法的基本思想和流程图
(1)优先级判断函数:
getprecedence(chare)判断运算符的优先级,返回每个运算符对应的数值。
运算符之间的关系:
+(加)=-(减)<*(乘)=/(除)=%(取余)<^(次方)=!
(开方)
(2)中缀转为后缀:
算法基本思想:
顺序扫描中缀表达式,当读到数字时,直接将其送至输出队列中;当读到运算符时,将栈中所有优先级高于或等于该运算符的运算符弹出,送至输出队列中,再将当前运算符入栈;当读入左括号时,将其入运算符栈;当读到右括号时,将栈中从栈顶到靠近栈顶的第一个左括号之间的所有运算符全部依次弹出,送至输出队列中,再删除栈中的左括号。
流程图:
Y
N
Y
N
N
Y
Y
N
Y
N
Y
N
Y
表格解释:
中缀表达式到后缀表达式的转换过程示例
转换步骤
中缀表达式的读入
运算符栈
后缀表达式
初始
1+2*(3-1+2)-3#
#
空
1
+2*(3-1+2)-3#
#
1
2
2*(3-1+2)-3#
#+
1
3
*(3-1+2)-3#
#+
12
4
(3-1+2)-3#
#+*
12
5
3-1+2)-3#
#+*(
12
6
-1+2)-3#
#+*(
123
7
1+2)-3#
#+*(-
123
8
+2)-3#
#+*(-
1231
9
2)-3#
#+*(+
1231-
10
)-3#
#+*(+
1231-2
11
-3#
#+*
1231-2+
12
3#
#-
1231-2+*+
13
#
#-
1231-2+*+3
14
空
1231-2+*+3-
(3)后缀表达式的计算:
算法基本思想:
利用栈(操作数和运算结果栈)计算后缀表达式。
顺序扫描后缀表达式,当读到数字时,将其送至栈中;当读到运算符θ时,将栈顶字符弹出,将其转换成对应的数值并赋给变量y,再将次栈顶字符弹出,将其转换成对应的数值,并赋给变量x,之后计算xθy,将运算结果转换成对应的数字字符送入栈中。
表格解释:
表1-2后缀表达式计算过程示例
计算步骤
后缀表达式的读入
运算符栈
初始
1231-2+*+3-
空
1
231-2+*+3-
1
2
31-2+*+3-
12
3
1-2+*+3-
123
4
-2+*+3-
1231
5
2+*+3-
122
6
+*+3-
1222
7
*+3-
124
8
+3-
18
9
3-
9
10
-
93
11
空
6
流程图:
N
Y
N
Y
N
Y
(3)中缀表达式就计算:
算法基本思想:
将中缀表达式通过中缀到后缀的转化函数转成后缀表达式并利用后缀表达式的求值函数来计算。
流程图:
5.实现及测试:
(1)开始菜单
(2)中缀表达式转换成后缀表达式
(3)后缀表达式的计算
例子:
23+4*5-
(4)中缀表达式的计算
例子:
(2+3)*4-5
(5)括号匹配检测
(6)除法零的处理
(7)其他运算符
n次幂运算
开平方运算
取余运算
6.结论与展望
时间复杂度上中缀表达式转后缀O(n),后缀表达式计算O(n^2),这个实验加深了我对栈和队列的理解,让我感受到了数据结构的强大作用,增加了我的学习热情。
这个程序的不足之处有很多,没有实现可视化也没有实现小数之间的运算,程序的操作界面过于简陋,我已经尽力而为了,在今后的学习中我会努力学习这些知识,让自己的编程水平更上一层楼!
7.参考文献:
《数据结构与算法》严蔚敏著
XX文库
8.附录
#include
#include
#include
#include
#include
usingnamespacestd;
typedefstructstack//链栈的定义
{
chardata;
structstack*next;
}stack,*linkstack;
typedefstructlnode//队的定义
{
chardata;
structlnode*next;
}lnode,*linklist;
voidinitstack(linkstack&s)//初始化栈
{
s=NULL;
}
voidpush(linkstack&s,charc)//入栈
{
linkstackp;
p=newstack;
p->data=c;
p->next=s;
s=p;
}
charpop(linkstack&s)//出栈
{
charc;
if(s==NULL)
{
cout<<"栈为空"<exit(0);
}
linkstackp;
c=s->data;
p=s;
s=s->next;
deletep;
returnc;
}
chargettop(linkstack&s)//取栈顶
{
if(s!
=NULL)
{
returns->data;
}
}
typedefstructqnode//链队的定义
{
chardata;
structqnode*next;
}qnode,*queueptr;
typedefstruct
{
queueptrfront;
queueptrrear;
}linkqueue;
voidinitqueue(linkqueue&q)//初始化队
{
q.front=q.rear=newqnode;
q.front->next=NULL;
}
voidenqueue(linkqueue&q,chare)//入队
{
queueptrp;
p=newqnode;
p->data=e;
p->next=NULL;
q.rear->next=p;
q.rear=p;
}
voiddequeue(linkqueueq)//出队并输出出队的值
{
qnode*p;
p=q.front->next;
while(p!
=NULL)
{
cout<data<<"";
p=p->next;
}
}
voidcreate(linklist&l)//输入函数并建立链表
{
linklistp,r;
l=newlnode;
r=l;
chara;
cout<<"请输入表达式并以#结尾"<cin>>a;
while(a!
='#')
{
p=newlnode;
p->data=a;
r->next=p;
r=p;
cin>>a;
}
r->next=NULL;
}
voidjudge(linklist&l)//判断函数,判断括号的匹配
{
linkstacks;
initstack(s);
linklistp;
p=l->next;
charc;
while(p!
=NULL)
{
if(p->data=='(')
{
c=p->data;
push(s,c);
}
elseif(p->data==')'&&s!
=NULL)
{
pop(s);
}
elseif(p->data==')'&&s==NULL)
{
cout<<"匹配失败,右括号多了"<exit(0);
}
p=p->next;
}
if(s==NULL)
cout<<"括号匹配成功"<else
cout<<"匹配失败,左括号多了"<}
intgetprecedence(chare)//得到操作符的优先级
{
switch(e)
{
case'#':
return0;
case'+':
return1;
case'-':
return1;
case'*':
return2;
case'/':
return2;
case'%':
return2;
case'^':
return3;
case'!
':
return3;
}
}
voidinqueue(linkqueue&q)//将后缀表达式入队,用来传给计算函数
{
qnode*p;
charx;
cout<<"请输入后缀表达式(以#结束输入):
"<cin>>x;
while(x!
='#')
{
p=newqnode;
p->data=x;
p->next=NULL;
q.rear->next=p;
q.rear=p;
cin>>x;
}
}
linkqueuechange(linklist&l,linkstack&s,linkqueueq)//中缀表达式转换成后缀表达式
{
initqueue(q);
initstack(s);
linklistp;
p=l->next;
chara,b,c;
push(s,'#');//先把#压入栈作为一个标志
while(p!
=NULL)
{
if((p->data)>='0'&&(p->data)<='9')//碰到数字入队
{
enqueue(q,p->data);
}
elseif(p->data=='(')//碰到左括号入栈
{
push(s,p->data);
}
elseif(p->data==')')//碰到右括号就出栈一直到栈顶为左括号再将左括号出栈
{
while(gettop(s)!
='(')
{
a=pop(s);
enqueue(q,a);
}
pop(s);//删除左括号
}
elseif(gettop(s)=='(')//碰到做括号入栈
{
push(s,p->data);
}
elseif(p->data=='+'||p->data=='-'||p->data=='*'||p->data=='/'||p->data=='!
'||p->data=='%'||p->data=='^')
{
while(getprecedence(gettop(s))>=getprecedence(p->data))//碰到运算符就将优先级大于等于自己的运算符出栈再将出栈的运算符入队,最后将自己入栈
{
b=pop(s);
enqueue(q,b);
}
push(s,p->data);
}
else//不是上述的情况证明输入了一个错误的元素
{
cout<<"输入格式有误!
系统无法识别,请重新输入!
"<exit(0);
}
p=p->next;
}
while(gettop(s)!
='#')//将栈中元素出栈直到栈顶为标志#
{
c=pop(s);
enqueue(q,c);
}
dequeue(q);//出队并输出
returnq;
}
intevaluateexpression(linkqueueq)//后缀表达式计算
{
qnode*p;
intx1,x2,temp;
linkstacks;
initstack(s);
p=q.front->next;
while(p!
=NULL)
{
if(p->data>='0'&&p->data<='9')//碰到数字就-48将char型转成int型,并将结果入栈
{
temp=p->data-48;
push(s,temp);
p=p->next;
}
elseif(p->data=='')//碰到空格就跳过
{
p=p->next;
}
elseif(p->data=='+')//碰到加号就弹出两个操作数并相加,并将结果入栈
{
x1=pop(s);
x2=pop(s);
temp=x1+x2;
push(s,temp);
p=p->next;
}
elseif(p->data=='-')//碰到减号就弹出两个操作数并相减,并将结果入栈
{
x1=pop(s);
x2=pop(s);
temp=x1-x2;
push(s,temp);
p=p->next;
}
elseif(p->data=='*')//碰到乘号就弹出两个操作数并相乘,并将结果入栈
{
x1=pop(s);
x2=pop(s);
temp=x1*x2;
push(s,temp);
p=p->next;
}
elseif(p->data=='/')//碰到除号就弹出两个操作数并相除,并将结果入栈
{
x1=pop(s);
x2=pop(s);
if(x1!
=0)
{
temp=x2/x1;
push(s,temp);
p=p->next;
}
else
{
cout<<"格式错误!
"<exit(0);
}
}
elseif(p->data=='^')//碰到次方就弹出两个操作数并做次方运算,并将结果入栈
{
x1=pop(s);
x2=pop(s);
temp=pow(x2,x1);
push(s,temp);
p=p->next;
}
elseif(p->data=='!
')//碰到开方号就弹出一个个操作数并开平方,并将结果入栈
{
x1=pop(s);
temp=sqrt(x1);
push(s,temp);
p=p->next;
}
elseif(p->data=='%')//碰到取余号就弹出两个操作数并取余,并将结果入栈
{
x1=pop(s);
x2=pop(s);
temp=x2%x1;
push(s,temp);
p=p->next;
}
}
temp=pop(s);//栈中最后剩下的元素就为最后运算的结果
returntemp;
}
voidmenu()//菜单函数
{
cout<<"¥***************************************************************************¥"<cout<<"简易计算器系统"<cout<<"1.实现中缀表达式到后缀表达式的转换"<cout<<"2.实现后缀表达式的计算"<cout<<"3.实现中缀表达式的计算"<cout<<"4.退出"<cout<<"¥***************************************************************************¥"<}
voidmain()//主函数
{
system("colorF9");//输出界面调色
intnum,ret;
menu();
linklistl;
linkstacks;
cout<<"请输入你要的选项:
";
while(num!
=4)
{
cin>>num;
switch(num)
{
case1:
system("cls");
cout<<"中缀表达式到后缀表达式的转换:
"<linkqueueq;
initqueue(q);
create(l);
judge(l);
cout<<"后缀表达式为:
";
q=change(l,s,q);cout<system("pause");
break;
case2:
system("cls");
cout<<"后缀表达式的计算"<cout<<"输入新的后缀表达式";
linkqueuem;
initqueue(m);
inqueue(m);
ret=evaluateexpression(m);
cout<<"后缀表达式计算的结果:
";
cout<system("pause");
break;
case3:
system("cls");
cout<<"中缀表达式的计算"<cout<<"请输入一个中缀表达式(以#作为结束符):
"<create(l);
judge(l);
q=change(l,s,q);
ret=evaluateexpression(q);
cout<<"中缀表达式的计算结果:
"<system("pause");
break;
case4:
system("cls");
cout<<"感谢您使用本系统,再见!
"<break;
default:
system("cls");
cout<<"没有此菜单选项";
system("pause");
}
if(num!
=4)
{
system("cls");
menu();
cout<<"请继续输入你的选择:
";
}
}
}