依賴關系是開發過程中經常遇到的,例如每個JAVA工程都可以依賴很多其它JAVA工程的制品,在整個進行構建時,就需要考慮這種依賴關系了, 不然總是構建不成功的,本文就以此情景為例,實現一個基於這種依賴關系的多個模塊排序,以便能正常地整個構建成功。
假設有A,B,C,D,E,F六個模塊,它們的依賴關系如下:
A <-- B,C
B <-- D,E
C <-- E
D <-- F
要表達這種抽象的關系,我們可以借助於拓撲圖,如下圖所示:

這種表達方式就比較清晰了,從中可以得出結論,出度為0(即沒有指向其它節點的箭頭)的節點排在最前面,排序的過程就是依次將出度為0的節點移出來,所形成的結果即是最終排序了。
這里用Python來表達排序過程的話,需要用字典類型來記錄依賴關系,具體代碼如下:
1 #!python 2 # coding:GB18030 3 ################################################################################################### 4 # 5 # 基於依賴關系的排序 6 # 情景:A <-- B,C 7 # B <-- D,E 8 # C <-- E 9 # D <-- F 10 # 11 # 12 #################################################################################################### 13 14 import os 15 16 def clearKeyFromVal(key, vals): 17 """從各Value中清除指定的Key 18 相當於在拓撲圖中移出一個節點后,要清除所有與該節點的關聯,即箭頭 19 """ 20 for val in vals: 21 if type(val) is tuple and key in val: 22 vl = list(val) #因為要對元組內容修改,需要轉為list類型 23 ln = vl.index(key) 24 vl.pop(ln) 25 tn = vals.index(val) 26 if len(vl) == 0: 27 vals[tn] = "" 28 else: 29 vals[tn] = tuple(vl) #將內容改變后,重新轉回tuple類型 30 return vals 31 32 33 34 def clearNullVal(keys, vals, result_list): 35 """將值為''的鍵值對移出字典(值為""的鍵即為在拓撲圖中出度為0的節點) 36 37 遞歸調用 38 """ 39 if "" in vals: 40 nn = vals.index("") 41 vals.pop(nn) 42 key = keys.pop(nn) 43 result_list.append(key) #移出的鍵,放到結果List中 44 vals = clearKeyFromVal(key, vals) #清除與移出鍵相關聯的箭頭,即需要在各個value中也清除該值 45 return clearNullVal(keys, vals, result_list) #注意這里要return結果 46 elif len(vals) == 0: 47 return result_list #移出所有Value后,退出 48 else: 49 print '存在循環依賴' 50 return 51 52 53 def sortModules(dic): 54 55 """根據依賴關系,將多個模塊進行排序,被依賴的模塊要在前""" 56 keys = dic.keys() 57 vals = dic.values() 58 mlist = [] 59 for val in vals: 60 if type(val) is tuple: 61 for tv in val: 62 if tv not in dic: 63 dic[tv] = "" #將沒有依賴的鍵也添加到字典中,以方便后續對整個字典遞歸處理,逐個將值為""的鍵移出,形成排序結果 64 65 print dic 66 return clearNullVal(dic.keys(), dic.values(), mlist) 67 68 69 if __name__ == "__main__": 70 71 #通過字典結構來表示依賴關系 72 73 dic={'A':('B','C'),'B':('D','E'),'C':('E', ), 'D': ('F', )} 74 r_list = sortModules(dic) 75 print r_list
注:1)要注意判斷是否存在循環依賴,即在拓撲圖中形成環,即始終找不到出度為0的節點。
2)移出節點時,運用了遞歸調用方式。
3)雖然依賴關系是用字典類型來表達的,但處理過程中,將字典的鍵和值分為兩個列表來處理,同步移出節點
4)依賴關系,在字典中是用元組作為Value的(因為它是不可變的,即可哈希的),在操作過程中,又適時與列表類型轉換
5) 一開始先將字典補充完整,即沒有依賴其它的模塊也加進去,為的就是通過遞歸方式,統一操作處理,不然,處理這非規則的情況,也比較麻煩,破壞使用遞歸的條件。
運行結果:

以上便是整個排序過程,如有高見,請不吝賜教
