日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 综合教程 >内容正文

综合教程

数据结构(十):图

發(fā)布時(shí)間:2023/12/15 综合教程 28 生活家
生活随笔 收集整理的這篇文章主要介紹了 数据结构(十):图 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、 圖概述

  日常生活中使用的地圖導(dǎo)航,每個(gè)城市看做一個(gè)頂點(diǎn),城市與城市間連通的線路看做聯(lián)通的邊,就組成了圖。除了導(dǎo)航,迷宮,電路板等等也是圖,需要用圖這種數(shù)據(jù)結(jié)構(gòu)去解決很多連通問(wèn)題。

二、 圖的特性

  圖的定義:圖是有一組頂點(diǎn)和一組能將頂點(diǎn)相連的邊組成的數(shù)據(jù)結(jié)構(gòu)

  

  

  

  特殊的圖:

  平行邊:連接同一對(duì)頂點(diǎn)的多條邊

  自環(huán):一條出口和入口都來(lái)自同一個(gè)頂點(diǎn)的邊

  

  圖的分類:

  無(wú)向圖:連接頂點(diǎn)的邊是無(wú)方向無(wú)意義的圖

  有向圖:連接頂點(diǎn)的邊具有方向的圖

  相鄰頂點(diǎn):兩個(gè)頂點(diǎn)通過(guò)一條邊相連時(shí)為相鄰頂點(diǎn)

  度:頂點(diǎn)邊的數(shù)量

  子圖:圖所有邊和相連頂點(diǎn)的子集

  路徑:A頂點(diǎn)到B頂點(diǎn)若干順序連接的邊

  環(huán):起點(diǎn)和終點(diǎn)相同,并且至少含有一條邊的路徑

  連通圖:圖中每一個(gè)頂點(diǎn)都存在一條邊到達(dá)另外一個(gè)頂點(diǎn),稱為連通圖

  

  連通子圖:一幅非連通圖由若干連通部分組成,該連通部分稱為連通子圖

  

三、 圖的實(shí)現(xiàn)

  3.1 鄰接矩陣

  圖的數(shù)據(jù)結(jié)構(gòu)可以通過(guò)二維數(shù)組來(lái)表示,即鄰接矩陣,如下圖生成一個(gè)8*8的二維數(shù)組,通過(guò)graph[7][8]=1和graph[8][7]=1來(lái)表示頂點(diǎn)7和8的連通。

  

  

  但該方式存在著內(nèi)存空間使用率低的問(wèn)題,N個(gè)頂點(diǎn)圖中,得初始化N^2規(guī)模的二維數(shù)組,空間復(fù)雜度是不可接受的。

  3.2鄰接表

  使用一個(gè)頂點(diǎn)數(shù)量相同大小的數(shù)組Queue[],索引作為圖的頂點(diǎn),索引對(duì)應(yīng)的隊(duì)列存放與頂點(diǎn)相連通的其他頂點(diǎn),用這種方式來(lái)表示圖稱為鄰接表。鄰接表相比鄰接矩陣可以大大的節(jié)省內(nèi)存空間。

  

  圖的鄰接表實(shí)現(xiàn):

/**

* 圖的實(shí)現(xiàn)

* @author jiyukai

*/

public class Graph {

//定點(diǎn)個(gè)數(shù)

public int V;

//邊的數(shù)量

public int E;

//圖的鄰接表

public Queue<Integer>[] qTable;

public Graph(int v) {

this.V = v;

this.E = 0;

//初始化鄰接表,數(shù)組中的索引為頂點(diǎn),值為已隊(duì)列,存放相鄰的頂點(diǎn)

qTable = new Queue[v];

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

qTable[i] = new Queue<Integer>();

}

}

/**

* 向圖中添加一條邊

* @param v

* @param w

*/

public void addEdge(int v,int w) {

//頂點(diǎn)v添加w的指向

qTable[v].enqueue(w);

//頂點(diǎn)w添加v的指向

qTable[w].enqueue(v);

//邊加1

E++;

}

/**

* 返回當(dāng)前頂點(diǎn)的數(shù)量

* @return

*/

public int V() {

return V;

}

/**

* 返回當(dāng)前邊的數(shù)量

* @return

*/

public int E() {

return E;

}

/**

* 獲取與頂點(diǎn)V相鄰的頂點(diǎn)

* @param V

* @return

*/

public Queue adjoin(int V) {

return qTable[V];

}

}


四、
深度優(yōu)先搜索

  圖的搜索算法中,深度優(yōu)先搜索指的是搜索到的頂點(diǎn)既有子結(jié)點(diǎn)又有兄弟結(jié)點(diǎn),優(yōu)先搜索子結(jié)點(diǎn)。如下演示為圖的深度優(yōu)先搜索順序

  

  

  為了不對(duì)已搜索過(guò)的頂點(diǎn)重復(fù)搜索,我們需要有個(gè)布爾類型的數(shù)組來(lái)標(biāo)記頂點(diǎn)是否被搜索過(guò),搜索過(guò)的就標(biāo)記為true,不再進(jìn)行深度搜索,提高效率的同時(shí),該數(shù)組也能判斷頂點(diǎn)A到B是否相通

  因?yàn)橄嗤ǖ拇硭阉鬟^(guò),會(huì)被標(biāo)記為true。

/**

* 深度優(yōu)先搜索

* @author jiyukai

*/

public class DepthSearch {

//標(biāo)記頂點(diǎn)x是否有被搜索過(guò)

public boolean[] flags;

public int count;

/**

* 深度優(yōu)先搜索,找出與頂點(diǎn)V想通的所有頂點(diǎn)

* @param G

* @param V

*/

public DepthSearch(Graph G,int V) {

//長(zhǎng)度置0

this.count = 0;

//創(chuàng)建一個(gè)與頂點(diǎn)數(shù)量相同的標(biāo)記數(shù)組,標(biāo)記每個(gè)頂點(diǎn)是否被搜索過(guò)

flags = new boolean[G.V()];

//深度優(yōu)先搜索

dfs(G, V);

}

/**

* 深度優(yōu)先搜索實(shí)現(xiàn)

* @param G

* @param V

*/

public void dfs(Graph G,int V) {

//被搜的頂點(diǎn)V標(biāo)記為搜索過(guò)

flags[V] = true;

for(int w : G.qTable[V]) {

if(!flags[w]) {

System.out.println("搜索的頂點(diǎn):"+w);

dfs(G, w);

}

}

//相通的點(diǎn)+1

count++;

}

/**

* 返回與頂點(diǎn)V相通的所有頂點(diǎn)

* @return

*/

public int count() {

return count;

}

/**

* 判斷頂點(diǎn)w是否與v相通

* @param w

* @return

*/

public boolean isConnected(int w) {

return flags[w];

}

}


五、
廣度優(yōu)先搜索

  圖的搜索算法中,廣度優(yōu)先搜索指的是搜索到的頂點(diǎn)既有子結(jié)點(diǎn)又有兄弟結(jié)點(diǎn),優(yōu)先搜索兄弟結(jié)點(diǎn)。如下演示為圖的廣度優(yōu)先搜索順序

  

  為了不對(duì)已搜索過(guò)的頂點(diǎn)重復(fù)搜索,我們需要有個(gè)布爾類型的數(shù)組來(lái)標(biāo)記頂點(diǎn)是否被搜索過(guò),搜索過(guò)的就標(biāo)記為true,不再進(jìn)行廣度搜索,提高效率的同時(shí),該數(shù)組也能判斷頂點(diǎn)A到B是否相通

  因?yàn)橄嗤ǖ拇硭阉鬟^(guò),會(huì)被標(biāo)記為true。

/**

* 廣度優(yōu)先搜索

*

* @author jiyukai

*/

public class WeightSearch {

// 標(biāo)記頂點(diǎn)x是否有被搜索過(guò)

public boolean[] flags;

// 聯(lián)通的點(diǎn)數(shù)量

public int count;

// 用來(lái)存儲(chǔ)待搜索鄰接表的點(diǎn)

private Queue<Integer> waitSearch;

/**

* 深度優(yōu)先搜索,找出與頂點(diǎn)V想通的所有頂點(diǎn)

*

* @param G

* @param V

*/

public WeightSearch(Graph G, int V) {

// 長(zhǎng)度置0

this.count = 0;

// 創(chuàng)建一個(gè)與頂點(diǎn)數(shù)量相同的標(biāo)記數(shù)組,標(biāo)記每個(gè)頂點(diǎn)是否被搜索過(guò)

flags = new boolean[G.V()];

// 初始化待搜索頂點(diǎn)隊(duì)列

waitSearch = new Queue<>();

// 深度優(yōu)先搜索

wfs(G, V);

}

/**

* 深度優(yōu)先搜索實(shí)現(xiàn)

*

* @param G

* @param V

*/

public void wfs(Graph G, int V) {

// 被搜的頂點(diǎn)V標(biāo)記為搜索過(guò)

flags[V] = true;

// 將待搜索的元素入隊(duì)列

for (int w : G.qTable[V]) {

waitSearch.enqueue(w);

}

while (!waitSearch.isEmpty()) {

int searchKey = waitSearch.dequeue();

if (!flags[searchKey]) {

wfs(G, searchKey);

}

}

// 相通的點(diǎn)+1

count++;

}

/**

* 返回與頂點(diǎn)V相通的所有頂點(diǎn)

*

* @return

*/

public int count() {

return count;

}

/**

* 判斷頂點(diǎn)w是否與v相通

*

* @param w

* @return

*/

public boolean isConnected(int w) {

return flags[w];

}

}


