1、问题定义
①参赛队伍信息的查找(按参赛队编号查找、按参赛学校查找)
2、问题分析
①从team.txt中读取参赛队伍的基本信息,实现基于二叉排序树的查找。根据提示输入参赛队编号,若查找成功,输出该赛事类别对应的基本信息(参赛作品名称、参赛学校、赛事类别、参赛者和指导老师信息),同时,输出查找成功时的平均查找长度ASL;否则,输出“查找失败!”。
②能够提供按参赛学校查询参赛团队(或根据赛事类别查询参赛团队),即,根据提示输入参赛学校名称(赛事类别),若查找成功,输出该学校参赛的(该赛事类别的)所有团队的基本信息,输出的参赛团队按赛事类别有序输出。
3、概要设计
数据结构、文件读写方法请查看:预习报告(一)
1、菜单
private void menu() {
//进入菜单时建立二叉排序树
creatTree();
System.out.println("\n======请选择操作======");
System.out.println("=======1-查询系统=======");
System.out.println("=======2-修改系统=======");
System.out.println("=======3-叫号系统=======");
System.out.println("=======4-导航系统=======");
System.out.println("=======0-退出系统=======");
int choose;
while (true) {
choose = sc.nextInt();
if (choose == 1 || choose == 2 || choose == 3 || choose == 4 || choose == 0) break;
else System.out.println("输入错误,请重新输入!");
}
switch (choose) {
case 1 -> find();
case 2 -> change();
case 0 -> {
System.out.println("欢迎再次使用本系统!");
write();//将数据重新写回文件中
System.exit(0);
}
}
}
2、信息输出
当遇到查询或者需要输出参赛队信息时,将参赛队对象传递到该方法并拼接输出
private void print(Contestant c) {
System.out.println(c.id + "\t#\t" + c.name + "\t#\t" + c.school + "\t#\t" + c.category + "\t#\t" + c.player + "\t#\t" + c.teacher);
}
3、查询系统
private void find() {
System.out.println("\n=======信息查询端口=======");
System.out.println("1-按参赛队编号进行查询");
System.out.println("2-按参赛学校名进行查询");
System.out.println("0-返回主菜单");
int choose;
while (true) {
choose = sc.nextInt();
if (choose == 1 || choose == 2 || choose == 0) break;
else System.out.println("输入错误,请重新输入!");
}
switch (choose) {
case 1 -> findNum();
case 2 -> findSchool();
case 0 -> menu();
}
}
3.1、按参赛队编号进行查询
按参赛队编号查询实际上很简单,但课设要求其基于二叉排序树查询,因此在读取文件时,将每个参赛队伍的参赛队编号存入了list中,用于建立二叉排序树,进入到菜单界面时就利用list来建立二叉排序树,查找时也是对二叉排序树来查找,在二叉树中找到了所查询的编号节点,再输出成功信息,实际是用以参赛队编号为key的哈希表来查询其信息的。
private void findNum() {
while (true) {
System.out.print("输入查询的参赛队编号:");
String num = sc.next();
Node node = root.search(Integer.parseInt(num));//基于二叉排序树查找
if (node == null) {//在二叉排序树中找不到节点
System.out.println("查找失败!输入1继续查询,输入其他则返回上层菜单");
int choose = sc.nextInt();
if (choose != 1) find();//返回查询系统
} else {//找到节点
System.out.println("查找成功!");
Contestant cnum = numberMap.get(num);//获取到该队信息对象
System.out.println("参赛队编号\t#\t参赛作品名称\t#\t参赛学校\t#\t赛事类别\t#\t参赛者\t#\t指导教师");
print(cnum);//信息输出
System.out.println("查找成功时的平均查找长度ASL:" + sum / (double) (numberMap.size()));
System.out.println("输入1继续查询,输入其他则返回上层菜单");
int choose = sc.nextInt();
if (choose != 1) find();//返回查询系统
}
}
}
3.2、按参赛学校名进行查询
对于参赛学校名查询,为了方便,定义一个新的数据结构——双层哈希表,以校名为key,value是该校所有参赛队的哈希表,在读取文件时也一并将信息存入了。
找到某学校的参赛队伍时,按归并排序算法进行输出,选择归并算法排序的原因是其较为稳定、速度较快,牺牲空间换时间,但因为数据量不大因此可以接受。
HashMap<String, Map<String, Contestant>> schoolMap = new HashMap<>();//以参赛学校名称为键的嵌套HashMap
private void findSchool() {
while (true) {
System.out.println("输入查询的参赛学校:");
String school = sc.next();
if (schoolMap.containsKey(school)) {
System.out.println("查找成功!");
HashMap<String, Contestant> innerMap = schoolMap.get(school);//获取该学校参赛队的哈希表
System.out.println("参赛队编号\t#\t参赛作品名称\t#\t参赛学校\t#\t赛事类别\t#\t参赛者\t#\t指导教师");
List<Contestant> contestants = new ArrayList<>();
Iterator<HashMap.Entry<String, Contestant>> iterator = innerMap.entrySet().iterator();
while (iterator.hasNext()) {//用迭代器遍历该学校对应的内部哈希表
HashMap.Entry<String, Contestant> entry = iterator.next();
Contestant c = entry.getValue();//获取该校每个参赛队伍
contestants.add(c);//添加至列表中
}
Contestant sortCategory = new Contestant();
sortCategory.mergeSort(contestants, 0, contestants.size() - 1);//排序
for (Contestant c : contestants) {//输出数据
print(c);
}
System.out.println("输入1重新查询,输入其他返回上层菜单");
int choose = sc.nextInt();
if (choose != 1) find();
} else {
System.out.println("查找失败,无该校的参赛队伍!输入1重新查询,输入其他返回上层菜单");
int choose = sc.nextInt();
if (choose != 1) find();
}
}
}
以下是Contestant类中的排序方法,用的是归并排序
public void mergeSort(List<Contestant> list, int left, int right) {
if (left >= right) {
return;
}
int mid = (left + right) / 2;
mergeSort(list, left, mid);
mergeSort(list, mid + 1, right);
merge(list, left, mid, right);
}
public void merge(List<Contestant> list, int left, int mid, int right) {
List<Contestant> temp = new ArrayList<>();
int i = left;
int j = mid + 1;
while (i <= mid && j <= right) {
if (list.get(i).category.compareTo(list.get(j).category) <= 0) {
temp.add(list.get(i));
i++;
} else {
temp.add(list.get(j));
j++;
}
}
while (i <= mid) {
temp.add(list.get(i));
i++;
}
while (j <= right) {
temp.add(list.get(j));
j++;
}
for (int k = 0; k < temp.size(); k++) {
list.set(left + k, temp.get(k));
}
}
4、测试
测试信息: