圖論基礎(chǔ)

圖分為有向圖邑贴,和無(wú)向圖迄沫。

如果圖的邊數(shù)接近頂點(diǎn)數(shù)其為稠密圖

如果圖的邊數(shù)遠(yuǎn)遠(yuǎn)小于頂點(diǎn)數(shù)其為稀疏圖

表示稠密圖一般采用鄰接矩陣的方法


package bobo.algo;

import java.util.Vector;

// 稠密圖 - 鄰接矩陣

public class DenseGraphimplements Graph{

private int n;? // 節(jié)點(diǎn)數(shù)

? ? private int m;? // 邊數(shù)

? ? private boolean directed;? // 是否為有向圖

? ? private boolean[][] g;? ? ? // 圖的具體數(shù)據(jù)

? ? // 構(gòu)造函數(shù)

? ? public DenseGraph(int n, boolean directed ){

assert n >=0;

? ? ? ? this.n = n;

? ? ? ? this.m =0;? ? // 初始化沒(méi)有任何邊

? ? ? ? this.directed = directed;

? ? ? ? // g初始化為n*n的布爾矩陣, 每一個(gè)g[i][j]均為false, 表示沒(méi)有任和邊

? ? ? ? // false為boolean型變量的默認(rèn)值

? ? ? ? g =new boolean[n][n];

? ? }

public int V(){return n;}// 返回節(jié)點(diǎn)個(gè)數(shù)

? ? public int E(){return m;}// 返回邊的個(gè)數(shù)

? ? // 向圖中添加一個(gè)邊

? ? public void addEdge(int v, int w ){

assert v >=0 && v < n;

? ? ? ? assert w >=0 && w < n;

? ? ? ? if( hasEdge( v, w ) )

return;

? ? ? ? g[v][w] =true;

? ? ? ? if( !directed )

g[w][v] =true;

? ? ? ? m ++;

? ? }

// 驗(yàn)證圖中是否有從v到w的邊

? ? public boolean hasEdge(int v, int w ){

assert v >=0 && v < n;

? ? ? ? assert w >=0 && w < n;

? ? ? ? return g[v][w];

? ? }

// 顯示圖的信息

? ? public void show(){

for(int i =0 ; i < n; i ++ ){

for(int j =0 ; j < n; j ++ )

System.out.print(g[i][j]+"\t");

? ? ? ? ? ? System.out.println();

? ? ? ? }

}

// 返回圖中一個(gè)頂點(diǎn)的所有鄰邊

? ? // 由于java使用引用機(jī)制,返回一個(gè)Vector不會(huì)帶來(lái)額外開(kāi)銷,

? ? public Iterable adj(int v) {

assert v >=0 && v < n;

? ? ? ? Vector adjV =new Vector();

? ? ? ? for(int i =0 ; i < n; i ++ )

if( g[v][i] )

adjV.add(i);

? ? ? ? return adjV;

? ? }

}




表示稀疏圖一般采用鄰接表的方法害驹。


package bobo.algo;

import java.util.Vector;

// 稀疏圖 - 鄰接表

public class SparseGraphimplements Graph {

private int n;? // 節(jié)點(diǎn)數(shù)

? ? private int m;? // 邊數(shù)

? ? private boolean directed;? // 是否為有向圖

? ? private Vector[] g; // 圖的具體數(shù)據(jù)

? ? // 構(gòu)造函數(shù)

? ? public SparseGraph(int n, boolean directed ){

assert n >=0;

? ? ? ? this.n = n;

? ? ? ? this.m =0;? ? // 初始化沒(méi)有任何邊

? ? ? ? this.directed = directed;

? ? ? ? // g初始化為n個(gè)空的vector, 表示每一個(gè)g[i]都為空, 即沒(méi)有任和邊

? ? ? ? g = (Vector[])new Vector[n];

? ? ? ? for(int i =0 ; i < n; i ++)

g[i] =new Vector();

? ? }

public int V(){return n;}// 返回節(jié)點(diǎn)個(gè)數(shù)

? ? public int E(){return m;}// 返回邊的個(gè)數(shù)

? ? // 向圖中添加一個(gè)邊

? ? public void addEdge(int v, int w ){

assert v >=0 && v < n;

? ? ? ? assert w >=0 && w < n;

? ? ? ? g[v].add(w);

? ? ? ? if( v != w && !directed )

g[w].add(v);

? ? ? ? m ++;

? ? }

// 驗(yàn)證圖中是否有從v到w的邊

? ? public boolean hasEdge(int v, int w ){

assert v >=0 && v < n;

? ? ? ? assert w >=0 && w < n;

? ? ? ? for(int i =0 ; i < g[v].size(); i ++ )

if( g[v].elementAt(i) == w )

return true;

return false;

? ? }

// 顯示圖的信息

? ? public void show(){

for(int i =0 ; i < n; i ++ ){

System.out.print("vertex " + i +":\t");

? ? ? ? ? ? for(int j =0 ; j < g[i].size(); j ++ )

System.out.print(g[i].elementAt(j) +"\t");

? ? ? ? ? ? System.out.println();

? ? ? ? }

}

// 返回圖中一個(gè)頂點(diǎn)的所有鄰邊

? ? // 由于java使用引用機(jī)制柑蛇,返回一個(gè)Vector不會(huì)帶來(lái)額外開(kāi)銷,

? ? public Iterable adj(int v) {

assert v >=0 && v < n;

? ? ? ? return g[v];

? ? }

}



圖的深度優(yōu)先遍歷


從0開(kāi)始,遍歷1棋弥,再遍歷1的子節(jié)點(diǎn)0,發(fā)現(xiàn)已遍歷完子節(jié)點(diǎn)退回到上層诚欠,遍歷2顽染,遍歷0漾岳,發(fā)現(xiàn)遍歷完了,再遍歷5粉寞,遍歷 0發(fā)現(xiàn)已經(jīng)遍歷換下一個(gè)尼荆,3,遍歷3的子節(jié)點(diǎn)4唧垦,遍歷4的子節(jié)點(diǎn)3捅儒,5,6振亮,以此類推


聯(lián)通分量

聯(lián)通分量之間沒(méi)有節(jié)點(diǎn)相連


深度優(yōu)先遍歷能遍歷完一個(gè)聯(lián)通分量

求聯(lián)通分量和深度遍歷

package bobo.algo;

// 求無(wú)權(quán)圖的聯(lián)通分量

public class Components {

Graph G;? ? ? ? ? ? ? ? ? ? // 圖的引用

? ? private boolean[] visited;? // 記錄dfs的過(guò)程中節(jié)點(diǎn)是否被訪問(wèn)

? ? private int ccount;? ? ? ? // 記錄聯(lián)通分量個(gè)數(shù)

? ? private int[] id;? ? ? ? ? // 每個(gè)節(jié)點(diǎn)所對(duì)應(yīng)的聯(lián)通分量標(biāo)記

? ? // 圖的深度優(yōu)先遍歷

? ? void dfs(int v ){

visited[v] =true;

? ? ? ? id[v] = ccount;

? ? ? ? for(int i: G.adj(v) ){

if( !visited[i] )

dfs(i);

? ? ? ? }

}

// 構(gòu)造函數(shù), 求出無(wú)權(quán)圖的聯(lián)通分量

? ? public Components(Graph graph){

// 算法初始化

? ? ? ? G = graph;

? ? ? ? visited =new boolean[G.V()];

? ? ? ? id =new int[G.V()];

? ? ? ? ccount =0;

? ? ? ? for(int i =0 ; i < G.V(); i ++ ){

visited[i] =false;

? ? ? ? ? ? id[i] = -1;

? ? ? ? }

// 求圖的聯(lián)通分量

? ? ? ? for(int i =0 ; i < G.V(); i ++ )

if( !visited[i] ){

dfs(i);

? ? ? ? ? ? ? ? ccount ++;

? ? ? ? ? ? }

}

// 返回圖的聯(lián)通分量個(gè)數(shù)

? ? int count(){

return ccount;

? ? }

// 查詢點(diǎn)v和點(diǎn)w是否聯(lián)通

? ? boolean isConnected(int v, int w ){

assert v >=0 && v < G.V();

? ? ? ? assert w >=0 && w < G.V();

? ? ? ? return id[v] == id[w];

? ? }

}



找出兩點(diǎn)之間的路徑一般是在深度遍歷時(shí)記錄上一個(gè)點(diǎn)的位置即可

package bobo.algo;

import java.util.Vector;

import java.util.Stack;

public class Path {

private Graph G;? // 圖的引用

? ? private int s;? ? // 起始點(diǎn)

? ? private boolean[] visited;? // 記錄dfs的過(guò)程中節(jié)點(diǎn)是否被訪問(wèn)

? ? private int[] from;? ? ? ? // 記錄路徑, from[i]表示查找的路徑上i的上一個(gè)節(jié)點(diǎn)

? ? // 圖的深度優(yōu)先遍歷

? ? private void dfs(int v ){

visited[v] =true;

? ? ? ? for(int i : G.adj(v) )

if( !visited[i] ){

from[i] = v;

? ? ? ? ? ? ? ? dfs(i);

? ? ? ? ? ? }

}

// 構(gòu)造函數(shù), 尋路算法, 尋找圖graph從s點(diǎn)到其他點(diǎn)的路徑

? ? public Path(Graph graph, int s){

// 算法初始化

? ? ? ? G = graph;

? ? ? ? assert s >=0 && s < G.V();

? ? ? ? visited =new boolean[G.V()];

? ? ? ? from =new int[G.V()];

? ? ? ? for(int i =0 ; i < G.V(); i ++ ){

visited[i] =false;

? ? ? ? ? ? from[i] = -1;

? ? ? ? }

this.s = s;

? ? ? ? // 尋路算法

? ? ? ? dfs(s);

? ? }

// 查詢從s點(diǎn)到w點(diǎn)是否有路徑

? ? boolean hasPath(int w){

assert w >=0 && w < G.V();

? ? ? ? return visited[w];

? ? }

// 查詢從s點(diǎn)到w點(diǎn)的路徑, 存放在vec中

? ? Vector path(int w){

assert hasPath(w);

? ? ? ? Stack s =new Stack();

? ? ? ? // 通過(guò)from數(shù)組逆向查找到從s到w的路徑, 存放到棧中

? ? ? ? int p = w;

? ? ? ? while( p != -1 ){

s.push(p);

? ? ? ? ? ? p = from[p];

? ? ? ? }

// 從棧中依次取出元素, 獲得順序的從s到w的路徑

? ? ? ? Vector res =new Vector();

? ? ? ? while( !s.empty() )

res.add( s.pop() );

? ? ? ? return res;

? ? }

// 打印出從s點(diǎn)到w點(diǎn)的路徑

? ? void showPath(int w){

assert hasPath(w);

? ? ? ? Vector vec = path(w);

? ? ? ? for(int i =0 ; i < vec.size(); i ++ ){

System.out.print(vec.elementAt(i));

? ? ? ? ? ? if( i == vec.size() -1 )

System.out.println();

else

? ? ? ? ? ? ? ? System.out.print(" -> ");

? ? ? ? }

}

}



倆點(diǎn)之間的最短路徑(無(wú)權(quán)圖)

用廣度遍歷巧还,先遍歷其所有子節(jié)點(diǎn),第一個(gè)子節(jié)點(diǎn)的子節(jié)點(diǎn)入棧坊秸,第二個(gè)子節(jié)點(diǎn)的子結(jié)點(diǎn)再入棧麸祷,以此類推,到第一個(gè)子節(jié)點(diǎn)的子節(jié)點(diǎn)的子節(jié)點(diǎn)入賬即可

package bobo.algo;

import java.util.Vector;

import java.util.Stack;

import java.util.LinkedList;

import java.util.Queue;

