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

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

问题描述

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

基本要求

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

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

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

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

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

设计要求

1)输入数据形式和范围:可以输入学校的名称,赛事项目的名称;

2)输出形式:有中文提示,各学校分数为整数;

3)界面要求:交互设计要合理,每个功能可以设立菜单,根据提示,可以完成相关功能的要求;

4)存储结构:学生自己根据系统功能要求自己设计,但是赛事相关数据要存储在文件中。

测试数据

要求使用全部合法数据,整体非法数据,局部非法数据。进行程序测试,以保证程序的稳定。

实现提示

假设3<赛事项目数量<=10,学校名称长度不超过20个字符。每个赛事结束时,将其编号、名称输入,并依次输入参赛学校编号、学校名称和成绩。

问题分析和任务定义

1)赛事情况的录入;

2)统计赛事情况;

3)针对某学校所参与赛事的统计和查询;

4)针对某赛事对报名学校的统计和查询;

5)根据得分实现对学校的排序;

6)根据赛事得分对赛事的排序;

7)查询某学校的某赛事的参赛情况;

8)查询得分排名前三的学校;

9)数据存入文件随时读取查询。

逻辑设计

1)创建Match(赛事)、school(学校)和Team(参赛队)pojo类;

2)根据多对一或一对多关系设计属性;

     ①Match

public class Match {
    private int MID;  //比赛编号
    private String MName;  //比赛名称
    private int MScores;  //比赛总分
    private List<Team> MTeams=new ArrayList<>();  //比赛所有的参赛队伍
    private List<School> MSchools=new ArrayList<>();  //参加按此比赛的所有学校

    public Match() {
    }

    public Match(int MID, String MName) {
        this.MID = MID;
        this.MName = MName;
    }

    public Match(int MID, String MName, int MScores, List<Team> MTeams, List<School> MSchools) {
        this.MID = MID;
        this.MName = MName;
        this.MScores = MScores;
        this.MTeams = MTeams;
        this.MSchools = MSchools;
    }

    public int getMID() {
        return MID;
    }

    public void setMID(int MID) {
        this.MID = MID;
    }

    public String getMName() {
        return MName;
    }

    public void setMName(String MName) {
        this.MName = MName;
    }

    public int getMScores() {
        int scores=0;
        for (Team team: getMTeams()) {
            scores+=team.getTScore();
        }
        setMScores(scores);
        return MScores;
    }

    public void setMScores(int MScores) {
        this.MScores=MScores;
    }

    public List<Team> getMTeams() {
        return MTeams;
    }

    public void setMTeams(List<Team> MTeams) {
        this.MTeams = MTeams;
    }

    public List<School> getMSchools() {
        return MSchools;
    }

    public void setMSchools(List<School> MSchools) {
        this.MSchools = MSchools;
    }

    public void setMTeams(Team team) {
        MTeams.add(team);
    }

    public void setMSchools(School school) {
        MSchools.add(school);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Match)) return false;
        Match match = (Match) o;
        return getMID() == match.getMID();
    }

    @Override
    public int hashCode() {
        return Objects.hash(getMID());
    }
}

②School

public class School {
    private int SID;  //学校编号
    private String SName;  //学校名称
    private int SScores;  //学校总分
    private List<Team> STeams=new ArrayList<>();  //学校所有队伍
    private List<Match> SMatches=new ArrayList<>();  //学校参加的比赛

    public School() {
    }

    public School(int SID, String SName) {
        this.SID = SID;
        this.SName = SName;
    }

    public int getSID() {
        return SID;
    }

    public void setSID(int SID) {
        this.SID = SID;
    }

    public String getSName() {
        return SName;
    }

    public void setSName(String SName) {
        this.SName = SName;
    }

    public int getSScores() {
        int scores=0;
        for (Team team: getSTeams()) {
            scores+=team.getTScore();
        }
        setSScores(scores);
        return SScores;
    }

    public void setSScores(int SScores) {
        this.SScores=SScores;
    }

    public List<Team> getSTeams() {
        return STeams;
    }

    public void setSTeams(List<Team> STeams) {
        this.STeams = STeams;
    }

    public List<Match> getSMatches() {
        return SMatches;
    }

    public void setSMatches(List<Match> SMatches) {
        this.SMatches = SMatches;
    }

    public void setSTeams(Team team) {
        STeams.add(team);
    }

    public void setSMatches(Match match) {
        SMatches.add(match);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof School)) return false;
        School school = (School) o;
        return getSID() == school.getSID();
    }

    @Override
    public int hashCode() {
        return Objects.hash(getSID());
    }
}

③Team

public class Team {
    private int TID;  //团队编号
    private String TName;  //团队名称
    private int TScore;  //团队得分
    private School TSchool;  //团队所属学校
    private Match TMatch;  //团队所报比赛

    public Team() {
    }

    public Team(int TID, String TName) {
        this.TID = TID;
        this.TName = TName;
    }

    public Team(int TID, String TName, int TScore, School TSchool,Match TMatch) {
        this.TID = TID;
        this.TName = TName;
        this.TScore=TScore;
        this.TSchool = TSchool;
        this.TMatch = TMatch;
    }

    public int getTID() {
        return TID;
    }

    public void setTID(int TID) {
        this.TID = TID;
    }

    public String getTName() {
        return TName;
    }

    public void setTName(String TName) {
        this.TName = TName;
    }

    public int getTScore() {
        return TScore;
    }

    public void setTScore(int TScore) {
        this.TScore = TScore;
    }

    public Match getTMatch() {
        return TMatch;
    }

    public void setTMatch(Match TMatch) {
        this.TMatch = TMatch;
    }

    public School getTSchool() {
        return TSchool;
    }

    public void setTSchool(School TSchool) {
        this.TSchool = TSchool;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Team)) return false;
        Team team = (Team) o;
        return getTID() == team.getTID();
    }

    @Override
    public int hashCode() {
        return Objects.hash(getTID());
    }
}

3)以查询模块作为主模块。

switch (in) {
    case 1 -> Methods.write();  //信息录入
    case 2 -> Methods.queryCompetitionBySID(schools);  //查询学校信息
    case 3 -> Methods.querySchoolByMID(matches);  //查询比赛信息
    case 4 -> Methods.sortSchool(schools);  //排序输出所有学校
    case 5 -> Methods.sortMatch(matches);  //排序输出所有比赛
    case 6 -> Methods.queryGivenCompetitionBySID(schools);  //查询某学校的某个项目
    case 7 -> Methods.topThreeOfSchools(matches);  //查询某个项目排名前三的学校
    }

物理设计

1)通过ArraryList类存储赛事和学校;

static List<School> schools = new ArrayList<>();
static List<Match> matches = new ArrayList<>();

2)涉及到java类库中List和ArraryList类的使用。

①.add 往ArraryList中添加数据

②.contain判断数据是否已存在ArraryList中,需添加pojo的equal方法

③.sort对ArraryList中数据排序,对于pojo对象需自定义比较器

程序编码

1)pojo类 见逻辑设计;

2)Method(方法)类。

public class Methods {

    static Scanner input = new Scanner(System.in);

    static Comparator<School> comparatorSchool = new Comparator<School>() {
        public int compare(School schoolA, School schoolB) {
            return schoolB.getSScores() - schoolA.getSScores();//根据优先权从小到大定义比较器
        }
    };

    static Comparator<Match> comparatorMatch = new Comparator<Match>() {
        public int compare(Match matchA, Match matchB) {
            return matchB.getMScores() - matchA.getMScores();//根据优先权从小到大定义比较器
        }
    };

