承蒙朋友看的起,前几天要我帮忙写一个小程序,程序的需求是这样的:
现在有一组人G(
顶格的那些人名,
可能有同名的人,
但是仅仅是同名,
不是同一个人),
他们有各自的朋友,
即每个顶格的人名下缩进的那些人名.
例如A. Sarry
认识Y. Jim
。现在希望对G
这组人进行排序,
排序规则如下:
首先按照这组人的人名的升序进行排序(
每个人的朋友也需要进行排序),
如果有重名,
则按照其朋友人数的多少进行升序排序,
最后如果朋友人数相同,
则依次按照每个朋友的名字的升序进行排序.
将以下数据存放在一个名为people.disorder
的文本文件中,
写一个java application,
对people.disorder
中的这组人G
进行排序,
并将排序结果放在名为people.inorder
的文本文件中.
以下的是people.disorder:
的内容
M. John
B. Kyle
C. Tom
——————–
M. John
C. Thomsom
D. Harry
B. Sim
——————–
A. Sarry
Y. Jim
——————–
S. Sarry
Z. Zoo
——————–
M. John
B. Sim
K. King
J. Jimmy
由于使用Java
实现,首先需要对每个人以及朋友建立一个对象,对于每个人的朋友按照名字进行排序,然后再按照每个人的大小顺序进行排序。按照这个思想,需要设计一个Person
类,用于记录每个人的姓名以及他所有的朋友,再设计一个类TextDb
用于从文件中读取内容,构造Person
类,然后对所有的Person
进行排序,最后把排序后的结果输出到文件中。在对Person
进行排序的过程中,两个Person
比较大小的操作应该是哪个类的职责哪?根据GRASP
原则,很显然,Person
比较大小的操作应该放在Person
类中比较合适。
根据以上的分析,涉及类Person
如下:
import java.util.Vector;
/**
* @author TIANLI
建立一个Person
类,代表个人,
他的所有的朋友的名字都在friends
列表中,
*
实例初始化的时候可以使用一个参数初始化名字这个变量。
*
*/
public class Person {
/**
*
名字,每个人都有的名字
*/
private String name;
/**
*
个人的朋友的列表,
*/
private Vector friends;
public Person() {
}
/**
*
计算朋友的个数
*
* @return
朋友的个数
*/
public int getFriendsNum() {
if (friends == null)
return 0;
else
return friends.size();
}
/**
*
构造一个实例,传入一个参数作为名字
*
* @param name
*
名字的值
*/
public Person(String name) {
this.name = name;
}
/**
*
为一个人增加一个朋友的名字,并且按照名字的先后字典顺序进行排序
*
* @param friendName
*
朋友的名字
*/
public void addFriend(String friendName) {
if (friends == null) {
friends = new Vector();
friends.add(friendName);
} else {
int i;
for (i = 0; i < friends.size(); i++) {
if (((String) friends.get(i)).compareTo(friendName) >= 0) {
friends.add(i, friendName);
break;
}
}
if (i == friends.size()) {
friends.add(i, friendName);
}
}
}
/**
* @return
所有朋友的列表
*/
public Vector getFriends() {
return friends;
}
/**
*
增加一个人的所有朋友
* @param friends
*/
public void setFriends(Vector friends) {
this.friends = friends;
}
/**
* @return
得到一个实例的名字
*/
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/* (non-Javadoc)
把一个实例输出来,实例的格式为名字{
朋友1
,朋友2
。。。}
* @see java.lang.Object#toString()
*/
public String toString() {
String ret = “—————————-\n”;
ret+=name + “\n”;
if (friends != null) {
for (int i = 0; i < friends.size(); i++) {
ret += ” ” + friends.get(i) + “\n”;
}
}
return ret;
}
/**
*
两个对象比较的原则是:如果名字不同,按照字典顺序逐个字符比较,字典顺序靠后的较大
*
如果名字相同,朋友个数多的较大
*
如果朋友个数相等,逐个按照字典顺序比较它们的朋友的名字的大小,字典顺序靠后的较大
* @param o
等待比较的对象
* @return
返回一个Bool
值,如果
*/
public boolean greateOrEqual(Object o) {
boolean retVal = false;
Person p = (Person) o;
//
名字的字典顺序比较
if (name.compareTo(p.getName()) > 0) {
retVal = true;
} else if (name.compareTo(p.getName()) < 0) {
retVal = false;
}
//
名字相同的情况下按照朋友的个数进行比较
else if (getFriendsNum() > p.getFriendsNum()) {
retVal = true;
} else if (getFriendsNum() < p.getFriendsNum()) {
retVal = false;
}
//
朋友个数也相同的情况下按照字典顺序比较朋友的名字。
else {
if (getFriendsNum() == 0) {
retVal = true;
} else {
for (int i = 0; i < friends.size(); i++) {
int minus = ((String) friends.get(i)).compareTo(((String) p
.getFriends().get(i)));
if (minus > 0) {
retVal = true;
break;
} else if (minus < 0) {
retVal = false;
break;
}
}
}
}
return retVal;
}
}
对于这个类,需要注意的地方就是朋友增加的时候使用插入排序的方法对朋友进行排序操作,由于个人的朋友是从文件中逐个读出来的,所以在构造Person
类的实例的时候,朋友的个数是逐个添加的。按照业务规则,两个实例进行比较的所有内容全部写在greateOrEqual
函数中。下面看一下相应的TextDb
类:
package com.logis.fz;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Vector;
/**
* @author TIANLI
,Li
*
从一个文件中得到所有人的信息,然后进行排序,并可以输出到一个文件中。
*/
public class TextDb {
private String inFileName = “D:\\people.disorder”;
private String outFileName = “D:\\people.inorder”;
private Vector persons = new Vector();
/**
*
从输入文件中得到所有的名字
从文件中逐行读取数据,
遇到—
则跳过这一行,
并设置下一次创建一个新的对象的标示
*
遇到一个新的名字,如果设置了创建新对象的标示,则创建新的对象,
否则把当前的名字添加到当前人的朋友列表中。
*
* @throws Exception
*/
public void getDataFromFile() throws Exception {
File myFile = new File(inFileName);
if (!myFile.exists()) {
System.err.println(“Can’t Find ” + inFileName);
}
BufferedReader in = new BufferedReader(new FileReader(myFile));
String str;
boolean newPerson = true;
Person p = null;
while ((str = in.readLine()) != null) {
if (!(str.indexOf(“–“) >= 0)) {
if (newPerson) {
p = new Person(str.trim());
newPerson = false;
} else {
if (p != null) {
p.addFriend(str.trim());
} else {
System.out.println(“Have a wrong number”);
}
}
} else {
if (p != null)
persons.add(p);
newPerson = true;
}
}
if (!newPerson)
persons.add(p);
in.close();
}
/**
*
进行排序操作,使用插入排序方法进行逐个的插入排序,
插入排序是不稳定的排序,但是不会影响效果。
*
* @throws Exception
*/
public void doOrder() throws Exception {
if (persons.size() == 0)
getDataFromFile();
if (persons.size() == 0)
throw new Exception(”
没有数据!”);
Vector result = new Vector();
result.add(persons.get(0));
for (int i = 1; i < persons.size(); i++) {
int j;
for (j = 0; j < result.size(); j++) {
if (!((Person) persons.get(i)).greateOrEqual(result.get(j))) {
result.add(j, persons.get(i));
break;
}
}
if (j == result.size()) {
result.add(j, persons.get(i));
}
}
persons = result;
}
/*
*
输出所有的人的信息
* @see java.lang.Object#toString()
*
把persons
转变为一个长字符串,包含所有人员的信息。
*/
public String toString() {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < persons.size(); i++) {
sb.append(persons.get(i));
}
return sb.toString();
}
/**
*
把内容输出到一个文本文件中。
*
需要设置参数outFileName,
如果没有设置,则有默认值为D:\\people.inorder
*/
public void exportToText() {
try {
FileWriter fw = new FileWriter(outFileName);
fw.write(this.toString());
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
*
得到待排序的输入文件的全路径。
* @return
返回待排序的输入文件的全路径。
*
*/
public String getInFileName() {
return inFileName;
}
/**
*
设置输入文件的名字
* @param inFileName
输入的文件名,默认值为D:\\people.disorder
*
输入的文件的名字需要全路径,如果\
出现需要使用\\
代替,否则路径就会出现问题
*
*/
public void setInFileName(String inFileName) {
this.inFileName = inFileName;
}
/**
*
输出文件的全路径
* @return
返回输出文件的全路径
*/
public String getOutFileName() {
return outFileName;
}
/**
*
设置输出文件的名字
* @param inFileName
输入的文件名,默认值为D:\\people.inorder
*
输入的文件的名字需要全路径,如果\
出现需要使用\\
代替,否则路径就会出现问题
*
*/
public void setOutFileName(String outFileName) {
this.outFileName = outFileName;
}
}
这个类中也没有什么特别的地方,主要需要注意的就是进行插入排序的函数和ToString
方法,在Person
类中已经覆盖了toString
方法,所以在这个ToString
方法中只需要循环遍历Persons,
然后输出就可以。
两个类都经过测试,下面是测试的结果:
测试类在附件中可以看到。使用Ant
进行编译和运行的,如果有需要了解整个工程源代码的(
包括ant
自动化编译、测试、生成JavaDoc,log4j
日志)
,请直接问本人索要。