Java 帮助遍历节点/输入文件读取

Java 帮助遍历节点/输入文件读取,java,graph-theory,filereader,adjacency-matrix,Java,Graph Theory,Filereader,Adjacency Matrix,所以我有一个作业,我一次读一行,用逗号隔开 Atlanta, Philadelphia New York, Philadelphia Philadelphia, Chicago Washington, Florida ..... up to a vast amount.. (I don't know the amount) 每条线表示两个位置(例如亚特兰大连接费城)之间的连接,创建连接的节点,而不是像华盛顿和佛罗里达那样连接的节点彼此连接,但没有其他节点 程序要做的是读取文件

所以我有一个作业,我一次读一行,用逗号隔开

Atlanta, Philadelphia   
New York, Philadelphia   
Philadelphia, Chicago   
Washington, Florida
.....
up to a vast amount.. (I don't know the amount)
每条线表示两个位置(例如亚特兰大连接费城)之间的连接,创建连接的节点,而不是像华盛顿和佛罗里达那样连接的节点彼此连接,但没有其他节点

程序要做的是读取文件,并给出两个city参数,如果连接,则假定为Yes;如果未连接,则为No

我完成了我的程序,它工作了,但是它没有效率。我不知道我能做什么。下面是使代码效率低下的程序的一部分

第一个输入读取文件,以便确定不同城市列表的大小,并删除任何重复的城市

private static void createCityList() throws IOException{

        try {
            FileReader a = new FileReader(file);
            BufferedReader br = new BufferedReader(a);
            String line;
            line = br.readLine();

            while(line != null){
                StringTokenizer st = new StringTokenizer(line, ",");
                while(st.hasMoreTokens()){ 
                    String currentToken = st.nextToken();
                    if(!cityList.contains(currentToken.trim())){ 
                        cityList.add(currentToken.trim());
                    }//if
                }//while hasMoreTokens
                line = br.readLine();//read the next line
            }//while line != null
            br.close();
        }//try

        catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        length = cityList.size(); // set length to amount of unique cities

    }//createCityList
执行另一个文件读取的第二个方法。。。允许我创建邻接矩阵

private static void graph() throws IOException{ 
    cityGraph = new int[cityList.size()][cityList.size()]; 

        try {
            FileReader a = new FileReader(file);
            BufferedReader br = new BufferedReader(a);
            String line;
            line = br.readLine();


            while(line != null){
                StringTokenizer st = new StringTokenizer(line, ",");
                while(st.hasMoreTokens()){ 
                    String firstToken = st.nextToken().trim();
                    String secondToken = st.nextToken().trim();
                    cityGraph[cityList.indexOf(firstToken)][cityList.indexOf(secondToken)] = 1; 
                    cityGraph[cityList.indexOf(secondToken)][cityList.indexOf(firstToken)] = 1; 
                }//while hasMoreTokens

                line = br.readLine();//read the next line

            }//while line != null

            br.close();

        }//try

        catch (FileNotFoundException e) {
            e.printStackTrace();
        }//catch
    }//graph
我的最后一个方法是在这两个城市上运行DFS,以确定其是否连接

private static void isConnected(String s1, String s2){

        city1 = cityList.indexOf(s1); //set city to the index of s1 or s2 in the cityList LinkedList.
        city2 = cityList.indexOf(s2); 


        int startNode = city1;
        q.add(startNode); // start node

        while(!q.isEmpty()){
        //visit vertex
            for(int i = 0; i < length; i++){
                if(cityGraph[startNode][i] == 1){
                    if( i == city2 ){ 
                        System.out.println("yes");
                        return;
                    }//if city2 found
                    q.add(i);
                    cityGraph[startNode][i] = 0; //Set to visited
                }//if vertex exist
            }//for
            q.remove();//remove the top element and start with new node
            if(!q.isEmpty()){
                startNode = (Integer) q.element();
            }//if

        }//while q is not empty     
        System.out.println("no");
    }//isConnected
private static void已连接(字符串s1、字符串s2){
city1=cityList.indexOf(s1);//将city设置为cityList链接列表中s1或s2的索引。
city2=城市列表索引(s2);
int startNode=城市1;
q、 添加(startNode);//开始节点
而(!q.isEmpty()){
//访问顶点
for(int i=0;i
我试图只读取一个文件,但我在从未知大小生成矩阵时遇到了问题。只有在读取文件后,我才能找到大小。任何帮助或建议都将非常有用
谢谢

这是双向图还是单向图

无论哪种方式,您都可以使用地图来表示从一个城市到另一个城市的边缘。鉴于此,您可以编写一个方法

设置getReachableNodes(字符串startingNode,映射可达性)


然后查看所需目标是否在结果集中。

我对代码有一些评论:

1) 以第一个代码段中的行为例:

while(st.hasMoreTokens()){ 
    String currentToken = st.nextToken();
    if(!cityList.contains(currentToken.trim())){ 
        cityList.add(currentToken.trim());
    }//if
}//while hasMoreTokens
while(st.hasMoreTokens()){ 
    String firstToken = st.nextToken().trim();
    String secondToken = st.nextToken().trim();
    cityGraph[cityList.indexOf(firstToken)][cityList.indexOf(secondToken)] = 1; 
    cityGraph[cityList.indexOf(secondToken)][cityList.indexOf(firstToken)] = 1; 
}//while hasMoreTokens
cityList.contains()
方法消耗城市数量的线性时间,而
while(st.hasMoreTokens())
可能会运行
O(V^2)
次,其中V是顶点数,因为可以有密集图。因此,就在这一个循环中,您正在消耗O(V^3)时间,这已经比DFS(在密集图中是
O(V^2)
)最糟糕了。你不能加快O(V^2)循环的速度,因为你必须读取所有的边,但是你可以使用更有效的数据结构来保存城市列表,即散列(
O(1)
lookup,
O(1)
insertion)

2) 在第二个代码段上:

while(st.hasMoreTokens()){ 
    String currentToken = st.nextToken();
    if(!cityList.contains(currentToken.trim())){ 
        cityList.add(currentToken.trim());
    }//if
}//while hasMoreTokens
while(st.hasMoreTokens()){ 
    String firstToken = st.nextToken().trim();
    String secondToken = st.nextToken().trim();
    cityGraph[cityList.indexOf(firstToken)][cityList.indexOf(secondToken)] = 1; 
    cityGraph[cityList.indexOf(secondToken)][cityList.indexOf(firstToken)] = 1; 
}//while hasMoreTokens
完全一样。使用散列而不是列表

3) DFS的内部循环

if(cityGraph[startNode][i] == 1){
    if( i == city2 ){ 
        System.out.println("yes");
        return;
    }//if city2 found
    q.add(i);
    cityGraph[startNode][i] = 0; //Set to visited
}//if vertex exist
有两个问题。一是每次运行DFS时都会覆盖图形表示。通过设置
cityGraph[startNode][i]=0实际上正在删除图形的边。如果要为每个DFS重建图,这将是一个巨大的问题

第二个问题是,在我看来,您以错误的方式标记访问的节点。您只是在标记已访问的边,而不是节点。如果您有路径1->2和路径1->4->2,您将访问(并添加到队列)节点2两次

要解决这两个问题,请使用
boolean[#cities]
数组。每次启动DFS时,都将所有节点设置为未访问。每次检查边时,都会检查是否已访问该节点。如果不是,则将其添加到队列中

最后一点是

q.remove();//remove the top element and start with new node
if(!q.isEmpty()){
    startNode = (Integer) q.element();
}//if
这很难看,因为您已经在检查while循环中的队列是否为空。相反,您可以将此代码移动到while循环的begining,删除if条件(因为您知道队列不是空的):


希望这有帮助……

我认为好的软件的关键是选择最佳的数据结构。我认为这比程序更重要(尽管这些当然很重要)。我不相信一个巨大图形的二维数组和一个巨大城市的列表是最佳的数据结构;对于这两种类型的数据结构,都必须进行线性搜索。这意味着,随着这些数据结构规模的增长,速度将变得更差

因此,我提出了一个重新设计,其中依赖于
HashMap
HashSet
。HashMap的主要值是恒定的查找时间,这意味着性能不会变得更差(如果您对它的工作原理感兴趣,请阅读Wikipedia上的更多内容)

因此,正如上面的一些答案所建议的,伪代码的提纲是:

HashMap<String, HashSet<String>> m = new ...
For each pair c1 c2 {
     if c1 is not a key in m {
          HashSet<String> set = new HashSet<String>
          set.add(c2)
          m.put(c1, set);

     }
     else //c is a key
          m.get(c1).add(c2)
 }
HashMap m=new。。。
对于每对c1和c2{
如果c1不是m中的键{
HashSet=newhashset
集合。添加(c2)
m、 put(c1,set);
}
否则//c是一个键
m、 获取(c1)。添加(c2)
}
现在查看c1和c2是否连接:

boolean isDirectlyConnected(c1, c2) { 
  return m.get(c1).contains(c2) || m.get(c2).contains(c1) 
}         

boolean isConnected (c1, c2) {    //checking the transitive closure of directly connected
   HashSet<String> citiesAlreadyChecked = new ...   //cities whose edges have already been checked
   Queue<String>  citiesToCheck = new ...
   citiesToCheck.push(c1)
   while (citiesToCheck is not empty) {
         String cityBeingCurrentlyChecked = citiesToCheck.pull
         if (isDirectlyConnected(cityBeingCurrentlyChecked,c2)) {
               return true;
         } 
         else {
               citiesAlreadyChecked.add(cityBeingCurrentlyChecked)
               for (String adjacentCity: m.get(cityBeingCurrentlyChecked)) {
                    if (adjacentCity is not in citiesAlreadyChecked) {
                           citiesToCheck.push(adjacentCity)
                    }
               }
          }
    }
    return false  
   //transitive colsure of cities connected to c1 have been checked, and c2 was not found there.

} 
boolean是直接连接的(c1,c2){
返回m.get(c1).contains(c2)| m.get(c2).contains(c1)
}         
布尔不连通(c1,c2){//检查直连通的传递闭包
HashSet citiesAlreadyChecked=new…//已检查边缘的城市
队列检查=新建。。。
citiesToCheck.推送(c1)
while(citiesToCheck不为空){
字符串cityBeingCurrentlyChecked=citiesT