    //信息录入
    public static void write() throws IOException {
        try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("E:\\新建文件夹\\数据结构课程设计\\Information\\test.txt", true))) {
            while (true) {  //是否继续添加学校
                System.out.println("请依次输入学校参赛队伍个数、学校编号及名称,中间用空格隔开:");
                String out = input.nextLine();
                char count, SID, space;
                while (true) {  //学校格式是否正确
                    while (true) //输入长度是否正确
                        if (out.length() > 3)
                            break;
                        else {
                            System.out.println("请正确依次输入学校参赛队伍个数、学校编号及名称,中间用空格隔开:");
                            out = input.nextLine();
                        }
                    count = out.charAt(0);
                    SID = out.charAt(2);
                    space = out.charAt(3);  //检查格式
                    if (count >= '0' && count <= '9' && SID >= '0' && SID <= '9' && space == ' ') {
                        bufferedWriter.write(out);
                        bufferedWriter.newLine();
                        break;
                    } else {
                        System.out.println("请正确依次输入学校参赛队伍个数、学校编号及名称,中间用空格隔开:");
                        out = input.nextLine();
                    }
                }
                char TIDFirst, TIDSecond, TScoreFirst, TScoreSecond, MID;
                for (int i = 0; i < count - '0'; i++) {
                    System.out.println("请输入第" + (i + 1) + "个该学校的各参赛队伍的编号、得分、名称、所参加赛事编号及名称,中间用空格隔开:");
                    out = input.nextLine();
                    while (true) {  //团队格式是否正确
                        while (true)  //团队信息长度是否正确
                            if (out.length() > 12)
                                break;
                            else {
                                System.out.println("请正确输入" + (i + 1) + "个该学校的各参赛队伍的编号、得分、名称、所参加赛事编号及名称,中间用空格隔开:");
                                out = input.nextLine();
                            }
                        TIDFirst = out.charAt(0);
                        TIDSecond = out.charAt(1);
                        TScoreFirst = out.charAt(3);
                        TScoreSecond = out.charAt(4);
                        MID = out.charAt(11);
                        space = out.charAt(12);
                        if (TIDFirst >= '0' && TIDFirst <= '9' && TIDSecond >= '0' && TIDSecond <= '9' && TScoreFirst >= '0' && TScoreFirst <= '9' && TScoreSecond >= '0' && TScoreSecond <= '9' && MID >= '0' && MID <= '9' && space == ' ') {
                            bufferedWriter.write(out);
                            bufferedWriter.newLine();
                            break;
                        } else {
                            System.out.println("请正确输入" + (i + 1) + "个该学校的各参赛队伍的编号、得分、名称、所参加赛事编号及名称,中间用空格隔开:");
                            out = input.nextLine();
                        }
                    }
                }
                bufferedWriter.flush();
                System.out.println("你还要继续添加学校吗?(y/是;n/结束)");
                char choice = input.nextLine().charAt(0);
                while (true) {  //输入选择是否正确
                    if (choice == 'y' || choice == 'n')
                        break;
                    else {
                        System.out.println("请选择正确的选项:");
                        choice = input.nextLine().charAt(0);
                    }
                }
                if (choice == 'n')
                    return;
            }
        }
    }

    //信息读取
    public static void read(List<School> schools, List<Match> matches) throws IOException {
        FileInputStream fis = new FileInputStream("E:\\新建文件夹\\数据结构课程设计\\Information\\School.txt");
        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fis))) {
            String myLine = null;
            List<String> myLines = new ArrayList<>();  //按行读出的行集合
            while ((myLine = bufferedReader.readLine()) != null) {
                myLines.add(myLine);
            }
            int SID, TID, MID, TScore, count;
            String SName, TName, MName;
            for (int i = 0; i < myLines.size(); ) {
                count = Character.getNumericValue(myLines.get(i).charAt(0));
                SID = Character.getNumericValue(myLines.get(i).charAt(2));
                SName = myLines.get(i).substring(4);
                School schoolOfList = new School(SID, SName);  //列表中添加的学校
                if (schools.contains(schoolOfList)) {  //是否有此学校
                    for (School tmp : schools) {
                        if (tmp.equals(schoolOfList)) {
                            schoolOfList = tmp;  //浅拷贝,对象复用
                            break;
                        }
                    }
                } else
                    schools.add(schoolOfList);  //添加新学校对象
                for (int j = i + 1; j <= i + count; j++) { //并不是二重循环
                    School schoolOfMatch = new School(SID, SName);  //报名此比赛的学校
                    TID = Integer.parseInt(myLines.get(j).substring(0, 2));
                    TScore = Integer.parseInt(myLines.get(j).substring(3, 5));
                    TName = myLines.get(j).substring(6, 10);
                    MID = Character.getNumericValue(myLines.get(j).charAt(11));
                    MName = myLines.get(j).substring(13);
                    Match matchOfList = new Match(MID, MName);  //列表中的比赛
                    if (matches.contains(matchOfList)) {
                        for (Match tmp : matches) {
                            if (matchOfList.equals(tmp))
                                matchOfList = tmp;
                        }
                    } else
                        matches.add(matchOfList);
                    Match matchOfSchool = new Match(MID, MName);  //此学校的比赛
                    Team team = new Team(TID, TName, TScore, schoolOfList, matchOfList);
                    schoolOfList.setSTeams(team);
                    matchOfList.setMTeams(team);
                    if (schoolOfList.getSMatches().contains(matchOfSchool)) {
                        for (Match tmp : schoolOfList.getSMatches()) {
                            if (matchOfSchool.equals(tmp)) {
                                matchOfSchool = tmp;
                                break;
                            }
                        }
                    } else
                        schoolOfList.setSMatches(matchOfSchool);
                    matchOfSchool.setMTeams(team);  //添加团队
                    if (matchOfList.getMSchools().contains(schoolOfMatch)) {
                        for (School tmp : matchOfList.getMSchools()) {
                            if (schoolOfMatch.equals(tmp)) {
                                schoolOfMatch = tmp;
                                break;
                            }
                        }
                    } else
                        matchOfList.setMSchools(schoolOfMatch);
                    schoolOfMatch.setSTeams(team);
                }
                i += count + 1;
            }
            fis.close();
        }
    }

    //查询学校信息
    public static void queryCompetitionBySID(List<School> schools) {
        System.out.println("请输入待查询学校的编号(1~" + schools.size() + ")或名称:");
        String information = input.nextLine();
        int SID = 0;
        if (information.length() < 3) {  //如果长度小于三,则视为用户传了编号
            while (true) {
                SID = Integer.parseInt(information);
                if (SID > 0 && SID < schools.size() + 1)
                    break;
                else {
                    System.out.println("请输入正确的学校编号(1~" + schools.size() + "):");
                    information = input.nextLine();
                }
            }
        }
        boolean mark = false;
        for (School school : schools) {
            if (school.getSID() == SID || school.getSName().equals(information)) {
                System.out.println("查询所得学校信息如下:");
                System.out.println("学校编号: " + school.getSID());
                System.out.println("学校名称: " + school.getSName());
                System.out.println("总分: " + school.getSScores());
                List<Match> tmp = new ArrayList<>(school.getSMatches());
                tmp.sort(comparatorMatch);
                System.out.println("学校所报赛事按总分从大到小排序如下:");
                for (Match match : tmp) {
                    System.out.println(match.getMID() + "  " + match.getMName() + "   " + match.getMScores());
                }
                mark = true;
                break;
            }
        }
        if (!mark)
            System.out.println("无此学校的相关信息!");
    }

    //查询比赛信息
    public static void querySchoolByMID(List<Match> matches) {
        System.out.println("请输入待查询项目的编号(1~" + matches.size() + ")或名称:");
        String information = input.nextLine();
        int MID = 0;
        if (information.length() < 3) {
            while (true) {
                MID = Integer.parseInt(information);
                if (MID > 0 && MID < matches.size() + 1)
                    break;
                else {
                    System.out.println("请输入正确的赛事编号(1~" + matches.size() + "):");
                    information = input.nextLine();
                }
            }
        }
        boolean mark = false;
        for (Match match : matches) {
            if (match.getMID() == MID || match.getMName().equals(information)) {
                System.out.println("查询所得比赛信息如下:");
                System.out.println("比赛编号: " + match.getMID());
                System.out.println("比赛名称: " + match.getMName());
                System.out.println("总分: " + match.getMScores());
                List<School> tmp = new ArrayList<>(match.getMSchools());
                tmp.sort(comparatorSchool);  //新列表中排序
                System.out.println("报名该赛事的学校按总分从大到小排序如下:");
                for (School school : tmp) {
                    System.out.println(school.getSID() + "  " + school.getSName() + "   " + school.getSScores());
                }
                mark = true;
                break;
            }
        }
        if (!mark)
            System.out.println("无此赛事的相关信息!");
    }

    //排序输出所有学校
    public static void sortSchool(List<School> schools) {
        List<School> tmp = new ArrayList<>(schools);
        tmp.sort(comparatorSchool);
        System.out.println("学校按总分从大到小排序如下:");
        for (School school : tmp) {
            System.out.println(school.getSID() + "  " + school.getSName() + "   " + school.getSScores());
        }
    }

    //排序输出所有比赛
    public static void sortMatch(List<Match> matches) {
        List<Match> tmp = new ArrayList<>(matches);
        tmp.sort(comparatorMatch);
        System.out.println("赛事按总分从大到小排序如下:");
        for (Match match : tmp) {
            System.out.println(match.getMID() + "  " + match.getMName() + "   " + match.getMScores());
        }
    }

    //查询某学校的某个项目
    public static void queryGivenCompetitionBySID(List<School> schools) {
        System.out.println("请输入待查询学校的编号(1~" + schools.size() + ")或名称:");
        String informationOfSchool = input.nextLine();
        int SID = 0;
        if (informationOfSchool.length() < 3) {
            while (true) {
                SID = Integer.parseInt(informationOfSchool);
                if (SID > 0 && SID < schools.size() + 1)
                    break;
                else {
                    System.out.println("请输入正确的学校编号(1~" + schools.size() + "):");
                    informationOfSchool = input.nextLine();
                }
            }
        }
        boolean markOfSchool = false;
        System.out.println("请输入待查询项目的编号(1~" + Implement.getMatchesSize() + ")或名称:");
        String informationOfMatch = input.nextLine();
        int MID = 0;
        if (informationOfMatch.length() < 3) {
            while (true) {
                MID = Integer.parseInt(informationOfMatch);
                if (MID > 0 && MID < Implement.getMatchesSize() + 1)
                    break;
                else {
                    System.out.println("请输入正确的赛事编号(1~" + Implement.getMatchesSize() + "):");
                    informationOfMatch = input.nextLine();
                }
            }
        }
        boolean markOfMatch = false;
        for (School school : schools) {
            if (school.getSID() == SID || school.getSName().equals(informationOfSchool)) {
                System.out.println("学校编号: " + school.getSID());
                System.out.println("学校名称: " + school.getSName());
                for (Match match : school.getSMatches()) {
                    if (match.getMID() == MID || match.getMName().equals(informationOfMatch)) {
                        System.out.println("赛事编号:  " + match.getMID());
                        System.out.println("赛事名称: " + match.getMName() + '\n' + "得分: " + match.getMScores());
                        System.out.println("参赛队伍情况如下:");
                        for (Team team : match.getMTeams()) {
                            System.out.println(team.getTID() + "   " + team.getTName() + "   " + team.getTScore());
                        }
                        markOfMatch = true;
                        break;
                    }
                }
                markOfSchool = true;
                break;
            }
        }
        if (!markOfSchool)
            System.out.println("无此学校的相关信息!");
        if (markOfSchool && !markOfMatch)
            System.out.println("无此赛事的相关信息!");
    }

    //查询某个项目排名前三的学校
    public static void topThreeOfSchools(List<Match> matches) {
        System.out.println("请输入待查询项目的编号(1~" + matches.size() + ")或名称:");
        String information = input.nextLine();
        int MID = 0;
        if (information.length() < 3) {
            while (true) {
                MID = Integer.parseInt(information);
                if (MID > 0 && MID < matches.size() + 1)
                    break;
                else {
                    System.out.println("请输入正确的赛事编号(1~" + matches.size() + "):");
                    information = input.nextLine();
                }
            }
        }
        boolean mark = false;
        for (Match match : matches) {
            if (match.getMID() == MID || match.getMName().equals(information)) {
                System.out.println("比赛名称: " + match.getMID());
                System.out.println("比赛名称: " + match.getMName());
                System.out.println("总分: " + match.getMScores());
                List<School> tmp = new ArrayList<>(match.getMSchools());
                tmp.sort(comparatorSchool);
                School school;
                System.out.println("报名该赛事的排名前三的学校如下:");
                for (int i = 0; i < 3; i++) {
                    school = tmp.get(i);
                    System.out.println(school.getSID() + "  " + school.getSName() + "   " + school.getSScores());
                }
                mark = true;
                break;
            }
        }
        if (!mark)
            System.out.println("无此赛事的相关信息!");
    }
}