public class ShortestPath {

private Graph G;? // 圖的引用

? ? private int s;? ? // 起始點(diǎn)

? ? private boolean[] visited;? // 記錄dfs的過(guò)程中節(jié)點(diǎn)是否被訪問(wèn)

? ? private int[] from;? ? ? ? // 記錄路徑, from[i]表示查找的路徑上i的上一個(gè)節(jié)點(diǎn)

? ? private int[] ord;? ? ? ? ? // 記錄路徑中節(jié)點(diǎn)的次序妇斤。ord[i]表示i節(jié)點(diǎn)在路徑中的次序摇锋。

? ? // 構(gòu)造函數(shù), 尋路算法, 尋找圖graph從s點(diǎn)到其他點(diǎn)的路徑

? ? public ShortestPath(Graph graph, int s){

// 算法初始化

? ? ? ? G = graph;

? ? ? ? assert s >=0 && s < G.V();

? ? ? ? visited =new boolean[G.V()];

? ? ? ? from =new int[G.V()];

? ? ? ? ord =new int[G.V()];

? ? ? ? for(int i =0 ; i < G.V(); i ++ ){

visited[i] =false;

? ? ? ? ? ? from[i] = -1;

? ? ? ? ? ? ord[i] = -1;

? ? ? ? }

this.s = s;

? ? ? ? // 無(wú)向圖最短路徑算法, 從s開(kāi)始廣度優(yōu)先遍歷整張圖

? ? ? ? Queue q =new LinkedList();

? ? ? ? q.add(s);

? ? ? ? visited[s] =true;

? ? ? ? ord[s] =0;

? ? ? ? while( !q.isEmpty() ){

int v = q.remove();

? ? ? ? ? ? for(int i : G.adj(v) )

if( !visited[i] ){

q.add(i);

? ? ? ? ? ? ? ? ? ? visited[i] =true;

? ? ? ? ? ? ? ? ? ? from[i] = v;

? ? ? ? ? ? ? ? ? ? ord[i] = ord[v] +1;

? ? ? ? ? ? ? ? }

}

}

// 查詢從s點(diǎn)到w點(diǎn)是否有路徑

? ? public boolean hasPath(int w){

assert w >=0 && w < G.V();

? ? ? ? return visited[w];

? ? }

// 查詢從s點(diǎn)到w點(diǎn)的路徑, 存放在vec中

? ? public Vector path(int w){

assert hasPath(w);

? ? ? ? Stack s =new Stack();

? ? ? ? // 通過(guò)from數(shù)組逆向查找到從s到w的路徑, 存放到棧中

? ? ? ? int p = w;

? ? ? ? while( p != -1 ){

s.push(p);

? ? ? ? ? ? p = from[p];

? ? ? ? }

// 從棧中依次取出元素, 獲得順序的從s到w的路徑

? ? ? ? Vector res =new Vector();

? ? ? ? while( !s.empty() )

res.add( s.pop() );

? ? ? ? return res;

? ? }

// 打印出從s點(diǎn)到w點(diǎn)的路徑

? ? public void showPath(int w){

assert hasPath(w);

? ? ? ? Vector vec = path(w);

? ? ? ? for(int i =0 ; i < vec.size(); i ++ ){

System.out.print(vec.elementAt(i));

? ? ? ? ? ? if( i == vec.size() -1 )

System.out.println();

else

? ? ? ? ? ? ? ? System.out.print(" -> ");

? ? ? ? }

}

// 查看從s點(diǎn)到w點(diǎn)的最短路徑長(zhǎng)度

? ? // 若從s到w不可達(dá)丹拯,返回-1

? ? public int length(int w){

assert w >=0 && w < G.V();

? ? ? ? return ord[w];

? ? }

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末站超,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子乖酬,更是在濱河造成了極大的恐慌死相,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咬像,死亡現(xiàn)場(chǎng)離奇詭異算撮,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)县昂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)肮柜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人倒彰,你說(shuō)我怎么就攤上這事审洞。” “怎么了待讳?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵芒澜,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我创淡,道長(zhǎng)痴晦,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任琳彩,我火速辦了婚禮誊酌,結(jié)果婚禮上部凑,老公的妹妹穿的比我還像新娘。我一直安慰自己碧浊,他們只是感情好砚尽,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著辉词,像睡著了一般必孤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上瑞躺,一...
    開(kāi)封第一講書(shū)人閱讀 48,970評(píng)論 1 284
  • 那天敷搪,我揣著相機(jī)與錄音,去河邊找鬼幢哨。 笑死赡勘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的捞镰。 我是一名探鬼主播闸与,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼岸售!你這毒婦竟也來(lái)了践樱?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤凸丸,失蹤者是張志新(化名)和其女友劉穎拷邢,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體屎慢,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瞭稼,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了腻惠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片环肘。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖集灌,靈堂內(nèi)的尸體忽然破棺而出悔雹,到底是詐尸還是另有隱情,我是刑警寧澤绝页,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布荠商,位于F島的核電站,受9級(jí)特大地震影響续誉,放射性物質(zhì)發(fā)生泄漏莱没。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一酷鸦、第九天 我趴在偏房一處隱蔽的房頂上張望饰躲。 院中可真熱鬧牙咏,春花似錦、人聲如沸嘹裂。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)寄狼。三九已至丁寄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間泊愧,已是汗流浹背伊磺。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留删咱,地道東北人屑埋。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像痰滋,于是被迫代替她去往敵國(guó)和親摘能。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些閱讀 2,027評(píng)論 0 2
  • 【第一章】突如其來(lái)的大火 【第二十九章】情難抑敲街、暗傷懷 李重樓一下樓团搞,就看見(jiàn)白展宏很不自在的站在那兒,額頭上一抹明...
    黃飛蝗閱讀 254評(píng)論 1 6
  • 今日:全天平和聪富,微笑莺丑。 由于昨晚兒子學(xué)習(xí)時(shí)看kindle到很晚著蟹,計(jì)劃也沒(méi)完成墩蔓,被我發(fā)現(xiàn),我沒(méi)批評(píng)他萧豆,只是拿進(jìn)了我房...
    玲03閱讀 217評(píng)論 0 0
  • 我們擁抱奸披,親吻 一整天都不出門(mén) 我們懷想藍(lán)色的天空 藍(lán)色的海洋 還有去年情人節(jié)買(mǎi)的藍(lán)色玫瑰 以及那毛絨絨的藍(lán)色地毯...
    叮咚的你閱讀 129評(píng)論 0 0
  • 關(guān)鍵詞:新東方;金沃斯涮雷;在線英語(yǔ)阵面;小班課; 1. 在線英語(yǔ)學(xué)習(xí)平臺(tái)“金沃斯”獲上億元A輪投資 神奇的事情接二連三地...
    Alex_Chang閱讀 216評(píng)論 1 1