环的寻找:寻找无向图中所有存在的环-删除点法
??????? 此文討論一個無向圖中存在環(huán)的問題,在不管多復(fù)雜的連通圖中尋找出所有的環(huán),使用刪除點的方法。
??????? 此外,這個版本的查找方法可以用于其他場景:找出無向圖中所有的環(huán)的算法?????????????
??????? 結(jié)果能找到最小的環(huán),或許要靠運氣,輸出該輸出的環(huán)...............,這是原始算法。
改進:
可以輸出最大環(huán)(通過跳過多度點),可以輸出最小子環(huán)(通過使用最短路徑)......................
??????? 使用一個圖:
???????
??????? 比如在上圖中,存在多個環(huán)(1,2,3,4,5,6)(6,7,8,9)(1,2,5,6)(1,2,3,5,6).........
??????? 怎么尋找呢?
一、使用刪除邊法
??????? 本例中,從頂點9開始,構(gòu)建DFS
??????? 1.首先刪除所有度數(shù)為1的點,這樣點14就被刪除。這樣只剩下多度頂點的環(huán)
??????????
??????? 2. 若從頂點9開始,找到了環(huán)(9,8,6,7),對于頂點8和頂點7,其所有鏈接的邊都在當(dāng)前環(huán)上,則可以刪除掉兩個頂點;
???????? 而9除了處于環(huán)中的邊,還有其他邊,則不能刪除。此外,頂點6也不能刪除。
???????? 判斷條件: 若頂點X鏈接的邊在這一個環(huán)上,則可以刪除此頂點。
???????? ????
???????????????? 例如:在圖中,刪除的點為7和8,同時所有的鏈接邊也刪除。輸出環(huán)(9.8.7.6)。
??????? 3. 使用堆棧,再次查找10,可以輸出環(huán)(10,11,12,13),同時可以刪除頂點(11,12,13)。此時頂點10 的度置位1,標識為已遍歷狀態(tài)。
???????? ???????
??????? 4.每次查找環(huán),都刪除度為1的節(jié)點和連接邊。此時可以刪除10,9,樹退化為一顆子樹。
?????????????????
? ? 5.到了一個查找重復(fù)環(huán)的時候 ??
???????? 5.1. 此時沒有單度節(jié)點,
???????? 5.2. 出現(xiàn)問題,得重新考慮了!!!
??????? 從頂點6開始找到所有的環(huán):注意此過程依然為生成樹的過程,每一個邊都被設(shè)定為有向邊。
???????
?? Code :
???
// 尋找聯(lián)通集合的閉包,判斷是否連通,返回閉包public static void findSub(Boolean adjM[][], Set<Integer> votex, ArrayList<Set<Integer>> loopSets) {if (votex.size() < 2) {// 治標不治本return;}for (int m = 0; m < adjM.length;++m){adjM[m][m] =false;}// 計算頂點的度Integer[] degrees = new Integer[adjM.length];degrees = calVotexDegree(adjM);//循環(huán)查找,找到所有的度不為1的閉包boolean isdeleted = true;while( isdeleted ){isdeleted = false;degrees = calVotexDegree(adjM);delete1Degree(adjM, degrees);// 刪除度數(shù)為1 的邊int l1 = votex.size();// 更新聯(lián)通集合for (int i = 0; i < degrees.length; ++i) {if (degrees[i] == 0) {votex.remove(i);for (int m = 0; m < adjM.length;++m){adjM[i][m] = false;//更新度,若被移除則相關(guān)的鄰接都置為falseadjM[m][i] = false;}}}int l2 = votex.size();if(l1!=l2) isdeleted = true;}// 遍歷所有節(jié)點,逐個取出,去除非環(huán)節(jié)點Set<Integer> loop = new HashSet<Integer>();Set<Integer> sub = new HashSet<Integer>();boolean isBlankX = false;boolean isFind = false;for (int ob : votex) {int obj = ob;sub.add(obj);int idx = obj;for (int j = idx; j < adjM[idx].length;) {if (adjM[idx][j]) {if (sub.contains(j) && idx != j) {transSet(sub, loop);// 若已存在元素,則存在環(huán),復(fù)制出環(huán)loopSets.add(loop);votex.removeAll(loop);sub.clear();findSub(adjM, votex, loopSets);isFind = true;if (votex.size() < 3) {// 剩余兩個就不再尋找isBlankX = true;}++j;} else {sub.add(j);++j;}} else++j;}if (isFind)break;}return;}
// 輸出頂點的度public static Integer[] calVotexDegree(Boolean adjM[][]) {Integer[] degrees = new Integer[adjM.length];for (int i = 0; i < adjM.length; ++i) {degrees[i] = 0;for (int j = 0; j < adjM[i].length; ++j) {if (adjM[i][j] == true) {degrees[i] = degrees[i] + 1;}}}return degrees;}
// 更新矩陣:刪除權(quán)值為1和0的邊public static void delete1Degree(Boolean[][] adjM, Integer[] degrees) {for (int j = 0; j < adjM.length; ++j) {adjM[j][j] = false;// 自身邊消除掉if (degrees[j] < 2) {for (int k = 0; k < adjM[j].length; ++k) {adjM[j][k] = false;adjM[k][j] = false;}degrees[j] = 0;}}}
輸出結(jié)果:輸出結(jié)果具有一定的概率性,和頂點的排序有關(guān)。
總結(jié)
以上是生活随笔為你收集整理的环的寻找:寻找无向图中所有存在的环-删除点法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: USB鼠标-配置描述符(三)
- 下一篇: 驾校管理html5模板,驾校学员管理系统