3)Implement (主程序)类

public class Implement {
    static List<School> schools = new ArrayList<>();
    static List<Match> matches = new ArrayList<>();

    public static int getSchoolsSize(){
        return schools.size();
    }

    public static int getMatchesSize(){
        return matches.size();
    }

    public static void main(String[] args) throws IOException {
        Methods.read(schools, matches);
        Scanner input = new Scanner(System.in);
        while (true) {  //是否继续执行操作
            System.out.println("""
                                  计算机设计大赛智慧统计系统
                    ***************************************************
                    *                  操作及功能:                      *
                    *                  1.信息录入                       *
                    *                  2.学校查询                       * 
                    *                  3.赛事查询                       * 
                    *                  4.学校排序                       *
                    *                  5.赛事排序                       *
                    *                  6.获奖情况                       *
                    *                  7.前三查询                       *
                    *               学校编号及对应名称:                   *
                    *                1 江苏科技大学                      *
                    *                2 扬州大学                         *
                    *                3 南京大学                         *
                    *                4 南京邮电大学                      *
                    *                5 兰州大学                         *
                    *                6 西安电子科技大学                   *
                    *               赛事编号及对应名称:                   *
                    *                1 人工智能挑战赛                    *
                    *                2 物联网挑战赛                      *
                    *                3 软件应用与开发                    *
                    ***************************************************
                    请选择你想要执行的操作(输入对应操作的编号):""");
            int in = input.nextInt();
            while (true)
                if (in > 0 && in < 8)
                    break;
                else {
                    System.out.println("请正确输入你想要执行的操作(输入对应操作的编号):");
                    in = input.nextInt();
                }
            switch (in) {
                case 1 -> Methods.write();
                case 2 -> Methods.queryCompetitionBySID(schools);
                case 3 -> Methods.querySchoolByMID(matches);
                case 4 -> Methods.sortSchool(schools);
                case 5 -> Methods.sortMatch(matches);
                case 6 -> Methods.queryGivenCompetitionBySID(schools);
                case 7 -> Methods.topThreeOfSchools(matches);
            }
            System.out.println("你还要执行其他操作吗?(y/是;n/结束)");
            input.nextLine();
            char choice = input.nextLine().charAt(0);
            while (true)
                if (choice == 'y' || choice == 'n')
                    break;
                else {
                    System.out.println("请选择正确的选项(y/是;n/结束):");
                    choice = input.nextLine().charAt(0);
                }
            if (choice == 'n')
                return;
        }
    }
}

结果分析

1)函数调用关系图;

2)效果分析。

该程序可较准确地实现题设中具体要求,采用严格的面向对象的思想,pojo对象进行了高度封装,从文件中读取数据作为参数创建对象。具有很好的可扩展性,模块严格划分,程序耦合度较低。

程序容错性能较好,规范用户的输入形式,取得较好的运行效果。编程过程中用到对象复用等思想,大大提高了程序的效率,减小了时间复杂度和空间复杂度。


项目2:校园导游咨询 

问题描述

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

基本要求

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

2)  为来访客人提供图中任意景点相关信息的查询;

3) 为来访客人提供图中任意景点的问路查询,即查询任意两个景点之间的一条最短的简单路径。

测试数据

以江苏科技大学长山校区为例。

实现提示

一般情况下,校园的道路是双向通行的,可设校园平面图是一个无向网.顶点和边均含有相关信息。

问题分析和任务定义

1)设计学校景点平面无向图,确定景点和权重信息;

2)寻找两景点间的最短路径;

3)通过景点代号或名称查询某景点的具体信息。

逻辑设计

1)创建Attraction(景点)类和Graph(无向图)类;

2)根据设计需求实现必要的成员方法。

① Attraction

public class Attraction {
    private int ID;
    private String name;
    private String introduction;

    public Attraction() {
    }

    public Attraction(int ID, String name) {
        this.ID = ID;
        this.name = name;
    }

    public Attraction(int ID, String name, String introduction) {
        this.ID = ID;
        this.name = name;
        this.introduction = introduction;
    }

    public int getID() {
        return ID;
    }

    public void setID(int ID) {
        this.ID = ID;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getIntroduction() {
        return introduction;
    }

    public void setIntroduction(String introduction) {
        this.introduction = introduction;
    }
}

② Graph

public class Graph {
    static final int Max = 100;
    private Attraction[] vertex = new Attraction[100];
    private int[][] adj = new int[Max][Max];
    private int vertexNum;
    private int edgeNum;

    public Graph() {
        vertexNum = 0;
        edgeNum = 0;
    }

    public Graph(Attraction[] a, int n) {
        vertexNum = n - 1;
        edgeNum = 0;
        if (n - 1 >= 0)
            System.arraycopy(a, 1, vertex, 1, n - 1);
        for (int i = 1; i < n; i++)
            for (int j = 1; j < n; j++)
                if (i == j)
                    adj[i][j] = 0;
                else
                    adj[i][j] = 100000000;
    }

    public Graph(Attraction[] vertex, int[][] adj, int vertexNum, int edgeNum) {
        this.vertex = vertex;
        this.adj = adj;
        this.vertexNum = vertexNum;
        this.edgeNum = edgeNum;
    }

    public Attraction[] getVertex() {
        return vertex;
    }

    public void setVertex(Attraction[] vertex) {
        this.vertex = vertex;
    }

    public int[][] getAdj() {
        return adj;
    }

    public void setAdj(int[][] adj) {
        this.adj = adj;
    }

    public int getVertexNum() {
        return vertexNum;
    }

    public void setVertexNum(int vertexNum) {
        this.vertexNum = vertexNum;
    }

    public int getEdgeNum() {
        return edgeNum;
    }

    public void setEdgeNum(int edgeNum) {
        this.edgeNum = edgeNum;
    }

    public void insertEdge(int i, int j, int length) {
        adj[i][j] = adj[j][i] = length;
        edgeNum++;
    }

    public int weight(int i, int j) {
        return adj[i][j];
    }

    public Attraction vex(int i) {
        return vertex[i];
    }
}

物理设计

1)使用无向图的数据结构,以景点作为无向图的顶点,权重为两景点间的距离;

2)设计江苏科技大学长山校区景点无向图。

程序编码

1)pojo类 见逻辑设计;

2)Method(方法)类。

public class Method {
    static final int Max = 100;
    static Attraction[] attractions = new Attraction[13];
    static Scanner input = new Scanner(System.in);

