graph演算法
❶ 數據結構——圖graph(基礎概念)
【各種東拼西湊來的】
圖(Graph)是由頂點和連接頂點的邊構成的離散結構。在計算機科學中,圖是最靈活的數據結構之一,很多問題都可以使用圖模型進行建模求解。例如:生態環境中不同物種的相互競爭、人與人之間的社交與關系網路、化學上用圖區分結構不同但分子式相同的同分異構體、分析計算機網路的拓撲結構確定兩台計算機是否可以通信、找到兩個城市之間的最短路徑等等。
圖的結構很簡單,就是由頂點$V$集和邊$E$集構成,因此圖可以表示成$G=(V, E)$。
注意: 頂點有時也稱為節點或者交點,邊有時也稱為鏈接。
無向圖
我們可以說這張圖中,有點集$V=\{1, 2, 3, 4, 5, 6\}$,邊集$E=\{(1, 2), (1, 5), (2, 3), (2, 5), (3, 4), (4, 5), (4, 6)\}$。在無向圖中,邊$(u, v)$和邊$(v, u)$是一樣的,因此只要記錄一個就行了。簡而言之,對稱。
有向圖
也很好理解,就是加上了方向性,頂點$(u, v)$之間的關系和頂點$(v,u)$之間的關系不同,後者或許不存在。例如,地圖應用中必須存儲單行道的信息,避免給出錯誤的方向。
加權圖 :
權:與圖的邊或弧相關的數叫做權。
與加權圖對應的就是無權圖,或叫等權圖。如果一張圖不含權重信息,我們就認為邊與邊之間沒有差別。不過,具體建模的時候,很多時候都需要有權重,比如對中國重要城市間道路聯吵隱笑系的建模,總不能認為從北京去上海和從北京去廣州一樣遠(等權)。
還有很多細化的概念,比如:無向圖中,任意兩個頂點間都有邊,稱為 無向完全圖 ;加權圖起一個新名字,叫 網(network) ……然而,如無必要,毋增實體。
鄰接(adjacency) :鄰接是 兩個頂點之間 的一種關系。如果圖包含$(u,v)$,則稱頂點$v$與頂點$u$鄰接。當然,在無向圖中,這也意味著頂點$u$與頂點$v$鄰接。
關聯(incidence) :關聯是 邊和頂點之間 的關系。在有向圖中,邊$(u,v)$從頂點$u$開始關聯到$v$,或者相反,從$v$關聯到$u$。注意,有向圖中,邊不一定是對稱的,有去無回是完全有可能的。細化這個概念,就有了頂點的 入度(in-degree) 和 出度(out-degree) 。無向圖中,頂點的度就是與頂點相關聯的邊的數目,沒有入度和出度。在有向圖中,我們以圖1-2為例,頂點10有2個入度,$3\rightarrow10$,$11\rightarrow10$,但是升含沒有從10指向其它頂點的邊,因此頂點10的出度為0。
路徑(path) :依次遍歷頂點序列之間的邊所形成的軌跡。注意,依次就意味著有序,先1後2和先2後1不一樣。
簡單路徑 : 沒有重復頂點的路徑稱為簡單路徑。說白了,這一趟路里沒有出現繞了一圈回到同一點的情況,也就是沒有 環 。
環/迴路 :包含相同的頂點兩次或者兩次以上。圖1-3中的頂點序列$<1,2,4,3,1>$,1出現了兩次,當然還有其它的環,比如$<1,4,3,1>$。
簡單迴路/簡單環: 除了第一個頂點和最後一個頂點之外,其餘頂點不重復出現的迴路
無環圖 :沒有環的圖,攜畢其中, 有向無環圖 有特殊的名稱,叫做 DAG(Directed Acyline Graph) (最好記住,DAG具有一些很好性質,比如很多動態規劃的問題都可以轉化成DAG中的最長路徑、最短路徑或者路徑計數的問題)。
兩個連通分支:
連通的 :無向圖中每一對不同的頂點之間都有路徑。如果這個條件在有向圖里也成立,那麼就是 強連通 的。
連通分量 :無向圖中的極大連通子圖。
兩點強連通:在有向圖G中,如果兩點互相可達
強連通圖: 如果有向圖G的每兩個頂點都強連通(任意兩點互相可達),稱G是一個 強連通圖 。
強連通分量: 非強連通有向圖的極大強連通子圖,稱為強連通 分量 (strongly connected components)。
關節點(割點) :某些特定的頂點對於保持圖或連通分支的連通性有特殊的重要意義。如果 移除某個頂點 將使圖或者分支 失去連通性 ,則稱該頂點為 關節點 。(在某圖中,若刪除頂點V以及V相關的邊後,圖的一個連通分量分割為兩個或兩個以上的連通分量,則稱頂點V為該圖的一個關節點)。
橋(割邊) :和關節點類似,刪除一條邊,就產生比原圖更多的連通分支的子圖,這條邊就稱為 割邊 或者 橋 。
雙連通圖 :在無向連通圖中,如果刪除該圖的任何一個結點都不能改變該圖的連通性,則該圖為雙連通的無向圖。個人理解就是一個雙連通圖沒有割點,沒有橋的圖。
1.2 一些有趣的圖概念
這一部分屬於圖論的內容,基礎圖演算法不會用到,但是我覺得挺有意思的,小記如下。【這部分我沒看,照搬過來了】
同構 4 :圖看起來結構不一樣,但它是一樣的。假定有$G_1$和$G_2$,那麼你只要確認對於$G_1$中的所有的兩個 相鄰點 $a$和$b$,可以通過某種方式$f$映射到$G_2$,映射後的兩個點$f(a)$、$f(b)$也是相鄰的。換句話說,當兩個簡單圖同構時,兩個圖的頂點之間保持相鄰關系的一一對應。
圖1-7就展示了圖的同構,這里頂點個數很少判斷圖的同構很簡單。我們可以把v1看成u1,自然我們會把u3看出v3。用數學的語言就是$f(u_1)=v_1$,$f(u_3)=v_3$。u1的另外一個連接是到u2,v1的另外一個連接是到v4,不難從相鄰頂點的關系驗證$f(u_2)=v_4$,$f(u_4)=v_2$。
歐拉迴路(Euler Circuit) :小學數學課本上的哥尼斯堡七橋問題,能不能從鎮里的某個位置出發 不重復的經過所有橋(邊)並且返回出發點 。這也就小學的一筆畫問題,歐拉大神解決里這個問題,開創了圖論。結論很簡單:至少2個頂點的連通多重圖存在歐拉迴路的充要條件是 每個頂點的度都是偶數 。證明也很容易,大家有興趣可以閱讀相關資料。結論也很好理解,從某個起點出發,最後要回起點,中間無論路過多少次起點,都會再次離開,進、出的數目必然相等,故一定是偶數。
哈密頓迴路(Hamilton Circuit) :哈密頓迴路條件就比歐拉迴路嚴格一點, 不能重復經過點 。你可能會感到意外,對於歐拉迴路,我們可以輕而易舉地回答,但是 我們卻很難解決哈密頓迴路問題,實際上它是一個NP完全問題 。這個術語源自1857年愛爾蘭數學家威廉·羅萬·哈密頓爵士發明的智力題。哈密頓的智力題用到了木質十二面體(如圖1-8(a)所示,十二面體有12個正五邊形表面)、十二面體每個頂點上的釘子、以及細線。十二面體的20個頂點用世界上的不同城市標記。智力題要求從一個城市開始,沿十二面體的邊旅行,訪問其他19個城市,每個恰好一次,最終回到第一個城市。
因為作者不可能向每位讀者提供帶釘子和細線的木質十二面體,所以考慮了一個 等價的問題 :對圖1-8(b)的圖是否具有恰好經過每個頂點一次的迴路?它就是對原題的解,因為這個平面圖 同構 於十二面體頂點和邊。
著名的 旅行商問題(TSP) 要求旅行商訪問一組城市所應當選取的最短路線。這個問題可以歸結為求完全圖的哈密頓迴路,使這個迴路的邊的權重和盡可能的小。同樣,因為這是個NP完全問題,最直截了當的方法就檢查所有可能的哈密頓迴路,然後選擇權重和最小的。當然這樣效率幾乎難以忍受,時間復雜度高達$O(n!)$。在實際應用中,我們使用的啟發式搜索等 近似演算法 ,可以完全求解城市數量上萬的實例,並且甚至能在誤差1%范圍內估計上百萬個城市的問題。
關於旅行商問題目前的研究進展,可以到 http://www.math.uwaterloo.ca/... 。
1.3 小結
以為可以一帶而過,結果寫了那麼多。也沒什麼好總結的了,當然這些也至是圖論概念的一小部分,還有一些圖可能我們以後也會見到,比如順著圖到網路流,就會涉及二分圖,不過都很好理解,畢竟有圖。
1、數組(鄰接矩陣)
2、鄰接表
3、十字鏈表
4、鄰接多種表
❷ GraphCut——GrabCut
此種演算法是對圖像進行分割操作,其將一幅圖像轉換成圖形結構來描述,通過找到圖中的最小割,從而將圖像中的前景與背景進行分割。
1、GraphCut
如上圖所示,將圖中的像素點作為圖中的點集,相鄰像素通過邊相連,另外多出的兩個點S,T分別代表的是歸於前景的點和歸於背景的點。對每個邊設置相應的權重,圖割的目的就在於利用最小割的方法將邊緣部分進行分割,此時的能量值(損失值)最小,由此得到對應的S,T集合,達到分割的目的。過程如下圖所示(其中B,O代表事先設置的種子點,由此知道分割出來的部分哪個代表背景,哪個代表目標;B代表該點屬於背景點,O代表該點屬於目標點):
2、GrabCut:
GrabCut是基於GraphCut的改進演算法,通過交互的方式得出前景與背景。
為什麼畫個框就能分割出前景與背景呢?
在框選出區域後,則將選框以外的部分視為背景區域,將選框以內的區域視為可能的前景區域。然後通過計算前景高斯混合模型(GMM)和背景GMM,然後對每一個像素的rgb值代入單個的高斯模型進行計算,選取值最大的那個模型作為該像素點的歸屬,然後再建立一個圖,對該圖求解最小隱此割,如此循環直至收斂,由此判斷得出選框內的前景區域與背景區域。
那關鍵在於如何得出前景與背景的GMM呢?
不同於GraphCut中的一次性求解圖的最衡野小割問題,GrabCut中採用的是迭代優化的方式逐步求解得出GMM。其具體過程如下圖所示:·
*其實對於這兩個演算法的具體實現並不是很清楚,在這兒只是想大體了解有這樣的一種分割的演算法,故也就不深究其是如何具體實現的了~另外Opencv中已經實現了GrabCut演算法,可以去玩玩~~
的確玩了一回,在進行區域分割的時候,通過將圖咐攜喊像進行二值化處理後,將其作為掩模來進行grabcut操作。但是處理速度比較慢,並且分割的准確性主要依賴二值圖像的質量~。
❸ graphgraphics區別
1、區別使用范圍:graph主要用於演算法、數據結褲睜構、網路等領域;graphics則用於計算機圖形學、設計等領域。
2、了解概念和定義:graph和graphics分別代表不同的概念和定義,需要在實際運用汪碰中使用正確的術語。
3、學習相關應用技術:要對graph和胡陵歲graphics相關的應用技術有足夠的了解,才能更好地運用和發揮其應用價值。
❹ GraphX和Graphscope哪個演算法更厲害
GraphScope的性能更優, GraphLab將數據抽象成Graph結構,非常的厲害
❺ python graph怎麼看
圖結構(Graph)——演算法學中最強大的框架之一。樹結構只是圖的一種特殊情況。
如果我們可將自己的工作詮釋成一個圖問題的話,那麼該問題至少已經碰判接近解決方案了。而我們我們的問題實例可以用樹結構(tree)來詮釋,那麼我們基本上已經擁有了一個真正有效的解決方案了。
鄰接表及加權鄰接字典
對於圖結構的實現來說,最直觀的方式之一就是使用鄰接列表。基本上就是針對每個節點設置一個鄰接列表。下面我們來實現一個最簡單的:假設我們現有 n 個節點,編號分別為 0, …, n-1.
節點當然可以是任何對象,可被賦予任何標簽或名稱。但使用 0, …, n-1 區間內的整數來實現的話,會簡單許多。因為如果我們能用數字來代表節點,我們索引起來顯然要方便許多。
然後,每個鄰接(鄰居)列表都只是一個數字列表,我們可以將它們編入一個大小為 n 的主列表,並用節點編號對其進行索引。由於這些列表內的節點的順序是任意的,所以,實際上,我們是使用列表來實現鄰接集(adjacency sets)。這里之所以還是使用列表這個術語,主要是因為傳統。幸運的是,Python 本身就提供獨立的 set 類型。
我們以下圖為例,說明圖結構的各種表示方笑凳改法(當我們在執行與圖相關的工作時,粗孝需要反復遵從一個主題思想,即一個圖的最佳表示方法應該取決於我們要用它來做什麼):
a, b, c, d, e, f, g, h = range(8)N = [ {b, c, d, e, f}, {c, e}, {d}, {e}, {f}, {c, g, h}, {f, h}, {f, g}]1234567891011
在圖論中,N(v)代表的是v的鄰居節點集;
>>> b in N[a] # neighborhood membershipTrue>>> len(N[f]) # out-degree:出度31234
加權鄰接字典
使用dict類型來代替set或list來表示鄰接集。在 dict 類型中,每個鄰居節點都會有一個鍵和一個額外的值,用於表示與其鄰居節點(或出邊)之間的關聯性,如邊的權重。
a, b, c, d, e, f, g, h = range(8)
N = [
{b:2, c:1, d:3, e:9, f:4},
{c:4, e:4},
{d:8},
{e:7},
{f:5},
{c:2, g:2, h:2},
{f:1, h:6},
{f:9, g:8}
]123456789101112
客戶端調用:
>>> b in N[a] # neighborhood membership
True
>>> len(N[f]) # out-degree
3
>>> N[a][b] # Edge weight for (a, b)
2123456
鄰接矩陣
鄰接矩陣是圖的另一種表示方法,這種表示方法的主要不同在於,它不再列出每個節點的所有鄰居節點。
a, b, c, d, e, f, g, h = range(8)
N =[
[0, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 1, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 1, 0, 0, 0, 1, 1],
[0, 0, 0, 0, 0, 1, 0, 1],
[0, 0, 0, 0, 0, 1, 1, 0],
]12345678910111213
關於鄰接矩陣:
(1)主對角線為自己到自己,為0
(2)行和為出度
(3)列和為入度
❻ c++實現的圖(graph)的演算法,怎麼能可視化演
#pragma comment(lib,"user32")#pragma comment(lib,"gdi32")#include <stdio.h>#include <stdlib.h>#include <windows.h>HWND WINAPI GetConsoleWindow();void HideTheCursor() { CONSOLE_CURSOR_INFO cciCursor; HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); if(GetConsoleCursorInfo(hStdOut, &cciCursor)) { cciCursor.bVisible = FALSE; SetConsoleCursorInfo(hStdOut, &cciCursor); }}void ShowTheCursor() { CONSOLE_CURSOR_INFO cciCursor; HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); if(GetConsoleCursorInfo(hStdOut, &cciCursor)) { cciCursor.bVisible = TRUE; SetConsoleCursorInfo(hStdOut, &cciCursor); }}int main() { HWND hwnd; HDC hdc; HFONT hfont; system("color F0"); system("cls"); HideTheCursor(); hwnd = GetConsoleWindow(); hdc = GetDC(hwnd); hfont = CreateFont(48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "華文楷體"); SelectObject(hdc,hfont); TextOut(hdc,10,10,"地球人都知道!",14); MoveToEx(hdc,5,5,NULL); LineTo(hdc,300, 5); LineTo(hdc,300, 60); LineTo(hdc, 5, 60); LineTo(hdc, 5, 5); DeleteObject(hfont); ReleaseDC(hwnd,hdc); getchar(); system("color 07"); system("cls"); ShowTheCursor(); return 0;}
❼ graphx 實現floyd演算法,並記錄路徑
https://my.oschina.net/uchihamadara/blog/834852
這里使用graphx 實現了好幾個圖路徑演算法念閉,但是都沒有記錄路徑。
圖演算法包括pregel包,其實都是皮顫基於aggreationMessage 來做的。
我們的演算法也是,在發送的消息裡面,需要記錄路徑
核心思想,就是設計傳遞的消息體,
不但要包含,當前最短路徑,還需要記錄最短路徑涉及的 path 記錄。仔握裂
Map[VertexId, (Double,List[VertexId]) ]
這個Double是當前最短路徑的值, List<VertexId> 就是走過的路徑節點集合。
這個list 可以擴展設計,比如包含path 的 節點和邊,以及你想要的屬性。都是可以的。
❽ 幾種常見的Graph Embedding方法
在介紹Graph Embedding之前,我們先回顧什麼是Embedding? Embedding在數學上是一個函數,將一個空間的點映射到另一個空間,通常是從高維抽象的空間映射到低維的具象空間。Embeding的意義將高維數據轉換到低維利於演算法的處理;同時解決one-hot向量長度隨樣本的變化而變化,以及無法表示兩個實體之間的相關性這一問題。
最常見的embeding方法是word2vec,根據語料庫中單詞的共現關系求出每個單詞的embedding,常用的word2vec模型有cbow和skip-gram兩種,cbow根據上下文預測賀芹中心詞,skip-gram根據中心詞預測上下文(詳見word2vec 中的數學原理詳解)。因此既然自然語言中的單詞可以通過共現關系進行embedding,那麼將graph類比成整個語料庫,圖中的節點類比成單詞,我們是否也可以通過耐歲共現關系對graph中的node進行embedding?對於word2vec而言,語料庫中的每個句子都可以描述單詞之間的共現,對於graph,這種共現關系如何描述呢?接下來我們將對多種不同的graph embedding方式進行展開。
Graph Embedding 的中心思想就是找到一種映射函數,該函數將網路中的每個節點轉換為低維度的潛在表示。利於計算存儲,不用再手動提特徵(自適應性),下圖是graph embeding的幾種常見分類:
DeepWalk 通過將節點視為單詞並生成短隨機遊走作為句子來彌補網路嵌入和單詞嵌入之間的差距。然後,可以將諸如 Skip-gram 之類的神經語言模型應用於這些隨機遊走以獲得網路嵌入。其優點是首先其可以按需生成隨機遊走。由於 Skip-gram 模型也針對每個樣本進行了優化,因此隨機遊走和 Skip-gram 的組合使 DeepWalk 成為在線演算法。其次,DeepWalk 是可擴展的,生成隨機遊走和優化 Skip-gram 模型的過程都是高效且平凡的並行化。最重要的是,DeepWalk 引入了深度學習圖形的範例。
用SkipGram的方法進行網路中節點的表示學習。那麼,根據SkipGram的思路,最重要的就是定義Context,也就是Neighborhood。NLP中,Neighborhood是當前Word周圍的字,本文用隨機遊走得到Graph或者Network中節點的Neighborhood。
(1)隨機遊走隨機均勻地選取網路節點,並生成固定長度的隨機遊走序列,將此序列類比為自然語言中的句子(節點序列=句子,序列中的節點=句子中的單詞),應用skip-gram模型學習節點的分布式表示。
(2)前提昌拍睜:如果一個網路的節點服從冪律分布,那麼節點在隨機遊走序列中的出現次數也服從冪律分布,並且實證發現NLP中單詞的出現頻率也服從冪律分布。
預測上下 文節點)--------- output:representation
node2vec在DW的基礎上,定義了一個bias random walk的策略生成序列,仍然用skip gram去訓練。
論文分析了BFS和DFS兩種遊走方式,保留的網路結構信息是不一樣的。 DeepWalk中根據邊的權重進行隨機遊走,而node2vec加了一個權重調整參數α:t是上一個節點,v是最新節點,x是候選下一個節點。d(t,x)是t到候選節點的最小跳數。 通過不同的p和q參數設置,來達到保留不同信息的目的。當p和q都是1.0的時候,它等價於DeepWalk。
利用SkipGram的方法,來為Networks抽取Representation。那麼,自然,根據SkipGram的思路,最重要的就是定義這個Context,或者說是Neighborhood。從文本的角度來說,這個Neighborhood當然就是當前Word周圍的字,這個定義非常自然。但是對於Graph或者Network來說就來得沒那麼容易了。
(1)先區分兩個概念:
一階相似度:直接相連節點間,例如6與7。
定義節點vi和vj間的聯合概率為
v代表節點,u代表節點的embedding。上面式子的意思是兩節點越相似,內積越大,sigmoid映射後的值越大,也就是這兩節點相連的權重越大,也就是這兩個節點間出現的概率越大???。
二階相似度:通過其他中介節點相連的節點間例如5與6。
用的是一個條件概率
(2)目標是讓NRL前後節點間相似度不變,也節點表示學習前如果兩個節點比較相似,那麼embedding後的這兩個節點表示向量也要很相似。--此文中用的是KL散度,度量兩個概率分布之間的距離。
以保證其一階相似度為例子:
embedding前:節點vi和vj間的經驗聯合概率為
所以,最小化:
前面說了很多GE的模型,從古典方法,到只考慮結構的模型,再到考慮節點和變extra info的模型,再到深度模型,大家可能覺眼花繚亂,並不知道實際中應該用哪個模型。
這里我提一句,你選擇的模型一定要和你的實際問題相關:
1.比如你的問題更加關注內容相似性(局部鄰域相似性)那麼你可以選擇node2vec,LINE,GraRep等;
2.如果你的問題更加關注結構相似性,你可以選擇struc2vec,這里可以簡單說以下為什麼螞蟻金服風控模型使用struc2vec相比node2vec有質的提升,這是因為在風控領域,你可信並不能代表你的鄰居可信(有些「大 V」節點的鄰居眾多),但是一個直觀的感覺是,如果兩個人在圖中處於相似的地位(比如兩個「大 V」),那麼這兩個人應該都可信或都不可信,並且一般來說這樣兩個人(節點)相距較遠;
3.再者如果你的模型需要考慮節點和邊的額外信息,那麼你可選擇CANE,CENE,Trans-net等;
4.如果你想處理大規模易變圖,你可以採用GraphSAGE,或者先使用其他GE方法,再使用GraphSAGE歸納學習;
如果你想微調你的模型,你可選擇GraphGAN;
甚至你可以選擇很多GE方法,並將得到的embedding向量進行聚合,比如concat等方式。
Graph Embedding作為知識圖譜的經典方法之一,其應用非常廣泛。當今國內外互聯網搜索引擎公司已經意識到知識圖譜的戰略意義,紛紛構建知識圖譜,如Google知識圖譜(Google Knowledge Graph),網路「知心」和搜狗的「知立方」,以此來改進搜索質量,知識圖譜對搜索引擎形態日益產生重要的影響。
了解更多關於知識圖譜、Graph Embedding干貨知識,鎖定8月20日(星期四)下午14:00公開課!
❾ Graph簡述
remarks: 從bear導入的,不可見圖為草稿,重點部分都有寫。
連通圖漏沒首(connected graph):如果從任意一個頂點都存在一條路徑到達另一個任意頂點(undirected graph)
樹:是一幅無環無向連通圖察晌
森林:1個or幾個樹
簡單路徑(simple path):一條沒有重復頂點的路徑
簡單環(simple cycle):一條(除了起點和終點必須相同之外)不含有重復頂點和邊的環
adjacent: when 2 v are connected by a single edge
biconnectivity/ biconnected graph: 移除一條邊也不會使graph成為unconnected的graph
subgraph(of graph G):只取G中的幾個頂點構成的圖
spanning subgraph:取G中所有頂點構成的圖
spanning tree:是G的subgraph+是tree=由G中所有頂點構成的無環無向連通圖(spanning tree不唯一)
directed edge: 有箭頭的邊,eg. flight(從A點到B點)
undirected edge: 無箭頭的邊,eg. flight route(A和B的距離)
directed graph
undirected graph
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-WUgPCDy8-1605523062295)(Graph/24905163-e121bc7bba6f78d1.png)]
space: O(V^2)
add edge: O(1)
check if adjacent: O(1)
iteration: O(V)
eg: [ [0,1], [0, 2], [0, 5], [1, 2], [2, 3], [2, 4], [3, 4], [3, 5] ]
Edge里含兩個int變數
space: O(E)
add edge: O(1)
check if adjacent: O(E)
iteration: O(E)
0: 6--->5--->2--->1
1: 3--->0
2: 0
3: 5--->1
4: 6--->5
5: 4--->3--->0
6: 7--->4--->0
7: 8--->6
8: 10--->7
9: 11--->返數10
10: 12--->9--->8
11: 9
12: 10
a) 使用的空間和V+E成正比
b) 添加一條邊所需的時間為常數
c) 遍歷頂點v的所有相鄰頂點所需的時間和v的度數成正比
d) 每條邊會出現兩次
space: O(V+E)
add edge: O(1)
check adjacent: deg(v) <- vertex v
iteration: deg(v)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-4Z4nziuk-1605523062297)(Graph/Photo%20Nov%2013,%202020%20at%20105929%20PM.jpg)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-yShOuTgS-1605523062298)(Graph/[email protected])]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-OFy3SB4e-1605523062299)(Graph/[email protected])]
O(V+E)
dfs遍歷整個圖的順序和最短路徑無關,而bfs搜索的是最短路徑
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-rfnh5z5r-1605523062302)(Graph/20190329164255150.png)]
共三個
可利用 深度優先 來找出圖中所有的連通分量
*深度優先搜索的預處理使用的時間和空間與V+E成正比且可以在常數時間內處理關於圖的連通性查詢。
有向圖:由一組頂點和一組有方向的邊組成的,每條有方向的邊都連接著有序的一對頂點
indegree(入度):point to
outdegree(出度):point away
simple:沒有重復的E / V
simple digraph的定律:E <= V(V-1)
strongly connected: every V is reachable from every other V
判斷strongly connectivity的時間復雜度:O(V+E)
在有向圖中,深度優先搜索標記由一個集合的頂點可達的所有頂點所需的時間與被標記的所有頂點的出度之和成正比
用途:解決優先順序限制下的調度問題
有向無環圖(DAG):不含有向環的有向圖
頂點的強連通:如果兩個頂點v和w是互相可達的,那麼它們是強連通的
圖的強連通:如果一幅有向圖中的任意兩個頂點都是強連通的,則稱這幅有向圖也是強連通的
三個for loop
space: O(V^2)
runtime: O(V^3)
必須是DAG -> directed graph that has no cycle
見筆記
O(V+E)
適用於 加權有向圖
重點解決「找到從一個頂點到達另一個頂點的權重最小的 有向路徑 」
(只寫了要注意的)
放鬆邊v -> w意味著檢查從s到w的最短路徑是否是先從s -> v -> w的,如果是,那麼更新數據結構的內容
採用了類似Prim的類似方法來計算最短路徑樹
Dijkstra可以解決邊 權重非負 的加權 有向圖 的 單起點 最短路徑問題。
也可以在加權無向圖中找到最短路徑
graph需要時connected的
使用Dijkstra計算根結點為給定起點的最短路徑樹所需的空間與V成正比,時間與ElogV成正比 -> O(ElogV)
用處:
當且僅當加權有向圖中至少 存在一條從s到v的有向路徑 且所有從s到v的有向路徑上的任意頂點都 不存在於任何負權重環中 時,s到v的最短路徑才是存在的
Bellman-Ford演算法所需的時間和EV成正比,空間和V成正比
一幅加權圖的最小生成樹(MST)是它的一棵權值(樹中所有邊的權值之和)最小的生成樹
最小生成樹僅存在於加權無向圖
每幅連通圖都只有一棵唯一的最小生成樹(所有邊權重不同)
無cycle=a tree+weight minimize
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-AgJkoBgj-1605523062304)(Graph/Photo%20Nov%2013,%202020%20at%20102515%20PM.jpg)]
只有一個頂點,會向它添加V-1條邊,每次總是將下一條連接樹中的頂點與不在樹中的頂點且權值最小的邊加入樹中
最小生成樹(Kruskal(克魯斯卡爾)和Prim(普里姆))演算法動畫演示_嗶哩嗶哩 (゜-゜)つロ 乾杯~-bilibili 4:00
把所有邊和weight按大小 排序 ,但保證不能有cycle
最小生成樹(Kruskal(克魯斯卡爾)和Prim(普里姆))演算法動畫演示_嗶哩嗶哩 (゜-゜)つロ 乾杯~-bilibili 2:09
所需的空間和E成正比,所需的時間和 ElogE 成正比
分塊然後選最短的路徑連接
O(ElogV)
對於每一種切分,權重最小的橫切邊必然屬於最小生成樹。
Remarks:Prim和Kruskal不能處理有向圖
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-iYd98l3e-1605523062305)(Graph/Photo%20Nov%2013,%202020%20at%20102448%20PM.jpg)]
圖的鄰接矩陣的實現
無向圖1——圖的鄰接表數組表示以及DFS、BFS搜索演算法實現_大魔王-CSDN博客
【數據結構】圖的連通分量 HaYa-CSDN博客 數據結構 連通分量
連通圖和連通分量 weixin_30569153的博客-CSDN博客 連通分量
❿ 圖的五種存儲結構
圖的鄰接矩陣(Adjacency Matrix): 圖的鄰接矩陣用兩個數組來表示圖。一個一維數組存儲圖中頂點信息,另一個二維數組(一般稱之為鄰接矩陣)來存儲圖中的邊或者弧的信息。從鄰接矩陣中我們自然知道一個頂點的度(對於無向圖)或者有向圖中一個頂點的入度出度信息。
假設圖G有n個頂點,則鄰接矩陣是一個n*n的方陣。
1.對於如果圖上的每條邊不帶權值來說,那麼我們就用真(一般為1)和假(一般為0)來表示一個頂點到另一個頂點存不存在邊。下面是一個圖的鄰接矩陣的定義:
鄰接矩陣法實現帶權值的無向圖的創建如下:
按照如圖輸入各邊(不重復)
測試程序如下:
結果可得該矩陣,證明創建樹成功。 假設n個頂點e條邊的創建,createGraph演算法的時間復雜度為O(n+n*n+e)。如果需要創建一個有向圖,那麼和上面一樣一個一個錄入邊下標和權值。
鄰接矩陣這種存儲結構的優缺點: 缺點是對於邊數相對頂點較少的稀疏圖來說會存在極大的空間浪費。假設有n個頂點,優點是對於有向完全圖和無向完全圖來說鄰接矩陣是一種不錯的存儲結構,浪費的話也只浪費了n個頂點的容量。
在樹的存儲結構一節中我們提到對於孩子表示法的第三種:用一段連續的存儲單元(數組)存儲樹中的所有結點,利用一個單鏈表來存儲數組中每個結點的孩子的信息。對於圖的存儲結構來說,我們也可以利用這種方法實現圖的存儲
鄰接表(Adjacency List): 這種數組與鏈表相結合的存儲方法叫做鄰接表。1.為什麼不也用單鏈表存儲圖的結點信息呢?原因就是數組這種順序存儲結構讀取結點信息速率快。對於頂點數組中,每個數據元素還需要存儲一個指向第一個鄰接頂點的指針,這樣才可以查找邊的信息2.圖中每個頂點Vi(i > 0)的所有鄰接點構成一個線性表 (在無向圖中這個線性表稱為Vi的邊表,有向圖中稱為頂點作為弧尾的出邊表) ,由於鄰接點的不確定性,所以用鏈表存儲,有多少個鄰接點就malloc一個空間存儲鄰接點,這樣更不會造成空間的浪費(與鄰接矩陣相比來說)。3.對於鄰接表中的某個頂點來說,用戶關心的是這個頂點的鄰接點,完全可以遍歷用單鏈表設計成的邊表或者出邊表得到,所以沒必要設計成雙鏈表。
鄰接表的存儲結構:
假設現在有一無向圖G,如下圖:
從鄰接表結構中,知道一個頂點的度或者判斷兩個頂點之間是否存在邊或者求一個頂點的所有鄰接頂點是很容易的。
假設現在有一有向圖G,如下圖:
無向圖的鄰接表創建示例如下:
假設在上圖(無向圖)中的V0V1V2V3頂點值為ABCD,則依據下面測試程序可得結果:
鄰接表的優缺點: 優點是:鄰接表存儲圖,既能夠知道一個頂點的度和頂點的鄰接結點的信息,並且更不會造成空間的浪費。缺點是鄰接表存儲有向圖時,如果關心的是頂點的出度問題自然用鄰接表結構,但是想了解入度需要遍歷圖才知道(需要考慮逆鄰接表)。
十字鏈表(Orthogonal List) :有向圖的一種存儲方法,它把鄰接表和逆鄰接表結合起來,因此在十字鏈表結構中可以知道一個頂點的入度和出度情況。
重新定義頂點表的結點如下圖:
現在有一有向圖如下圖:
則它的存儲結構示意圖為:
其定義如下:
十字鏈表是用來存儲有向圖的,這樣可以看出一個頂點的出入度信息。對於無向圖來說完全沒必要用十字鏈表來存儲。
在無向圖中,因為我們關注的是頂點的信息,在考慮節約空間的情況下我們利用鄰接表來存儲無向圖。但是如果我們關注的是邊的信息,例如需要刪除某條邊對於鄰接表來說是挺繁瑣的。它需要操作兩個單鏈表刪除兩個結點。因此我們仿照十字鏈表的方式對邊表結點結構重新定義如下圖:
它的鄰接多重表結構為:
多重鄰接表的優點:對於邊的操作相比於鄰接表來說更加方便。比如說我們現在需要刪除(V0,V2)這條邊,只需將69步驟中的指針改為nullptr即可。
邊集數組(edgeset array): 邊集數組是由兩個數組組成,一個存儲頂點信息,另一個存儲邊的信息,這個邊數組中的每個數據元素由起點下標,終點下標,和權組成(如果邊上含有權值的話)。
邊數組結構如下圖:
邊集數組實現圖的存儲的優缺點:優點是對於邊的操作方便快捷,操作的只是數組元素。比如說刪除某條邊,只需要刪除一個數組元素。缺點是:對於圖的頂點信息,我們只有遍歷整個邊數組才知道,這個費時。因此對於關注邊的操作來說,邊集數組更加方便。