想起以前大学时代写的一个项目,读取文件,初始化城市公交线路,然后可以查询该城市各个公交线路,还可以查询该城市每两个公交站之间的线路。很可惜,源码找不到了,最近几天时间利用闲暇时间把这个项目复习一下。
网上找了个excel文件,连云港的公交路线图,如下图的形式
首先,看到这个文件的时候,第一反映肯定是 这个应该用图结构来做。
第二反映应该是,图的节点挺多,路线很少,应该用链表形式表示图。
分析之后,发现其实图的边都不用保存,每个节点信息中保存一个集合,该集合中声明了节点所在的线路,和节点在该线路的索引(第几站),数据结构如下:
//站点所在的线路集合 Set<StandLineInfo> lines = new HashSet<StandLineInfo>();
package graph; /** * StandLineInfo : 在站点保存的线路信息 * @author xuejupo [email protected] * create in 2015-12-3 下午7:21:26 */ public class StandLineInfo { //线路名称 String line; //线路的索引 int index; public StandLineInfo(String line,int index){ this.line = line; this.index = index; } /** * 因为要放到set里面,所以重写hashcode方法和equals方法 * 当线路存在时则不重写 */ @Override public int hashCode() { // TODO Auto-generated method stub return line.hashCode() + new Integer(index).hashCode(); } @Override public boolean equals(Object obj) { // TODO Auto-generated method stub StandLineInfo s = (StandLineInfo)obj; return s.line.equals(s.line) && this.index == s.index; } public String toString(){ return "线路:"+line+"\t"+"第"+index+"站"; } }
另外,每条线路应该有个数据结构:
package graph; /** * TransitLine : 公交线路类 * @author xuejupo [email protected] * create in 2015-12-2 下午6:57:26 */ public class TransitLine { /** * @Fields lineName : 线路名称 */ String lineName; /** * @Fields sumOperationTime : 夏季运营时间 */ String sumOperationTime; /** * @Fields winOperationTime : 冬季运营时间 */ String winOperationTime; /** * @Fields lines : 线路中所有站的信息 */ String[] lines; public String toString(){ StringBuilder sb = new StringBuilder("线路名称:"+lineName+"\t"); sb.append("线路夏季运行时间:"+sumOperationTime+"\t"); sb.append("线路冬季运行时间:"+winOperationTime+"\r\n"); sb.append("线路的运营信息如下:\r\n"); for(int i = 0; i < lines.length; i ++){ sb.append(lines[i]); if(i % 5 == 0){ sb.append("\r\n"); } sb.append("==>"); } sb.append("\r\n"); return sb.toString(); } }
记录该线路的各种信息。初始化文件时,应该保存的有:
/** * @Fields TRANSIT_VALUE_TO_NAME : 数组坐标到站名的对应关系 */ static Map<Integer, String> TRANSIT_INDEX_TO_NAME = new HashMap<Integer, String>(); /** * @Fields TRANSIT_NAME_TO_INDEX : 站名到数组坐标的对应关系 */ static Map<String, Integer> TRANSIT_NAME_TO_INDEX = new HashMap<String, Integer>(); /** * @Fields TRANSIT_LINES : 线路对应的所有站名 */ static Map<String, TransitLine> TRANSIT_LINES = new HashMap<String, TransitLine>();
读取excel文件并初始化:
/** * init: 初始化整个文件 * void 返回类型 */ public static void init() { // 网上找的连云港的公交路线 File f = new File("D:\\gongjiao\\连云港.xls"); if (!f.exists()) { System.out.println("ERROR!!!"); return; } try { Workbook book = Workbook.getWorkbook(f);// Sheet sheet = book.getSheet(0); // 获得第一个工作表对象 for (int i = 2; i < sheet.getRows(); i++) { //线路 String line = null; //运营时间 String time = null; //站点名称 String transit = null; for (int j = 0; j < sheet.getColumns(); j++) { Cell cell = sheet.getCell(j, i); // 获得单元格 if (j == 1 || j == 4 || j == 6) { if(j == 1){ line = cell.getContents(); }else if(j == 4){ time = cell.getContents(); }else{ transit = cell.getContents(); } } } initData(line, time, transit); } } catch (BiffException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
初始化每一条线路(也就是excel的每一行):
/** * initData: 初始化一条线路 * *line 线路 *time 运营时间 *transit 站点名称; * void 返回类型 */ private static void initData(String line,String time,String transit){ if(line == null || time == null || transit == null){ return; } String[] lines = transit.split("、"); //初始化站名和数字坐标对应关系 for(int i = 0; i < lines.length; i++){ if(!TRANSIT_NAME_TO_INDEX.containsKey(lines[i].trim())){ TRANSIT_INDEX_TO_NAME.put(max, lines[i].trim()); TRANSIT_NAME_TO_INDEX.put(lines[i].trim(), max); graph.addVex(max, line,i); if(i != 0){ graph.addEdge(max - 1, max, 1); // graph.addEdgeIn(max, max - 1, 1); } max++; }else{ graph.addVexLine(TRANSIT_NAME_TO_INDEX.get(lines[i].trim()), line, i); if(i != 0){ graph.addEdge(TRANSIT_NAME_TO_INDEX.get(lines[i-1].trim()), TRANSIT_NAME_TO_INDEX.get(lines[i].trim()), 1); // graph.addEdgeIn(TRANSIT_NAME_TO_INDEX.get(lines[i].trim()), TRANSIT_NAME_TO_INDEX.get(lines[i-1].trim()), 1); } } } //初始化线路信息 //1.初始化线路运营时间 TransitLine lin = new TransitLine(); if(time.contains("夏")){ lin.sumOperationTime = time.substring(1, 10); lin.winOperationTime = time.substring(11); }else{ lin.sumOperationTime = time; lin.winOperationTime = time; } //2.初始化线路的具体站名 lin.lines = lines; lin.lineName = line; //放入内存中 TRANSIT_LINES.put(line.trim(), lin); }
测试方法:
public static void main(String[] args) { // TODO Auto-generated method stub Map<Integer,String> m = new HashMap<Integer,String>(); m.put(1, "test"); System.out.println(m.get(0)); long start = System.currentTimeMillis(); System.out.println("初始化中-----"); MessageInit.init(); long end = System.currentTimeMillis(); System.out.println("初始化完成,耗时" + (end - start)+"毫秒"); System.out.println("输入操作:1表示查看线路信息,2表示查看坐标对应的站点,3表示查看站点详细信息,-1退出"); Scanner sc = new Scanner(System.in); String in = sc.next(); while(!"-1".equals(in)){ if("1".equals(in)){ System.out.println("共有线路"+MessageInit.TRANSIT_LINES.size()+"个"); System.out.println("输入线路名称"); in = sc.next(); System.out.println("您输入了:"+in); System.out.println(MessageInit.TRANSIT_LINES.get(in)); } if("2".equals(in)){ System.out.println("共有站"+MessageInit.TRANSIT_INDEX_TO_NAME.size()+"个"); System.out.println("输入坐标"); int i = sc.nextInt(); System.out.println("您输入了:"+i); System.out.println(MessageInit.TRANSIT_INDEX_TO_NAME.get(i)); } if("3".equals(in)){ System.out.println("输入站名"); System.out.println("共有站"+MessageInit.TRANSIT_NAME_TO_INDEX.size()+"个"); in = sc.next(); System.out.println("您输入了:"+in); System.out.println("站点所在的线路共有:"); Set<StandLineInfo> stands = MessageInit.graph.vexs.get(MessageInit.TRANSIT_NAME_TO_INDEX.get(in)).lines; for(StandLineInfo s:stands){ System.out.println(s); } System.out.println("他上一站有:"); Edge pre = MessageInit.graph.vexs.get(MessageInit.TRANSIT_NAME_TO_INDEX.get(in)).edgeIn; while(pre != null){ System.out.print(MessageInit.TRANSIT_INDEX_TO_NAME.get(pre.iVex)+"\t"); pre = pre.next; } System.out.println(); System.out.println("他下一站有:"); Edge nex = MessageInit.graph.vexs.get(MessageInit.TRANSIT_NAME_TO_INDEX.get(in)).edge; while(nex != null){ System.out.print(MessageInit.TRANSIT_INDEX_TO_NAME.get(nex.iVex)+"\t"+nex.iVex+"\t"); nex = nex.next; } System.out.println(); } System.out.println("输入操作:1表示查看线路信息,2表示查看坐标对应的站点,3表示查看站点对应的坐标,-1退出"); in = sc.next(); }
结果:
初始化中----- 初始化完成,耗时127毫秒 输入操作:1表示查看线路信息,2表示查看坐标对应的站点,3表示查看站点详细信息,-1退出 1 共有线路59个 输入线路名称 快速公交(BRT)喂给线1(H1) 您输入了:快速公交(BRT)喂给线1(H1) 线路名称:快速公交(BRT)喂给线1(H1) 线路夏季运行时间:6:00-20:00 线路冬季运行时间:6:00-20:00 线路的运营信息如下: 火车站 ==>汽车总站==>利玛国际锦苑==>银泰花苑==>郁洲公园==>博威江南明珠苑 ==>万润花园==>大润发==>移动大楼==>外国语学校==>龙河广场 ==>市民广场==>天然居==>工商银行==>黄海影剧院==>园林花园 ==>电视台==>石油公司==>火车站==> 输入操作:1表示查看线路信息,2表示查看坐标对应的站点,3表示查看站点对应的坐标,-1退出 3 输入站名 共有站595个 火车站 您输入了:火车站 站点所在的线路共有: 线路:快速公交(BRT)喂给线1(H1) 第18站 线路:常规公交9路 第0站 线路:快速公交(BRT)喂给线3(B11) 第0站 线路:常规公交旅游线路游2路 第0站 线路:常规公交11路 第0站 线路:常规公交15路 第25站 线路:常规公交23路 第22站 线路:常规公交17路 第0站 线路:常规公交夜班线203路 第0站 线路:常规公交9路 第29站 线路:常规公交119路 第13站 线路:快速公交(BRT)喂给线1(H1) 第0站 线路:常规公交12路 第12站 线路:常规公交4路 第0站 线路:常规公交21路 第0站 线路:常规公交8路 第0站 线路:常规公交22路 第0站 他上一站有: 石油公司 汽车总站 工农路口 他下一站有: 汽车总站 31 石油公司 40 工农路口 308 输入操作:1表示查看线路信息,2表示查看坐标对应的站点,3表示查看站点对应的坐标,-1退出 2 共有站595个 输入坐标 13 您输入了:13 自来水公司 输入操作:1表示查看线路信息,2表示查看坐标对应的站点,3表示查看站点对应的坐标,-1退出 -1