    //通过景点信息和景点间的线路创建一个无向图
    public static Graph init() {

        String des1 = """
                北苑餐厅坐落在江苏科技大学长山校区北,靠近行政楼,菜品以炒菜为主,有一些特色主食,如面条水饺馄饨,味道鲜美的牛肉火锅等。           
                """;
        String des2 = """
                在海韵湖的柔波里,
                                
                我甘心做一只小船。
                                
                满载一船星光,
                                
                在星辉斑斓里放歌!
                                
                江科大海韵湖位于长山校区图书馆旁。湖面上有3只黑天鹅时而玩水,时而低飞,时而沐浴阳光小憩,自由自在,快活惬意。
                并且,它们的“素质”也很高,遇到靠近的老师同学不会转身飞走,只会优雅起立或者傲娇挪开。
                但是大家驻足观赏时要注意安全,一定要把“可远观而不可亵玩”这句话牢记心底,更不能有“抓住它吃掉”或者“铁锅炖大鹅”的想法哦。
                黑天鹅远道而来,作为热爱大自然的江科大人,我们应好好招待,展现江科大好客之道哦!
                """;
        String des3 = """
                长山校区图书馆于2020年9月搬迁至长山校区,现位于镇江市丹徒区长晖路666号,毗邻湖畔,环境优美,
                全馆建筑面积32200平方米,设有11个阅览室、4个研讨间,可提供自习座位5500余个。图书馆下设梦溪校区分馆,位于镇江市京口区梦溪路2号,馆舍面积10578平方米,1988年9月启用。
                """;
        String des4 = """
                沧桑巨变、风雨兼程。伴随着中国进入社会主义新时代的伟大进程,承蒙各级领导和社会各界的殷切关怀和鼎力支持,江苏科技大学计算机学院走过了一段光辉的历史,硕果累累。
                学院全体师生以自己的卓越智慧和不懈努力,植根于科大深厚的“船魂”精神,奋力前行。
                奉献、创新、突破、发展,学院人才培养质量、大学生科技创新、学科持续竞争力、社会服务能力和国际影响力逐步提升,谱写了学院发展史上的动人诗篇。
                伴随着“互联网+”时代的到来,我们将秉承“笃学明德、经世致用”校训,紧紧把握国家经济、社会发展和科技进步的要求,
                围绕学校“建设一流造船大学”的奋斗目标和信息技术发展的重大战略需求,为建设特色鲜明的学院而努力奋斗!
                """;
        String des5 = """
                东苑食堂二楼的红烧牛肉刀削面,
                                
                面条劲道Q弹,汤底浓郁,鲜香爽滑,
                                
                搭配大块的牛肉,香味扑鼻,
                                
                一碗热气腾腾的面是对秋冬最好的慰藉。
                """;
        String des6 = """
                文理大楼为江科大最高建筑,是江科大的地标性建筑,信息化教室与实验室完备。
                """;
        String des7 = """
                笃学楼位于图书馆旁边,内设上百间座位数达120位的大教室!
                """;
        String des8 = """
                经世楼位于明德楼旁边,教室较小,适合人数较少的班级开展教学。
                """;
        String des9 = """
                明德楼离西苑餐厅较近,晚上经常有科大学子前往自习。
                """;
        String des10 = """
                七号组团为计算机学院女生住所。
                """;
        String des11 = """
                三号组团为计算机学院男生住所。
                """;
        String des12 = """
                三号组团为计算机学院男生住所。
                """;
        Attraction att1 = new Attraction(1, "北苑食堂", des1);
        Attraction att2 = new Attraction(2, "海韵湖", des2);
        Attraction att3 = new Attraction(3, "图书馆", des3);
        Attraction att4 = new Attraction(4, "计算机学院楼", des4);
        Attraction att5 = new Attraction(5, "东苑食堂", des5);
        Attraction att6 = new Attraction(6, "文理大楼", des6);
        Attraction att7 = new Attraction(7, "笃学楼", des7);
        Attraction att8 = new Attraction(8, "经世楼", des8);
        Attraction att9 = new Attraction(9, "明德楼", des9);
        Attraction att10 = new Attraction(10, "七号组团", des10);
        Attraction att11 = new Attraction(11, "西苑食堂", des11);
        Attraction att12 = new Attraction(12, "三号组团", des12);
        attractions[1] = att1;
        attractions[2] = att2;
        attractions[3] = att3;
        attractions[4] = att4;
        attractions[5] = att5;
        attractions[6] = att6;
        attractions[7] = att7;
        attractions[8] = att8;
        attractions[9] = att9;
        attractions[10] = att10;
        attractions[11] = att11;
        attractions[12] = att12;
        Graph graph = new Graph(attractions, 13);
        graph.insertEdge(1, 2, 450);
        graph.insertEdge(1, 4, 990);
        graph.insertEdge(2, 3, 500);
        graph.insertEdge(3, 5, 400);
        graph.insertEdge(3, 6, 700);
        graph.insertEdge(3, 7, 550);
        graph.insertEdge(4, 6, 500);
        graph.insertEdge(4, 8, 600);
        graph.insertEdge(5, 7, 300);
        graph.insertEdge(6, 8, 400);
        graph.insertEdge(6, 9, 450);
        graph.insertEdge(7, 11, 650);
        graph.insertEdge(8, 9, 200);
        graph.insertEdge(9, 10, 480);
        graph.insertEdge(10, 11, 220);
        graph.insertEdge(10, 12, 600);
        graph.insertEdge(11, 12, 480);
        return graph;
    }
    /*
    * 求无向图中顶点v到其他顶点的最短路径
    * dist[i]为顶点i到顶点v的最短路径长度
    * path[i]为顶点i到顶点v最短路径中i的前驱顶点,通过迭代可求出整个最短路径
    * s[i]==1表示已找到该顶点i到顶点v的最短路径
    * */
    public static void Dijkstra(Graph graph, int v, int[] dist, int[] path) {
        int k, min, n = graph.getVertexNum() + 1;
        int[] s = new int[Max];
        for (int i = 1; i < n; i++) {
            dist[i] = graph.weight(v, i);
            if (dist[i] != 100000000)  //权重(长度)为100000000表示两点不连通
                path[i] = v;
            else path[i] = -1;
        }
        s[v] = 1;
        dist[v] = 0;
        int num = 2;
        path[v] = -1;

        while (num < n) {
            k = 1;
            min = 100000000;
            for (int i = 1; i < n; i++) //找下一个到顶点v路径最短的顶点k
                if (dist[i] < min && s[i] != 1) {
                    min = dist[i];
                    k = i;
                }
            s[k] = 1;
            for (int i = 1; i < n; i++)
                if (dist[i] > dist[k] + graph.weight(k, i)) {  //直达距离大于新距离,更新最短路径长度
                    dist[i] = dist[k] + graph.weight(k, i);
                    path[i] = k;
                }
            num++;
        }
    }

    //寻找最短路径
    public static void wayFinding() {
        Graph graph = init();
        int vi = 0;
        while (true) { //是否继续寻找
            //控制正确输入格式,并找到待查询景点的代号
            while (true) {
                System.out.println("请输入起点的名称或编号(1~12):");
                String information = input.nextLine();
                boolean mark = false;
                if (information.length() < 3) {
                    while (true) {
                        vi = Integer.parseInt(information);
                        if (vi > 0 && vi < 13) {
                            mark = true;
                            break;
                        } else {
                            System.out.println("请输入正确的景点编号(1~12):");
                            information = input.nextLine();
                        }
                    }
                } else
                    for (int i = 1; i < 13; i++)
                        if (attractions[i].getName().equals(information)) {
                            vi = i;
                            mark = true;
                            break;
                        }
                if (!mark)
                    System.out.println("未找到此景点!");
                else
                    break;
            }
            int vj = 0;
            while (true) {
                System.out.println("请输入终点的名称或编号(1~12):");
                String information = input.nextLine();
                boolean mark = false;
                if (information.length() < 3) {
                    while (true) {
                        vj = Integer.parseInt(information);
                        if (vj > 0 && vj < 13) {
                            mark = true;
                            break;
                        } else {
                            System.out.println("请输入正确的景点编号(1~12):");
                            information = input.nextLine();
                        }
                    }
                } else
                    for (int i = 1; i < 13; i++)
                        if (attractions[i].getName().equals(information)) {
                            vj = i;
                            mark = true;
                            break;
                        }
                if (!mark)
                    System.out.println("未找到此景点!");
                else if (vi == vj)
                    System.out.println("起点与终点相同!");
                else
                    break;

            }

            //通过Dijkstra更新path和dist数组,里面存储最短路径长度和最短路径
            int[] path = new int[100];
            int[] dist = new int[100];
            Dijkstra(graph, vj, dist, path);//所有点到vj的最短路径。
            if (dist[vi] == 100000000)  //vi到vj的距离为100000000,表示两地不连通。
                System.out.println("这两个景点尚未连通!");
            else {
                System.out.print("路线规划:" + attractions[vi].getName());
                int pre = path[vi];
                while (pre != -1) {  //通过迭代寻找最短路径
                    System.out.print("->" + attractions[pre].getName());
                    pre = path[pre];
                }
                System.out.println();
                System.out.println("路线长度:" + dist[vi]);
            }
            System.out.println("你还要查询其他路线吗?(y/是;n/结束)");
            char choice = input.nextLine().charAt(0);
            while (true)
                if (choice == 'y' || choice == 'n')
                    break;
                else {
                    System.out.println("请选择正确的选项(y/是;n/结束):");
                    choice = input.nextLine().charAt(0);
                }
            if (choice == 'n')
                return;
        }
    }

