数据结构课程设计预习报告

项目1:中国计算机设计大赛赛事统计

1、问题分析和任务定义

【问题描述】

  参加计算机设计大赛的n个学校编号为1~n,赛事分成m个项目,项目的编号为1~m.比赛获奖按照得分降序,取前三名,写一个统计程序产生各种成绩单和得分报表。

【基本要求】

1)每个比赛项目至少有10支参赛队;每个学校最多有6支队伍参赛;

2)能统计各学校的总分;

3)可以按照学校编号或名称,学校的总分、各项目的总分排序输出;

4)可以按学校编号查询学校某个项目的获奖情况;可以按项目编号查询取得前三名的学校;

5)数据存入文件并能随时查询

  1. 数据结构的选择和概要设计

学校定义为一个结构体类型,

typedef struct

{

int schnum, i;//学校的编号

int teamnum[6];//每个学校六个参赛队

int score[6];//学校六个项目得分

int summscore;

}school;//学校记录类型

顺序表中存放学校数组和长度:

struct List

{

school r[10];

int length;

};

还有对顺序表进行排序的void InsertSort(List& L)函数和打印顺序表void print(List L)函数。

流程图:

 

项目2:校园导游咨询

要求:

设计一个校园导游程序,为来访的客人提供各种信息查询服务。

(1)设计你所在学校的校园平面图,所含景点不少于10个.以图中顶点表示校内各景点,存放景点名称、代号、简介  等信息;以边表示路径,存放路径长度等相关信息。

  1. 为来访客人提供图中任意景点相关信息的查询。
  2. 为来访客人提供图中任意景点的问路查询,即查询任意两个景点之间的一条最短的简单路径。

思路:本次程序设计中对于图的存储采用的是邻接矩阵,其实就是二维数组。查询路径采用的则是弗洛伊德算法,其中对于所求的路径地点名采用的是三元组的形式,第一个数表示始点,第二个表示终点,第三个表示中间经过的点的下标。

本程序中包含5个模块

(1)主函数:int main();

(2)主界面函数:mainjiemian();

(3)显示地图信息:map();

(4)求取最短路径的算法:ShortestPath();

(5)退出函数:exit();

3.元素类型、结点类型和指针类型

    #define MX65535            //最大值 无穷

    #defineNUM  10             //最大顶点个数

    typedef intadjmatrix[NUM][NUM];

    typedef intpath[NUM][NUM][NUM];

    typedefstruct

    {   int vex;              /*顶点号*/

         string name;          /*景点名字*/

         string jieshao;       /*景点简介*/

     }Vertex;

项目3:算术表达式求解

  1. 问题分析和任务定义

设计一个简单的算术表达式计算器。实现标准整数类型的四则运算表达式的求值(包含括号,可多层嵌入)。

  1. 数据结构的选择和概要设计

模拟计算器程序主要利用了“栈”这种数据结构来把中缀表达式转化为后缀表达式,并且运用了递归的思想来解决Abs()和Sqrt()中嵌套表达式的问题,其中还有一些统计的思想来判定表达式是否合法的算法

  1. 详细设计和编码

本设计需要考虑许多的问题,首先是表达式的合法判断,然后是字符串表达式提取分离的问题,核心部分就是中缀表达式转化为后缀表达式。对于第一个问题,我是分步来判断,首先表达式中是否含有其它非法字符,然后判断括号是否合法,接着判断运算法两边是否合法,比如除法时,除数不能为零。对于第二个问题,我是直接转换的,从左到右遍历中缀表达式,把数据全部取出来。对于核心问题,利用了“栈”这种“后进先出”的数据结构,利用两个“栈”,一个“数据栈”,一个“运算符栈”来把中缀表达式转换成后缀表达式。最后利用后缀表达式来求解表达式的值。

3.1 表达式的合法判定

表达式的合法判定过程如图所示:

首先是其它字符的判定,从左到右遍历中缀表达式,看是否存在其它非法的。

然后是判定括号是否的匹配是否和合法,首先把“(”对应为1,相应的“)”对应为-1。从左到右遍历表达式,如果遇到括号就加上其对应的值,用sum来保存其累加值。如果在中途出现sum小于零的情况,即出现“..... )” 那么的情况,即非法。在遍历的最后,还要判断sum的值是否为零,如果为零就是合法,否则就是非法。代码如下:

    for(i=0;i<s.length();i++){  //检验括号是否合法,以及是否存在非法字符

        if(!IsNum(s[i]) && !IsSign(s[i]) && s[i]!='('

            && s[i]!=')' && s[i]!='A' && s[i]!='S' && s[i]!='.')return false;

        if(s[i]=='(')sum+=1;

        else if(s[i]==')')sum-=1;

        if(sum<0)return false;  //括号匹配不合法

}

