2011-02-17 31 views
2

所以我有這個任務,我一次讀了一行,每次用逗號隔開,例如,幫助遍歷節點/輸入文件讀取

Atlanta, Philadelphia 
New York, Philadelphia 
Philadelphia, Chicago 
Washington, Florida 
..... 
up to a vast amount.. (I don't know the amount) 

每一行代表在兩個位置之間的連接(例如亞特蘭大連接到費城)創建連接的節點和未連接等華盛頓和佛羅里達被連接到彼此,但沒有其他人的節點。

該程序假設要讀取該文件並給出兩個城市參數,假設其連接/如果不連接則返回否。

我完成了我的程序,它的工作原理,但它效率不高。我很難理解我能做些什麼。這是使代碼效率低下的程序的一部分。

這第一個輸入讀取文件,以便我可以確定不同城市的列表大小,它還可以刪除任何重複的城市。

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 

這確實另一FILEREAD第二方法......讓我以創建鄰接矩陣

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 

我的最後一個方法運行在2個城市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 

我想只有一個文件讀取,但我有問題從一個未知的大小製作矩陣它只有在文件讀取後,我發現大小。任何幫助或建議將大大 讚賞!

回答

2

我對代碼幾點意見:

1)取在所述第一代碼段的那些行:

while(st.hasMoreTokens()){ 
    String currentToken = st.nextToken(); 
    if(!cityList.contains(currentToken.trim())){ 
     cityList.add(currentToken.trim()); 
    }//if 
}//while hasMoreTokens 

cityList.contains()方法消耗上城市的數量線性時間,while(st.hasMoreTokens())可能會運行O(V^2)次,其中V是頂點的數量,因爲您可以有一個密集圖。所以,就在這一個循環中,你消耗的O(V^3)時間已經比DFS(O(V + E),即密集圖中的O(V^2))差。您不能加速O(V^2)循環,因爲您必須讀取所有邊,但可以使用更高效的數據結構來保存該城市列表,即散列(O(1)查找,O(1)插入)。

2)在第二代碼片斷:

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的圖形,那是一個巨大的問題。

第二個問題是,在我看來,你正在以錯誤的方式標記訪問節點。你只是標記訪問EDGES,而不是節點。如果你有路徑1 - > 2和路徑1 - > 4 - > 2,你將要訪問(並添加隊列)節點2兩次。

要解決這兩個問題,請使用boolean visited[#cities]陣列。每次啓動DFS時,都會將所有節點設置爲未訪問。每次檢查邊緣時,都會檢查是否已經訪問過該節點。如果沒有,請將其添加到隊列中。

關於最後一點,

q.remove();//remove the top element and start with new node 
if(!q.isEmpty()){ 
    startNode = (Integer) q.element(); 
}//if 

這是醜陋的,因爲你已經檢查,如果隊列是在while循環空。相反,你可以只移動這個代碼while循環的beggining,去除如果條件(因爲你知道的隊列不爲空):

while(!q.isEmpty()){ 
    startNode = (Integer) q.element(); 
    q.remove(); 

希望幫助....

1

這是一個雙向或單向圖嗎?

無論採用哪種方式,您都可以使用地圖來表示從一個城市到另一個城市的邊緣。鑑於此,您可以編寫一個方法

Set getReachableNodes(String startingNode,Map reachability);

並查看期望的目標是否在結果集合中。

+0

實際上,我不知道,如果它的雙向或uni我給出的小樣本輸入文件不需要雙向來獲取跨地點的方式 – xiaolin 2011-02-17 05:04:04

+0

您可以詳細說明使用Map的含義嗎?我實際上從來沒有使用過它..地圖上有一個關鍵字和一個附加值。我怎樣才能使用這個來實現city1連接city2,它連接到city6 ...等等...... – xiaolin 2011-02-17 05:10:35

+0

是的,假設你有String標籤,使用`Map `來表示從一個節點(關鍵字)到另一個(值)。所以說有從奧克蘭到聖何塞,聖何塞到奧克蘭,從奧克蘭到舊金山的邊緣: – 2011-02-17 05:14:12

1

我認爲好軟件的關鍵在於選擇最佳的數據結構。我認爲這比程序更重要(當然這些重要)。我不相信二維數組是一個巨大的圖表,而大量的城市列表是最佳的數據結構;對於這兩種類型的數據結構,您都不得不進行線性搜索。這意味着隨着這些數據結構的增長,速度會變得更糟。

因此,我建議重新設計您依靠HashMap<String>HashSet<String>。 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) 
} 

現在用於查找,如果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. 

} 

人們還可以使圖雙重聯繫,從而擺脫||在isDirectlyConnected中。使雙聯,同時通過調用

m.put構建完成(C1,設定C2加)和 m.put(C2,加入C1組)