项目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)程序思路及大部分实现来源于作者居十四。