运算符判断是否合法,也是遍历一遍表达式,遇到“/”,看其后面的除数是否为零。这里要考虑表达式中出现负数的情况,因此特殊考虑“-”号,判断它的前面是“(”还是没有字符了,那么就是负数。

中缀表达式转化为后缀表达式

中缀表达式转化为后缀表达式,利用两个“栈”,一个“数据栈”,一个“运算符栈”来把中缀表达式转换成后缀表达式。最后利用后缀表达式来求解表达式的值。设一个stack存后缀数据,一个rout栈存运算符。

算法流程如下:

(1)从右向左依次取得数据ch。

(2)如果ch是操作数,直接加进stack中。

(3)如果ch是运算符(含左右括号),则:

     a:如果ch = '(',放入堆栈rout中。

     b:如果ch = ')',依次输出堆栈rout中的运算符,直到遇到'('为止。

     c:如果ch不是')'或者'(',那么就和堆栈rout顶点位置的运算符top做优先级比较。

          1:如果ch优先级比rtop高,那么将ch放入堆栈rout。

          2:如果ch优先级低于或者等于rtop,那么输出top到stack中(直到!top或者满足 1),然后将ch放入堆栈rout。

 可以看出算法复杂度是O(n)的,因此效率是比较高的,能够在1s内处理百万级别长度的表达式。算法的主要思想是利用“栈”的后进先出的特性,以及运算符的优先级,这里我们定义运算符的优先级;代码如下:

int GetKey(char c){  //定义运算符的关键字

    int key;

    switch(c){

        case '+':key=1;break;

        case '-':key=1;break;

        case '*':key=2;break;

        case '/':key=2;break;

        case '(':key=4;break;

        case ')':key=5;break;

    }

    return key;

}

中缀转化为后缀处理的核心代码如下:

 /* 双栈,sta1存放后缀表达式,sta2存放运算符符号*/

    stack<pair<double,int> > sta1,sta2;

    for(i=0;i<k;i++){

        if(!num[i].second)sta1.push(num[i]);  //为数据,直接放入sta1

        else if(num[i].second==4)sta2.push(num[i]); //为'(',直接放入sta2

/* 为')',从sta2中取出运算符,push到sta1中,直到遇到')' */

        else if(num[i].second==5){              

while(sta2.top().second!=4){

                sta1.push(sta2.top());

                sta2.pop();

            }sta2.pop();  //取出'('括号

        }

        /*为'+','-','*'或者'/'运算符,取出sta2中的运算符,

        push到sta1中,直到比sta2栈顶中的优先级大*/

        else {

            while(!sta2.empty() && sta2.top().second>=num[i].second && sta2.top().second!=4){

                sta1.push(sta2.top());

                sta2.pop();

            }

            sta2.push(num[i]);  //放入当前运算符

        }

    }

最后,后缀表达式就存放在sta1栈中,把sta1栈中的结果存放到SufExp中就得到了后缀表达式。

处理后缀表达式

这里也是运用“栈”来处理,运用栈模板在求值过程顺序扫描后缀表达式,每次遇到操作数便将它压入堆栈;遇到运算符,则从栈中弹出两个操作数进行计算,然后再把结果压入堆栈,等到扫描结束时,则表达式的结果就求出来了。算法流程如图所示:

                     

处理后缀表达式流程

核心代码如下:

double Expression::GetAns()

{

    int i;

    double temp,num1,num2;  //num1和num2为运算符两遍的操作数

    stack<double> sta;   //数据栈

    for(i=0;i<Size;i++){

        if(!SufExp[i].second){   //为数据

            sta.push(SufExp[i].first);

        }

        else {   //为运算符

            num1=sta.top();   //取出第一个操作数

            sta.pop();

            num2=sta.top();    //取出第二个操作数

            sta.pop();

            temp=Cal((char)SufExp[i].first,num2,num1);

            sta.push(temp);   //放入操作数结果

        }

    }

    Ans=sta.top();

    return Ans;   //返回最终结果

}

 表达式嵌套处理

如果遇到A()和S()中含有表达式,而不是单纯的数字,例如A(1.1+3.4*S(2.5)),那么就需要对其字表达式“1.1+3.4*S(2.5)”进行递归处理,这个子表达式中还含有子表达式“2.5”,然后再递归处理,依次类推下去。其核心代码如下:

  if(s[i]=='A' || s[i]=='S'){  //遇到Abs()或者Sqrt()递归处理子表达式

       Expression temp;   //创建子表达式

       temp.Init();

       for(j=0;i+j+2<Pos[i+1];j++) //复制表达式

            st[j]=s[i+j+2];

       st[j]=0;

       temp.s=st;   //复制表达式

       temp.SloveExp();    //得到子表达式的值

       num[k].first=(s[i]=='A'?fabs(temp.Ans):sqrt(temp.Ans));

       num[k].second=0;   //标记为数据

       if(s[i-1]=='-' && (i-1==0 || s[i-2]=='('))num[k].first=-num[k].first;

       k++,i=Pos[i+1];

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值