    //查询景点信息
    public static void QueryInformation() {
        init();
        int vi = 0;
        while (true) {  //是否继续查询
            while (true) {  //控制正确输入格式,并输出待查询景点的信息
                System.out.println("请输入待查询景点的名称或编号(1~12):");
                String information = input.nextLine();
                boolean mark = false;
                if (information.length() < 3) {
                    while (true) {
                        vi = Integer.parseInt(information);
                        if (vi > 0 && vi < 13) {
                            System.out.println("景点名称:" + attractions[vi].getName());
                            System.out.println("景点描述:" + '\n' + attractions[vi].getIntroduction());
                            mark = true;
                            break;
                        } else {
                            System.out.println("请输入正确的景点编号(1~12):");
                            information = input.nextLine();
                        }
                    }
                } else
                    for (int i = 1; i < 13; i++)
                        if (attractions[i].getName().equals(information)) {
                            System.out.println("景点编号:" + i);
                            System.out.println("景点描述:" + '\n' + attractions[i].getIntroduction());
                            mark = true;
                            break;
                        }
                if (!mark)
                    System.out.println("未找到此景点!");
                else
                    break;
            }
            System.out.println("你还要查询其他景点吗?(y/是;n/结束)");
            char choice = input.nextLine().charAt(0);
            while (true)
                if (choice == 'y' || choice == 'n')
                    break;
                else {
                    System.out.println("请选择正确的选项(y/是;n/结束):");
                    choice = input.nextLine().charAt(0);
                }
            if (choice == 'n')
                return;
        }
    }
}

3)Implement (主程序)类

public class Implement {

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.println("""
                欢迎来到volante导游系统!
                江苏科技大学各景点名称及对应编号如下:
                1 北苑食堂           7 笃学楼
                2 海韵湖            8 经世楼
                3 图书馆            9 明德楼
                4 计算机学院楼       10 七号组图
                5 东苑食堂          11 西苑食堂
                6 文理大楼          12 三号组团

                系统功能及对应编号如下:
                1 问路查询
                2 景点攻略
                """);
        while (true) {
            System.out.println("请输入你想要执行的操作(输入对应操作的编号):");
            int in = input.nextInt();
            while (true)
                if (in > 0 && in < 3)
                    break;
                else {
                    System.out.println("请正确输入你想要执行的操作(输入对应操作的编号):");
                    in = input.nextInt();
                }
            switch (in) {
                case 1 -> Method.wayFinding();
                case 2 -> Method.QueryInformation();
            }
            System.out.println("你还要执行其他操作吗?(y/是;n/结束)");
            input.nextLine();
            char choice = input.nextLine().charAt(0);
            while (true)
                if (choice == 'y' || choice == 'n')
                    break;
                else {
                    System.out.println("请选择正确的选项(y/是;n/结束):");
                    choice = input.nextLine().charAt(0);
                }
            if (choice == 'n')
                return;
        }
    }
}

结果分析

1)函数调用关系图;

2)效果分析。

在求最短路径时通过使用Dijkstra算法得到最短路径数组和最短路径长度数组,高效且灵活地求出最短路径,可准确地实现问路查询。


项目3:算术表达式求解

问题描述

设计一个简单的算术表达式计算器。

基本要求

实现标准整数类型的四则运算表达式的求值(包含括号,可多层嵌入)。

测试数据

(30+2*70)/3-12*3;

5+(9*(62-37)+15)*6;

要求自行设计非法表达式,进行程序测试,以保证程序的稳定运行。

实现提示

可以设计以下辅助函数:

status isNumber(char ReadInChar);  //视ReadInchar 是否是数字而返回 TRUE 或 FALSE 

int TurnToInteger(char IntChar);   // 将字符’0’.’9’ 转换为整数

问题分析和任务定义

1)实现基本的四则运算;

2)含有括号嵌套,能正确计算结果;

3)中缀表达式转换为后缀表达式,益于计算机普遍采用的栈式内存结构。

逻辑设计

1)定义pair、polish2inverse、calculate、simplify、isOpe、isAllOpe、isGreater、getLevel、isNumeric等方法实现特定功能模块;

2)通过模块的相互调用实现运算功能;

3)波兰形式转逆波兰形式的伪代码描述。

分配1个栈,临时存储运算符,并分配一个ArrayList存放后缀表达式形式结果,还需一个string来暂存数字

从左往右扫描中缀表达式串,对于每一个操作数或操作符,执行以下操作;

                IF (扫描到的s[i]是操作数DATA)

         将s[i]添加到string中

               IF (扫描到的s[i]是运算符')

                        IF(string非空)

                                数据串中数据放入ArrayList

                                string置空

                        IF(取出的字符是”+、-、*、/“)

                                将该运算符与栈顶元素比较

                                        IF(该运算符优先级高于栈顶运算符优先级)

                                                将该运算符进栈
                                        ELSE

                                                WHILE(栈顶运算符为”(“或栈顶运算符低于该运算符优先级)

                                                       将栈顶运算符弹出,送入List中
                                               将该运算符送入栈。

                      IF(取出的字符是")")

                             WHILE(栈非空)

                                        将距离栈顶最近的"("之间的运算符,逐个出栈,依次送入List中

                     IF(取出的字符是"(")

                             直接送入栈顶

物理设计

1)在波兰式转逆波兰式时使用栈数据结构作为过渡结构存储运算符;

Stack<Character> opeStack = new Stack<>();  //符号栈

2)在波兰式转逆波兰式时使用String作为过渡结构存储数据;

StringBuilder numStr = new StringBuilder();  //记录一个 一位或多位的 数字