六、
路徑查找

  導(dǎo)航中常用的一個(gè)場(chǎng)景就是起點(diǎn)s到重點(diǎn)v之間是否存在一條可連通的路徑,若存在,需要走什么樣的路到達(dá)。

  

  基于深度搜索來(lái)實(shí)現(xiàn)圖的搜索,新增一個(gè)數(shù)組conn[]來(lái)記錄各個(gè)連通點(diǎn)之間的關(guān)系,索引為頂點(diǎn),值為指向頂點(diǎn)的相鄰頂點(diǎn),假設(shè)0為起點(diǎn),在conn數(shù)組構(gòu)建完畢后,我們通過(guò)索引0找到頂點(diǎn)4

  在通過(guò)索引4找到頂點(diǎn)5,依次找下去,并將找到的頂點(diǎn)依次入棧,則最后能找到和0相通的其他頂點(diǎn)和中間經(jīng)過(guò)的路徑。

  

  將找到的頂點(diǎn)依次入棧

  

/**

* 基于深度優(yōu)先搜索實(shí)現(xiàn)的路徑查找

* @author jiyukai

*/

public class DepthSearchPath {

// 標(biāo)記頂點(diǎn)x是否有被搜索過(guò)

public boolean[] flags;

// 聯(lián)通的點(diǎn)數(shù)量

public int count;

// 初始化起點(diǎn)

public int s;

// 連通頂點(diǎn)的關(guān)系

public int conn[];

/**

* 深度優(yōu)先搜索,找出與頂點(diǎn)V想通的所有頂點(diǎn)

* @param G

* @param V

*/

public DepthSearchPath(Graph G, int s) {

// 長(zhǎng)度置0

this.count = 0;

// 創(chuàng)建一個(gè)與頂點(diǎn)數(shù)量相同的標(biāo)記數(shù)組,標(biāo)記每個(gè)頂點(diǎn)是否被搜索過(guò)

flags = new boolean[G.V()];

// 初始化連通頂點(diǎn)的關(guān)系數(shù)組

conn = new int[G.V()];

// 初始化起點(diǎn)

this.s = s;

// 深度優(yōu)先搜索

wfs(G, s);

}

/**

* 深度優(yōu)先搜索實(shí)現(xiàn)

* @param G

* @param V

*/

public void wfs(Graph G, int v) {

// 被搜的頂點(diǎn)V標(biāo)記為搜索過(guò)

flags[v] = true;

for (int w : G.qTable[v]) {

if (!flags[w]) {

conn[w] = v;

wfs(G, w);

}

}

// 相通的點(diǎn)+1

count++;

}

/**

* 返回與頂點(diǎn)V相通的所有頂點(diǎn)

* @return

*/

public int count() {

return count;

}

/**

* 判斷頂點(diǎn)w是否與v相通

* @param w

* @return

*/

public boolean isConnected(int w) {

return flags[w];

}

/**

* 找出s到頂點(diǎn)v的路徑

* @param v

* @return

*/

public Stack<Integer> pathTo(int v){

//判斷是否連接

if(!isConnected(v)) {

return null;

}

//創(chuàng)建存放連通圖的棧

Stack<Integer> stack = new Stack<Integer>();

//找出與起點(diǎn)s連通路徑上的頂點(diǎn)

for(int x=v;x!=s;x=conn[x]) {

stack.push(x);

}

//起點(diǎn)入棧

stack.push(s);

return stack;

}

}

總結(jié)

以上是生活随笔為你收集整理的数据结构(十):图的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。