1. 程式人生 > >圖的基礎知識學習(一)

圖的基礎知識學習(一)

終於決定學一下圖了,圖一直以為是一種蠻有意思的方法。
圖G=(V,E),V表示頂點數,E表示邊數,圖可以分為有向圖和無向圖,有兩種標準的方法,即鄰接表和鄰接矩陣。
鄰接表有V個列表的Adj陣列組成,Adj[u]包含圖G中的所有和頂點u相連的頂點,在無向圖中的順序是任意的,在有向圖中和圖的方向有關。鄰接矩陣在無向圖中為頂點的點為1,其餘為零,有向圖中則和方向有關,如下圖所示。
這裡寫圖片描述
鄰接表無論是有向圖還是無向圖的儲存空間都為O(V+E),但有潛在的不足及,要搜尋邊(u,v)是否存在只能在Adj[u]陣列中搜索v;鄰接矩陣的儲存空間為O(V2),所需的儲存空間較大,但搜尋邊(u,v)的速度較快。對於無向圖的鄰接矩陣,如上圖所示為一個對稱矩陣,儲存空空間可以再縮小一半。
圖搜尋演算法主要分為兩種:廣度優先演算法和深度優先演算法
廣度優先演算法(BFS)中:
對於給定的圖G和源頂點s,優先對s的相鄰邊進行搜尋,以求發現所有s可以到達的頂點,同時還能生成一顆根為s,包含所有s能到達的廣度優先樹,適用於無向圖和有向圖。廣度優先演算法先發現與發現點與未發現的點之間的邊界,沿其廣度方向向外擴充套件,即會先發現1所有距離為k的點然後發現距離為k+1的點。
如下圖所示:
這裡寫圖片描述


程式碼(來自維基百科):

def breadth_first_search(problem):

  # a FIFO open_set
  open_set = Queue()

  # an empty set to maintain visited nodes
  closed_set = set()

  # a dictionary to maintain meta information (used for path formation)
  # key -> (parent state, action to reach child)
  meta = dict()

  # initialize
root = problem.get_root() meta[root] = (None, None) open_set.enqueue(root) # For each node on the current level expand and process, if no children # (leaf) then unwind while not open_set.is_empty(): subtree_root = open_set.dequeue() # We found the node we wanted so stop and emit a path.
if problem.is_goal(subtree_root): return construct_path(subtree_root, meta) # For each child of the current tree process for (child, action) in problem.get_successors(subtree_root): # The node has already been processed, so skip over it if child in closed_set: continue # The child is not enqueued to be processed, so enqueue this level of # children to be expanded if child not in open_set: meta[child] = (subtree_root, action) # create metadata for these nodes open_set.enqueue(child) # enqueue these nodes # We finished processing the root of this subtree, so add it to the closed # set closed_set.add(subtree_root) # Produce a backtrace of the actions taken to find the goal node, using the # recorded meta dictionary def construct_path(state, meta): action_list = list() # Continue until you reach root meta data (i.e. (None, None)) while meta[state][0] is not None: state, action = meta[state] action_list.append(action) action_list.reverse() return action_list

深度優先演算法(DSF):
在演算法的搜尋過程中,對於發現的新的頂點,如果它還有以此為起點而未探測到的邊,就研此邊搜尋下去。當頂點v的所有邊都被搜尋後回到發現v頂點那邊開始搜尋其他邊,直到所有的頂點都被搜尋完。
下面是深度優先演算法的虛擬碼:
這裡設定兩個時間戳d[v],f[v],d[v]表示發現點v,f[v]表示結束髮現點v,這裡設定未發現點v為白色,發現後變灰色,結束搜尋點v所在的支路後為黑色;

DFS(G)
for each vertes u∈V[G]
    do color[u]<- WHITE
        π[u]<-NIL
time<-0
for each vertex u∈V[G]
    do if color[u]=WHITE
        then DFS-VISIT(u)

DFS-VISIT(u)
color[u]<-GRAY
time<-time+1
d[u]<-time+1
for each v∈Adj[u]
    do if color[v]=WHITE
        then π[v]<-u
            DFS-VISIT(v)
color[u]<-BLACK
f[u]<-time<-time+1

這裡寫圖片描述
先初始化整個圖為白色,π域為NIL,置定時器為0,再依次檢索V中的頂點,當發現白色頂點時呼叫DFS-VISIT訪問。
呼叫DFS-VISIT時置u為灰色,增加time的值,記錄發現u的值,再檢查和u相鄰的頂點v如果為白色則遞迴呼叫DFS-VISIT,當以u為起點的所有邊都被搜尋後值u為黑色,並記錄時間在f[u].
這裡寫圖片描述