3)在波兰式转逆波兰式时使用ArrayList数据结构存储得到的逆波兰式;

List<String> list = new ArrayList<>();  //存放后缀表达式结果

4)在对逆波兰式求解过程中用栈数据结构存储运算数据和最终结果。

Stack<Integer> num = new Stack<>();

程序编码

1)定义pair、polish2inverse、calculate、simplify、isOpe、isAllOpe、isGreater、getLevel、isNumeric等方法实现特定功能模块;

2)通过模块的相互调用实现运算功能。

①pair 判断表达式括号是否匹配

public static boolean pair(String strExpression) {
        Stack<Character> characterStack = new Stack<>();
        for (int i = 0; i < strExpression.length(); i++) {
            if (strExpression.charAt(i) == '(')
                characterStack.push('(');
            else if (strExpression.charAt(i) == ')' && !characterStack.isEmpty())
                characterStack.pop();
            else if (strExpression.charAt(i) == ')' && characterStack.isEmpty())
                return false;
        }
        return characterStack.size() == 0;
    }

②polish2inverse 中缀表达式转换为后缀表达式

public static List<String> polish2inverse(String strExpression) {
        String s = simplify(strExpression);  //简化表达式
        System.out.println("简化后的表达式为:\ns : " + s);
        StringBuilder numStr = new StringBuilder();  //记录一个 一位或多位的 数字
        Stack<Character> opeStack = new Stack<>();  //符号栈
        int l = s.length();  //字符串长度 l
        List<String> list = new ArrayList<>();  //存放后缀表达式结果

        for (int i = 0; i < l; i++) {
            char ch = s.charAt(i);
            //处理运算符
            if (isAllOpe(ch)) {
                if (!numStr.toString().equals("")) {
                    list.add(numStr.toString());
                    numStr = new StringBuilder();
                }
                if (ch == '(')
                    opeStack.push(ch);
                else if (isOpe(ch)) {
                    char top = opeStack.peek();
                    if (!isGreater(ch, top)) {
                        while (true) {
                            char t = opeStack.peek();
                            if (t == '(')
                                break;
                            if (isGreater(ch, t))
                                break;

                            list.add(Character.toString(t));
                            opeStack.pop();
                        }
                    }
                    opeStack.push(ch);

                } else if (ch == ')') {
                    char t = opeStack.pop();
                    while (t != '(' && !opeStack.isEmpty()) {
                        list.add(Character.toString(t));
                        t = opeStack.pop();
                    }
                }

            } else  //处理数字
                numStr.append(ch);
        }
        return list;
    }

③calculate 计算后缀表达式

public static void calculate(String strExpression) {
        List<String> list = polish2inverse(strExpression);
        System.out.println("后缀表达式为:\n" + list.toString());
        Stack<Integer> num = new Stack<>();
        for (String t : list) {
            if (isNumeric(t)) {  //若是数据则入栈,并将t转换成int方便计算
                num.push(Integer.parseInt(t));
            } else {
                //如果t为运算符,则只有一位,用charAt(0)
                char c = t.charAt(0);  //运算符
                //取出后缀形式中运算符前的两个数据(栈的前两个元素)
                int b = num.pop();
                int a = num.pop();
                //前两个数据与运算符进行运算,运算结果再继续入栈
                switch (c) {
                    case '+':
                        num.push(a + b);
                        break;
                    case '-':
                        num.push(a - b);
                        break;
                    case '*':
                        num.push(a * b);
                        break;
                    case '/':
                        num.push(a / b);
                        break;
                    default:
                        break;
                }
            }
        }
        //打印后缀表达式(即原算术表达式)的运算结果
        System.out.println("计算结果为: " + num.pop());
    }

④simplify 化简表达式

public static String simplify(String str) {
        //负数的处理
        // 处理负数,这里在-前面的位置加入一个0,如-4变为0-4,
        // 细节:注意-开头的地方前面一定不能是数字或者反括号,如9-0,(3-4)-5,这里地方是不能加0的
        // 它的后面可以是数字或者正括号,如-9=>0-9, -(3*3)=>0-(3*3)
        String s = str.replaceAll("(?<![0-9)}\\]])(?=-[0-9({\\[])", "0");
        //将表达式中的 {}[]替换为()
        s = s.replace('[', '(');
        s = s.replace('{', '(');
        s = s.replace(']', ')');
        s = s.replace(']', ')');
        //为了方便将中缀转换为后缀在字符串前后分别加上(,)
        s = "(" + s + ")";

        return s;
    }

⑤isOpe 判断字符c是否为合理的运算符(不包括括号)

public static boolean isOpe(char c) {
        return c == '+' || c == '-' || c == '*' || c == '/';
    }

⑦isAllOpe 判断字符c是否为合理的运算符(包括括号)

public static boolean isAllOpe(char c) {
        if (c == '+' || c == '-' || c == '*' || c == '/')
            return true;

        else return c == '(' || c == ')';
    }

⑧isGreater 比较字符等级a是否大于b

public static boolean isGreater(char a, char b) {
        int a1 = getLevel(a);
        int b1 = getLevel(b);
        return a1 > b1;
    }

⑨getLevel 得到一个字符的优先级

public static int getLevel(char a) {

        if (a == '+')
            return 0;
        else if (a == '-')
            return 1;
        else if (a == '*')
            return 3;
        else if (a == '/')
            return 4;
        else
            return -1; //'(',')'等级为-1
    }

⑩isNumeric 判断是不是数字

public static boolean isNumeric(String str) {
        Pattern pattern = Pattern.compile("[0-9]*");  //0~9的一位或多位数据
        Matcher isNum = pattern.matcher(str);  //匹配
        return isNum.matches();
    }

结果分析

1)函数调用关系图;

2)效果分析;

程序可准确计算各运算表达式,对嵌套括号可进行正确的处理,容错率较高,可判断输入表达式括号是否匹配。通过中缀转后缀表达式的手段计算表达式值,益于计算机普遍采用的栈式内存结构。

3)程序思路及大部分实现来源于作者居十四。

Java实现四则运算带括号和负数_居十四的博客-CSDN博客_java带括号四则运算

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值