帮朋友写了个java数据结构课设,记录一下
本次课设用到的文件,密码d315
现有学生成绩信息文件1(1.txt),内容如下:
学生成绩信息文件2(2.txt),内容如下:
试编写一管理系统,要求如下:
(1)实现对两个文件数据进行合并,生成新文件3.txt,(去重)
(2)抽取出三科成绩中有补考的学生并保存在一个新文件4.txt
(3)对合并后的文件3.txt中的数据按总分降序排序(至少采用两种排序方法实现必须包含一个时间复杂为nlog2n)
(4)输入一个学生姓名后,能查找到此学生的信息并输出结果(至少采用两种查找方法实现)
(5)要求使用结构体,链或数组等实现上述要求.
首先是学生的javabean,根据题目要求设置了几个私有属性,姓名,学号,成绩等,顺手添加了他的get和set方法.
因为要求第二条需要判断是否挂科我添加了 re_exam() 方法判断是否补考
在读取文件的同时还需要去重,自然而然的想到了集合,但是使用HashSet需要重写equals方法和hashCode方法,之前使用hashset都是存一些整型字符串之类的,这一次存自己定义的对象还费了一番周折
toString方法我也改了一下,主要是为了输出到文档上方便对齐(对齐也不好看)
构造方法我使用list作为参数,在主类里面list中将会含有读取到的所有信息,方便创建对象(自然也要留一个无参的构造方法)
package com.jiashi.test;
import java.io.Serializable;
import java.util.ArrayList;
public class student implements Serializable {
private String name; //姓名
private String snum;//学号
private Integer chinese;//语文
private Integer math;//数学
private Integer english;//英语
private Integer score;//总分
public boolean re_exam() {//判断是否补考
if (chinese >= 60 && math >= 60 && english >= 60) {
return false;
} else {
return true;
}
}
//类的构造方法
public student(ArrayList<String> list) {
this.name = list.get(0);
this.snum = list.get(1);
this.chinese = Integer.parseInt(list.get(2));
this.math = Integer.parseInt(list.get(3));
this.english = Integer.parseInt(list.get(4));
this.score = chinese + math + english;
}
public student() {
}
//toString方法
@Override
public String toString() {
return name + " " +
snum + " " +
chinese + " " +
math + " " +
english + " " +
score;
}
//复写hashCode方法
@Override
public int hashCode() {
int prim = 31;
int resultCode = prim * (prim + 1) + snum.hashCode();
return resultCode;
}
//复写equals方法
@Override
public boolean equals(Object obj) {
if(!(obj instanceof student)) {
// instanceof 已经处理了obj = null的情况
return false;
}
student stuObj = (student) obj;
// 地址相等
if (this == stuObj) {
return true;
}
// 如果两个对象姓名、年龄、性别相等,我们认为两个对象相等
if (stuObj.getName().equals(this.name)
&& stuObj.getSnum().equals(this.snum)) {
return true;
} else {
return false;
}
}
public String getSnum() {
return snum;
}
public void setSnum(String snum) {
this.snum = snum;
}
public Integer getScore() {
return score;
}
public void setScore(Integer score) {
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getChinese() {
return chinese;
}
public void setChinese(Integer chinese) {
this.chinese = chinese;
}
public Integer getMath() {
return math;
}
public void setMath(Integer math) {
this.math = math;
}
public Integer getEnglish() {
return english;
}
public void setEnglish(Integer english) {
this.english = english;
}
}
然后是主类,主要有如下几个方法
readFile
该方法旨在从文件中读取数据,由于其按行读取的特性,我选择使用BufferedReader,我在IDE上面使用UTF-8读取我桌面上的文件产生了乱码,于是将InputStreamReader的第二个构造参数传为GBK,乱码就被解决了(大概是编码问题);
在读取文件中每一行的文件时,需要过滤首行和行与行之间的空隙,我使用split将字符串分解为数组,但是正则不太会用,这就导致我在信息行的数组里面多了好多空格的元素,无奈之下将数组中空格过滤,然后添加到list中(顺序存储很好用),然后利用list作为参数创建student对象;然后将对象存入hashset中
writeFile
写出文件就要省事多了,将排序好的list传入,遍历的时候PrintWriter直接按行写出即可
排序算法和查找算法
在此就不过多赘述,篇幅较大
main
当上面的函数都写好了之后,事情就变得简单多了,读取文件存到HashSet中,然后遍历到list里面方便排序,遍历的过程中顺手做个判断,挂科的也存起来,然后使用写好的排序算法排序,然后打印.
然后是查找学生,用Scanner读取查找的姓名,当输入不为quit时不跳出查找的循环,查到就打印出来,查不到就不打印.这里使用循环方便用户多次查找,而不是查找一次
另外,我的读写文件路径是我的桌面,不同用户自行修改
package com.jiashi.test;
import java.io.*;
import java.util.*;
public class Application {
//使用hashset来去重
protected static HashSet<student> students = new HashSet<student>();
//读取文件的方法
public static void readFile(String path) throws IOException {
FileInputStream fis = new FileInputStream(path);
//设置GBK编码防止乱码,如果在其他设备乱码可以改成UTF-8试试
InputStreamReader isr = new InputStreamReader(fis, "GBK");
BufferedReader br = new BufferedReader(isr);
/*
* BufferedReader提供了按行读取方法
* String readLine()
* 连续读取若干字符,直到读取到换行符位置,并将
* 换行符之间读取的字符以一个字符串返回,若返回值为null
* 则表示读取到末尾
* 注意:该字符串不包含最后的换行符
*/
//从流中读取到的字符串
String line = null;
//将字符串截取为数组存在这里
String[] split = null;
//过滤数组,将有用信息存在这里
ArrayList<String> list = new ArrayList<>();
while ((line = br.readLine()) != null) {
split = line.split("\\ ");
//读取到的文件行与行之间有空数组,下面判断滤去第一行和空行
if (split.length != 1 && !"姓名".equals(split[0])) {
int j = 0;
for (int i = 0; i < split.length; i++) {
//过滤数组中的空格
if (!"".equals(split[i])) {
//将数据存入list
list.add(split[i]);
}
}
//使用list创建学生对象,存入hashset
students.add(new student(list));
//清除list中的上一组数据
list.clear();
}
}
//关闭流
br.close();
}
public static void writeFile(String path, ArrayList<student> list) throws IOException {
/*
* 提供了多种构造方法
* 其中有两个可以直接
* 对文件进行写出操作的构造方法
*
* PrintWriter(File file)
* PrintWriter(String path)
*/
PrintWriter pw = new PrintWriter(path, "GBK");
pw.println("姓名 学号 语文 数学 英语 总分");
for (student s : list) {
//遍历list并写出
pw.println(s);
}
System.out.println("写出完毕 ");
//关闭流
pw.close();
}
//冒泡排序
public static ArrayList<student> bubbleSort(ArrayList<student> list) {
student temp;
//一共比较length-1轮
for (int i = 0; i < list.size() - 1; i++) {
//一次比较length-1-i次
for (int j = 0; j < list.size() - 1 - i; j++) {
if (list.get(j).getScore() < list.get(j + 1).getScore()) {
temp = list.get(j + 1);
list.set(j + 1, list.get(j));
list.set(j, temp);
}
}
}
return list;
}
//快速排序
public static ArrayList<student> fastSort(ArrayList<student> list) {
quickSort(list, 0, list.size() - 1);
return list;
}
//快速排序子方法
public static void quickSort(ArrayList<student> list, int start, int end) {
if (start < end) {
//把第0个元素当做标准元素
student stard = list.get(start);
//记录需要排序的下标
int low = start;
int high = end;
//循环找出比标准数分数大的元素和比标准数分数小的元素
while (low < high) {
//右边分数比标准数小
while (low < high && stard.getScore() >= list.get(high).getScore()) {
high--;
}
//使用右边的元素替换左边的元素
list.set(low, list.get(high));
//右边分数比标准数大
while (low < high && stard.getScore() <= list.get(low).getScore()) {
low++;
}
list.set(high, list.get(low));
}
//把标准元素赋给low==high的位置
list.set(low, stard);
//处理所有小于标准数的数字
quickSort(list, start, low);
//处理所有大于标准数的数字
quickSort(list, low + 1, end);
}
}
//线性查找
public static void lineSearch(String name) {
System.out.println("线性查找:");
for (student s : students) {
if (s.getName().equals(name)) {
System.out.println("姓名 学号 语文 数学 英语 总分");
System.out.println(s);
}
}
}
//二分查找
public static void binarySearch(ArrayList<student> list, String str) {
System.out.println("二分查找");
//二分查找要按顺序,所以用compareTo来排序一下
student temp;
for (int i = 0; i < list.size() - 1; i++) {
for (int j = 0; j < list.size() - 1 - i; j++) {
if (list.get(j).getName().compareTo(list.get(j + 1).getName()) > 0) {
temp = list.get(j + 1);
list.set(j + 1, list.get(j));
list.set(j, temp);
}
}
}
int low = 0;
int height = list.size() - 1;
int mid;
while (low <= height) {
mid = (low + height) / 2;
if (list.get(mid).getName().compareTo(str) > 0) {
height = mid - 1;
} else if (list.get(mid).getName().compareTo(str) < 0) {
low = mid + 1;
} else if (list.get(mid).getName().compareTo(str) == 0) {
System.out.println("姓名 学号 语文 数学 英语 总分");
System.out.println(list.get(mid));
break;
}
}
}
public static void main(String[] args) {
//读取两个文件的内容
try {
readFile("C:\\Users\\Excalibur\\Desktop\\1.txt");
readFile("C:\\Users\\Excalibur\\Desktop\\2.txt");
} catch (Exception e) {
e.printStackTrace();
}
ArrayList<student> list = new ArrayList<>();
ArrayList<student> list_re = new ArrayList<>();
//因为要排序,所以把元素从hashset->list
for (student s : Application.students) {
list.add(s);
//将挂科的存一下
if (s.re_exam()) {
list_re.add(s);
}
}
//快速排序产生的list
ArrayList<student> fast = fastSort(list);
try {
//使用快速排序打印3.txt
writeFile("C:\\Users\\Excalibur\\Desktop\\3.txt", fast);
//使用冒泡排序打印4.txt
writeFile("C:\\Users\\Excalibur\\Desktop\\4.txt", bubbleSort(list_re));
} catch (IOException e) {
e.printStackTrace();
}
//读取键盘
Scanner scanner = new Scanner(System.in);
String str = "";
//当没输入quit就一直循环,这样可以查好多次
while (!"quit".equals(str)) {
System.out.println("-------------------------------------------");
System.out.print("请输入待查找的学生姓名,输入quit退出:");
str = scanner.nextLine();
if (!"quit".equals(str)) {
//线性查找
lineSearch(str);
//二分查找
binarySearch(fast, str);
}
System.out.println("-------------------------------------------");
}
}
}
对于大佬来说这个可能很简单,希望可以帮到哪位做课设的学弟学妹
码字不易,点个赞再走吧