数据结构(表达式求值)课程设计

时间:2024.4.20

课程设计报告

20##年  12月 31日


目       录

1.设计目的:........................................................ 1

2.设计要求:........................................................ 1

3.设计方案:........................................................ 1

4.设计内容:........................................................ 2

4.1.需求分析.................................................. 2

4.2.概要设计.................................................. 2

4.3.详细设计................................................... 4

4.4.调试分析与结果............................................. 7

4.5:使用说明................................................. 11

5.总结:.......................................................... 12

6.附录三:源代码.................................................. 12


表达式求值问题

1.设计目的:

《数据结构课程设计》是计算机专业集中实践性环节之一,是学习完《数据结构》课程后进行的一次全面的综合练习。其目的是:

(1)要达到理论与实际应用相结合,使学生能够根据数据对象的特性,学会数据组织的方法,能把现实世界中的实际问题在计算机内部表示出来,并培养良好的程序设计技能。

(2)在实践中认识为什么要学习数据结构,掌握数据结构、程序设计语言、程序设计技术之间的关系,是前面所学知识的综合和回顾。

2.设计要求:

以字符序列的形式从键盘输入语法正确的、不含变量的整数(或实数)表达式,实现对算术四则混合运算表达式的求值。当用户输入一个合法的算术表达式后,能够返回正确的结果。能够计算的运算符包括:加、减、乘、除、括号,对于异常表达式能给出错误提示。

3.设计方案:

任何一个表达式都是由操作符,运算符组成的。我们分别用顺序栈来寄存表达式的操作数和运算符。栈是限定于紧仅在表尾进行插入或删除操作的线性表。顺序栈的存储结构是利用一组连续的存储单元依次存放自栈底到栈顶的数据元素。

为了实现算符优先算法。可以使用两个栈。一个称为OPF,用以寄存运算符,另一个称做OPS,用以寄存操作数或运算结果。

1.首先置操作数栈为空栈,表达式起始符”#”为运算符栈的栈底元素;

2.依次读入表达式,若是操作符即进OPS栈,若是运算符则和OPF栈的栈顶运算符比较优先权后作相应的操作,直至整个表达式求值完毕(即OPF栈的栈顶元素和当前读入的字符均为”#”)。

4.设计内容:

4.1.需求分析

本程序所做的工作为:能直接求出四则表达式的值,并输出;本程序可用于小学教师对学生作业的快速批改以及对数值位数要求较大的科学运算。

4.2.概要设计

1.//用于存储操作数和运算结果(OPS:

ADT LinkStack{

数据元素:此链栈中的所有元素类型为字符型的数字字符

数据关系:栈中数据元素之间是线性关系。

基本操作:

(1)InitStack(LinkStack &head)

操作结果:构造一个空栈head

(2)IsEmpty(LinkStack head)

初始条件:栈head已存在

操作结果:若栈为空栈,则返回TRUE,否则FALSE

(3)Push(LinkStack &head,ElementType element)

初始条件:栈head已存在

操作结果:插入元素element为新的栈顶元素

(4)Pop(LinkStack &head,ElementType &element)

初始条件:栈head已存在且非空

操作结果:删除head的栈顶元素,并用e返回其值

(5)GetTop(LinkStack head, ElementType &element)

初始条件:栈head已存在并且非空

操作结果:用e返回head的栈顶元素

(6)DestroyStack(LinkStack &head)

初始条件:栈head已存在

操作结果:栈head 被销毁

}ADT LinkStack

2//用于存储运算符(OPF)

ADT LinkCharStack{

数据对象D:元素类型为字符型的符号字符

数据关系R:

基本操作:栈中数据元素之间是线性关系。

(1)CInitStack(LinkCharStack &head)

操作结果:构造一个空栈head

(2)CIsEmpty(LinkCharStack head)

初始条件:栈head已存在

操作结果:若栈为空栈,则返回TRUE,否则FALSE

(3)CPush(LinkCharStack &head,ElementType element)

初始条件:栈head已存在

操作结果:插入元素element为新的栈顶元素

(4)CPop(LinkCharStack &head,ElementType &element)

初始条件:栈head已存在且非空

操作结果:删除head的栈顶元素,并用e返回其值

(5)CGetTop(LinkCharStack head, ElementType &element)

初始条件:栈head已存在并且非空

操作结果:用e返回head的栈顶元素

(6)CDestroyStack(LinkCharStack &head)

初始条件:栈head已存在

操作结果:栈head 被销毁

}ADT LinkCharStack

3.系统中子程序及功能要求:

Comop(char ch):判断输入的字符是否为运算符

char Precede(char ch,char c):比较两个运算符的优先级,ch是栈顶字符,c是表达式字符。

ElementType Operate(ElementType a,char ch,ElementType b):解析表达式中的双目运算,其返回的结果即为双目运算表达式的值。

int error(char *str)  :错误提示函数,实现对多种非法四则表达式的判断,并给出提示,让用户更正自己的输入错误。

void MenuPrint():主菜单打印函数。

void Clear():清屏函数。

ElementType EvaluateExpression(char *exp):这是此程序的核心函数,可以综合其它子函数,实现最终的表达式求解。

各程序模块之间的调用关系(子程序编号见上):

主函数可调用子程序5,6,7。

子程序7可调用子程序1,2,3,4。

4.3.详细设计

此算法的基本思想:

首先置操作数栈OPS为空栈,表达式起始符“#”为运算符的栈底元素;依次读入表达式中每个字符,若是操作数则进栈,若是运算符则和OPF栈的栈顶运算符比较优先权作相应操作,直至整个表达式求值完毕(即OPF栈的栈顶元素和当前读入的字符均为“#”)

此算法的伪代码:

       ElementType EvaluateExpression(char *exp)

{  定义两个字符变量c和ch,c代表输入表达式中的字符,ch代表栈顶运算符;

定义字符指针 *p,*q,*temp;temp指向运算符后面的一个字符

       double i=0,a=0,b=0;

       将传入的实参赋给p,q;

       定义一个运算符栈 OPF;

       定义一个操作数栈 OPS;

       调用函数InitStack()初始化栈OPS;

调用函数CInitCharStack()初始化栈OPF;

调用函数CPush(OPF,'#')将#压入运算符栈;

       c=*p;temp=p;p++;

       if(第一个字符就为‘-’)

       {

              c=*p;temp=p;p++;

       }

       while(栈不为空或表达式没有结束)

         {//进入最外层循环

              if(不是运算符)//则解析数字字符串然后进操作数栈

              {

                     整数部分m=0;

小数部分n=0;

                     while(没有遇到小数点并且为数字字符)

                     {  解析整数部分m  }

                     if(遇到小数点)

                     {  解析小数部分

                            c=*p;

                            将p指针移到第一个出现的字符;

                            将q指针指向小数的最后一位;

                            while(p指针不指向’.’)

                            {

                                   将p指向的字符转为小数n

                                   p--;

                            }

                            p=q;

                            p++;

                      }         

              if(运算符为‘-’并且运算符前一个为‘(’或者为表达式的开始)

                     调用Push(OPS,-(m+n))将m+n的相反数入栈;

              else

                     调用Push(OPS,m+n)将m+n入栈;

}数字进栈结束

              else//是运算符时则进栈OPF

              { if(运算符为‘-’&&运算符前一个为‘(’)

                     {  c=*p;

                            temp=p;

                            p++;

                      }

                     else

                     { 调用函数CGetTop(OPF,ch)得到OPF的栈顶元素;

switch(调用函数Precede(ch,c)判断栈顶元素与接收的字符的优生级别)

                            {

                            case 栈顶运算符优先权低:

                                   调用函数CPush(OPF,c)将c入运算符栈;

                                   接收下一个字符;

                            case 栈顶运算符优先权高:

                                   运算符出栈得到ch;

                                   数字栈连续出栈两次得到a,b ;

                                   调用Operate(a,ch,b)并将结果入栈到数字栈;break;

                            case 优生权相等:脱括号并接收下一个字符;

                                   调用CPop(OPF,ch)脱括号;接收下一个字符;

                            default:接收下一个字符;

                            }退出switch循环

                     }//else1

              }//else2

       }//退出最外层while循环

       调用函数GetTop(OPS,i)得到栈顶元素i;

       将两个栈消毁;

}EvaluateExpression函数结束

利用该算法对算术表达式3*(7-2)求值操作过程如下:

表一

4.4.调试分析与结果

附录一:测试数据

表二

按照附录中的测试数据,得出如下测试、分析结果:

当我们输入表格中两个正确的四则表达式时程序能准确地求得其值:

完全支持浮点数,正负数的运算;

而当我们输入第五组错误的表达式时,程序能做出正确判断,提醒用户输入的表达式错误。

其数据测试的情况见截图:

1

表达式一运算结果

2

表达式二运行结果

3

表达式三运行结果

4

表达式四运行结果

由表二可知以上四组表达式运行结果皆正确。

5

表达式五运行结果

由表二可知第五组表达式错误。


附录二:部分错误表达式

 表三

4.5:使用说明

运行程序,首先出现主菜单。主菜单包括三个选项:选项a:表达式求解,选择该项可进行四则表达式的求解;选项b:清屏;选项c:退出程序,选择该项将退出程序。

5.总结:

这次课程设计让我更加了解了学到的C语言和数据结构。课程设计不仅要求对课本知识有较深刻的了解,同时要求程序设计者有较强的思维和动手能力同时这也使我更加了解编程思想和编程技巧。

这次课程设计让我有一个深刻的体会,那就是细节决定成败,编程最需要的是严谨,如何的严谨都不过分,往往检查了半天发现错误发生在某个括号,分号,引号,或者数据类型上。就像我在写EvaluateExpression()函数时,忘了指针的地址符值不用加*,这一点小小的错误也耽误了我几十分钟,所以说细节很重要。

程序设计时,也不要怕遇到错误,在实际操作过程中犯的一些错误还会有意外的收获,感觉课程设计很有意思。在具体操作中这学期所学的数据结构的理论知识得到巩固,达到课程设计的基本目的,也发现自己的不足之出,在以后的上机中应更加注意。

6.附录三:源代码

//这个栈是用来存储数字字符的

#include<stdlib.h>

# include <stdio.h>

# include <string.h>

#define ERROR 0

#define OK 1

#define  TRUE 1

#define FALSE 0

typedef char ElemType;

typedef int Status;

typedef double ElementType;

typedef int Status;

# define STACK_INIT_SIZE 30

# define STACKINCREAMENT 10

# define NUMBER 30

typedef struct node{

    ElementType data;

    struct node *next;

}StackNode, *LinkStack;

void InitStack(LinkStack &head){

    head=(LinkStack)malloc(sizeof(StackNode));

       head->next=NULL;

}

Status IsEmpty(LinkStack head){

       if(head->next==NULL)return TRUE;

       else return ERROR;

}

Status Push(LinkStack &head,ElementType element){//入栈

       LinkStack p;

       p=(LinkStack)malloc(sizeof(StackNode));

       if(p== NULL) return FALSE;

       p->data=element;

       p->next=head->next;

       head->next=p;

       return OK;

}

Status Pop(LinkStack &head,ElementType &element){//出栈

       if(IsEmpty(head))return FALSE;

       LinkStack temp=head->next;

    element=temp->data;

       head->next=temp->next;

       free(temp);

       return OK;

}

Status GetTop(LinkStack head, ElementType &element){

       if(head->next==NULL)

              return ERROR;

        element =head->next->data;

              return OK;

}

Status DestroyStack(LinkStack &head)

{

        LinkStack q;

        while(head)

        {

               q=head->next;

               free(head);

               head=q;

        }

        return TRUE;

}

//这个栈是用来存储符号字符的

typedef struct node1{

       ElemType data;

       struct node1 *next;

}StackCharNode,*LinkCharStack;

void CInitCharStack(LinkCharStack &head){

       head=(LinkCharStack)malloc(sizeof(StackCharNode));

       head->next=NULL;

}

Status CIsEmpty(LinkCharStack head){

       return (head->next==NULL)?TRUE:FALSE;

}

Status CPush(LinkCharStack &head,ElemType element){

       LinkCharStack temp=(LinkCharStack)malloc(sizeof(StackCharNode));

       if(!temp)return ERROR;

       temp->data=element;

       temp->next=head->next;

       head->next=temp;

       return TRUE;

}

Status CPop(LinkCharStack &head,ElemType &element){

       if(CIsEmpty(head))return FALSE;

       StackCharNode *temp=head->next;

       element=temp->data;

       head->next=temp->next;

       free(temp);

       return TRUE;

}

Status CGetTop(LinkCharStack head,ElemType &element){

       if(head->next!=NULL)

       {

              element=head->next->data;

              return TRUE;

       }

       element='#';

       return FALSE;

}

Status CDestroyStack(LinkCharStack &head){

       LinkCharStack q;

       while(head)

       {

              q=head->next;

              free(head);

              head=q;

       }

       return TRUE;

}

//判断ch是否为运算符

int Comop(char ch)

{

       switch(ch)

       {

              case '+':

              case '-':

              case '*':

              case '/':

              case '(':

              case ')':

              case '[':

              case ']':

              case '{':

              case '}':

              case '#':return 1;

              default:return 0;

       }

}//Comop


//比较两个运算符的优先级

char Precede(char ch,char c)//ch是栈顶字符,c 是表达式字符

{

       switch(ch)

       {

       case '+':

       case '-':

              if(c=='+'||c=='-'||c==')'||c=='#'||c==')'||c==']'||c=='}')return '>';

              if(c=='*'||c=='/'||c=='('||c=='['||c=='{')return '<';

       case '*':

       case '/':

              if(c=='+'||c=='-'||c=='*'||c=='/'||c==')'||c==']'||c=='}'||c=='#')return '>';

              if(c=='('||c=='['||c=='{')return '<';

       case '(':

              if(c=='+'||c=='-'||c=='*'||c=='/')return '<';

              if(c==')')return '=';

       case ')':

              if(c=='+'||c=='-'||c=='*'||c=='/'||c==']')return '>';

              if(c=='#')return '>';

       case'[':

              if(c=='+'||c=='-'||c=='*'||c=='/'||c=='(')return '<';

              if(c==']')return '=';

       case']':

              if(c=='+'||c=='-'||c=='*'||c=='/'||c=='}')return '>';

              if(c=='#')return '>';

    case'{':

              if(c=='+'||c=='-'||c=='*'||c=='/'||c=='('||c=='[')return '<';

              if(c=='}')return '=';

    case'}':

              if(c=='+'||c=='-'||c=='*'||c=='/')return '>';

              if(c=='#')return '>';

       case '#':

              if(c=='+'||c=='-'||c=='*'||c=='/'||c=='('||c=='['||c=='{')return '<';

              if(c=='#')return '=';

       default:

              return '$';

       }

}//precede

//运算函数

ElementType Operate(ElementType a,char ch,ElementType b)

{

       switch(ch)

       {

       case '+':return a+b;

       case '-':return a-b;

       case '*':return a*b;

       case '/':

              if(b==0)

              {

                     return -32767;

              }

              return a/b;

       default:

              return -32767;

       }

}//Operate


//错误提示函数

int error(char *str) 

 {int i=0;

 while(str[i]!='#') //主要通过判断所有输入的字符数组str[30]

 {

 if( (

     (str[i]=='+'||str[i]=='-'||str[i]=='*'||str[i]=='/'||str[i]=='.') 

     &&        //其它函数只要一声明err=1也就说明输入有误

     (str[i+1]==')'||str[i+1]==']'||str[i+1]=='}')

       )

     ||(

        (str[i]=='+'||str[i]=='*'||str[i]=='/'||str[i]=='.')

     &&

     (str[i-1]=='('||str[i-1]=='['||str[i-1]=='{')

       )

     ||(

           (str[i]==')' || str[i]==']'||str[i]=='}')&& str[i+1]=='.'

          )

     ||(

            str[i]=='.' &&( str[i+1]=='('||str[i+1]=='['||str[i+1]=='{')

          )

     ||(str[i]==')' && str[i+1]=='(')

     ||(str[i]=='(' && str[i+1]==')')

        ||(str[i]=='[' && str[i+1]==']')

     ||(str[i]==']' && str[i+1]=='[')

     ||(str[i]=='{' && str[i+1]=='}')

     ||(str[i]=='}' && str[i+1]=='{')

        ||(

           (str[i]==')'||str[i]==']'||str[i]=='}') && str[i+1]>='0'&&str[i+1]<='9'

          )

        ||(

           (str[i]>='0'&&str[i]<='9'&& (str[i+1]=='('||str[i+1]=='['||str[i+1]=='{')

          )

     ||(str[0]=='+'||str[0]=='*'||str[0]=='/'||str[0]==')'||str[0]==']'||str[0]=='}')                               

     ||(

        (str[i]=='+'||str[i]=='-'||str[i]=='*'||str[i]=='/'||str[i]=='.') 

         &&

        (str[i+1]=='+'||str[i+1]=='-'||str[i+1]=='*'||str[i+1]=='/'||str[i+1]=='.')

          )

  

     ||(int(str[i])>57&&(int(str[i])!=91 && int(str[i])!=93 && int(str[i])!=123 && int(str[i])!=125))

     ||(str[i]=='/' && str[i+1]=='0')

     ||(int(str[i])>31 && int(str[i])<38)

    )

   )

     return 1;

    else if(str[i]=='#')return 0;

   i++;

 }//while

  return 0;

}//错误提示函数

//表达式计算函数

ElementType EvaluateExpression(char *exp){

       char c,ch;      //c代表输入表达式中的字符,ch代表栈顶运算符

       char *p,*q,*temp;//temp指向运算符后面的一个字符

       double i=0,a=0,b=0;

       p=q=exp;

       LinkCharStack OPF;//运算符栈

       LinkStack OPS;//操作数栈

       CInitCharStack(OPF);CPush(OPF,'#');

       InitStack(OPS);

       c=*p;temp=p;p++;

       if(c=='-')

       {

              c=*p;temp=p;p++;

       }

       while(c!='#'||!CIsEmpty(OPF))   //栈不为空或表达式没有结束

       {//*********************进入最外层循环*********************

              if(!Comop(c))//不是运算符则解析数字字符串然后进操作数栈

              {

                     double m=0,n=0;

                     while(c!='.'&&c>='0'&&c<='9')

                     {//解析整数部分

                            m=m*10+(c-48);

                            c=*p;

                            p++;

                     }

                     if(c=='.')

                     {//解析小数部分

                            c=*p;

                            while(c>='0'&&c<='9')

                            {p++;c=*p;}

                            q=p;

                            p--;

                            while(*p!='.')

                            {

                                   n=n/10+(*p-48)/10.0;

                                   p--;

                            }

                            p=q;

                            p++;

                     }           

              if(*(temp-2)=='('&&*(temp-1)=='-'||temp-1==exp)

                     Push(OPS,-(m+n));

              else

                     Push(OPS,m+n);

              }//*****数字进栈结束******

              else//是运算符时则进栈OPF

              {

                     if(c=='-'&&*(p-2)=='(')

                     {

                            c=*p;

                            temp=p;

                            p++;

                     }

                     else//else1

                     {

                            CGetTop(OPF,ch);

                            switch(Precede(ch,c))

                            {

                            case '<'://栈顶运算符优先权低

                                   CPush(OPF,c);c=*p;temp=p;p++;break;

                            case '>'://栈顶运算符优先权高

                                   CPop(OPF,ch);

                                   Pop(OPS,b);Pop(OPS,a);

                                   Push(OPS,Operate(a,ch,b));break;

                            case '='://脱括号并接收下一个字符

                                   CPop(OPF,ch);c=*p;temp=p;p++;break;

                            default:

                                   c=*p;temp=p;p++;

                            }//switch

                     }//else1

              }//else2

       }//退出最外层循环

       GetTop(OPS,i);

       DestroyStack(OPS);

       CDestroyStack(OPF);

       return i;

}//EvaluateExpression函数结束

//菜单函数

void MenuPrint()

{

        printf("\t\t┌─────────┐\n");

        printf("\t\t│多功能计算器 │\n");

        printf("\t\t├(a)表达式求解│\n");

        printf("\t\t├(b)清屏      │\n");

        printf("\t\t├(c)退出      │\n");

        printf("\t\t└─────────┘\n");

       } //菜单函数

//清屏函数

void Clear()

{  system("cls");

   MenuPrint();

}//清屏函数

//main主函数

void main()

{

       double result=0;

       char exp[NUMBER],c;

    freopen("DS1.in", "r", stdin);

    freopen("DS1.out", "w", stdout);

    Clear();

       printf("\t\t请输入你要进行的操作:\n");

       while(1)

       {

              scanf("%c",&c);

              switch(c)

              {  case 'a':

                            Clear();

                            sr:

                            printf("输入要计算的表达式,以##结束\n");

                            scanf("%s",exp); 

                            if(!error(exp))

                            {  result=EvaluateExpression(exp);

                                   printf("计算结果为:%lf\n",result);

                                   printf("请根据屏幕提示选择要进行的操作:\n");

                                   scanf("%d",&c);

                                   break;

                            }

                            else if(error(exp))

                                   {printf("您输入的表达式有误!");

                     goto sr;

                                   }

                           

                     case 'b':Clear();

               printf("\t\t请输入你要进行的操作:");

                             scanf("%d",&c);break;

                             break;

                     case 'c':system("cls");exit(1);

                     default:printf("输入有误!");                     

              }//switch

       }//while

}//main

更多相关推荐:
数据结构课程设计总结

课程设计说明书课程名:《数据结构课程设计》题目:一元多项式运算系统20##年1月一、课程认识数据结构课程主要是研究非数值计算的程序设计问题中所出现的计算机操作对象以及它们之间的关系和操作的学科。数据结构是介于数…

数据结构课程设计心得体会

程序设计心得体会做了一个星期的程序设计终于做完了,在这次程序设计课中,真是让我获益匪浅,我突然发现写程序还挺有意思的。由于上学期的C语言跟这学期的数据结构都算不上真正的懂,对于书上的稍微难点的知识就是是而非的,…

《数据结构课程设计报告》

安徽省巢湖学院计算机与信息工程学院课程设计报告课程名称课题名称用三元组实现稀疏矩阵的转置相加相乘专业计算机科学与技术班级学号AA姓名AAA联系方式136XXXXXXXX指导教师武彬20年月日目录1数据结构课程设...

数据结构课程设计总结

课程设计总结一周的课程设计结束了,在这次的课程设计中不仅检验了我所学习的知识,也培养了我如何去把握一件事情,如何去做一件事情,又如何完成一件事情的方法和技巧。在设计过程中,和同学们相互探讨,相互学习,相互监督。…

数据结构课程设计报告(含代码)

西安郵電學院数据结构课程设计报告题目校园导航系统院系名称计算机学院专业名称计算机科学与技术班级学生姓名学号8位指导教师设计起止时间20xx年12月11日20xx年12月15日一设计目的1通过本次课程设计巩固数据...

数据结构课程设计报告

CENTRALSOUTHUNIVERSITY数据结构课程设计报告题目学生姓名指导教师学院专业班级完成时间交通旅游图的最短路径问题摘要数据结构主要是一门研究非数值计算的程序设计问题中的计算机操作对象以及它们之间的...

数据结构课程设计总结 (1)

《程序设计与数据结构》综合课程设计论文题目:程序设计与数据结构综合课程设计专业:计算机科学与技术班级:N计科12-1F姓名:学号:指导老师:一、课程认识数据结构课程主要是研究非数值计算的程序设计问题中所出现的计…

数据结构课程设计报告-关键路径

数据结构课程设计报告学院计算机与通信工程专业网络工程班级学号学生姓名指导教师课程成绩完成日期20xx年2月27日数据结构程序设计学院计算机与通信工程学院专业网络工程班级学号学生姓名指导教师完成日期20xx年2月...

数据结构课程设计报告

淮阴工学院数据结构课程设计报告选题名称无向图应用问题系院计算机工程学院专业计算机科学与技术班级网络1111姓名1111311105指导教师周海岩单劲松学年学期20xx20xx学年第1学期年1设计任务书2摘要本课...

数据结构课程设计——报告(样例)

数据结构与算法课程设计报告王婧龚丹宋毅编写题目航空订票管理系统学期20xx秋班号学号姓名成绩哈尔滨华德学院电子与信息工程学院20xx年12月一实训设计的目的与要求注正文为宋体五号字为单倍行距一课程设计目的不少于...

厦门理工 数据结构课程设计报告2

《数据结构与算法》课程设计报告(20##20##学年第1学期)专业:网络工程班级:11网络工程姓名学号:指导教师:成绩:计算机科学与技术系目录一.课程设计目的与要求11.设计目的12.设计任务及要求1二.方案实…

迷宫求解数据结构课程设计报告

数据结构课程设计数据结构课程设计报告课题名称迷宫求解姓名马兆瑞学号20xx03021071专业电子信息科学与技术班级信息092班指导教师侯瑞莲数据结构课程设计目录第一部分引言3第二部分课程设计报告3第一章课程设...

数据结构课程设计总结(48篇)