1. 程式人生 > >圖的儲存與遍歷(鏈式前向星中的DFS與BFS)

圖的儲存與遍歷(鏈式前向星中的DFS與BFS)

圖的儲存方式:

1.圖的陣列(鄰接矩陣)儲存表示,其中無向圖的儲存方式為對稱矩陣陣列,有向圖的儲存方式為非對稱矩陣陣列。求最短路徑時常常採用陣列儲存表示各點間的路徑。

2.邊集方法                    

邊的定義:
     stuct edge_set
         int u,v;
         int weight;
edge[N];
邊的結點:edge[i].uedge[i].v
邊的權重:edge[i].weight

例如:

edge[0].u=1,edge[0].v=2,edge[0].weight=6
edge[1].u=1,edge[0].v=3,edge[0].weight=3

edge[2].u=2,edge[0].v=4,edge[0].weight=9

edge[3].u=3,edge[0].v=4,edge[0].weight=5

3.圖的鄰接表儲存表示法

鄰接表是圖的一種鏈式儲存結構

對圖中每個頂點建立一個單鏈表,第i個單鏈表中的結點表示依附於頂點vi的邊;由此通過遍歷每個頂點所對應的連結串列就可以遍歷所有的邊。

詳解以及陣列實現:https://www.cnblogs.com/ECJTUACM-873284962/p/6905416.html

但使用連結串列來實現鄰接表對於痛恨指標的的朋友來說,這簡直就是噩夢。於是便有了以結構體陣列形式來實現的方法,又稱

鏈式前向星。

4.鏈式前向星(鄰接表儲存的結構體陣列實現方法)

const int M=105;  //結點數
const int oo=100000000;
struct node {
       int to,next,weight;
} edge[M*100]; //M*100為邊數
int head[2*M]; //頭結點
構圖:
void add(int a, int b, int c) {
    	edge[tot].to=b;    edge[tot].weight=c;    edge[tot].next=head[a];    head[a]=tot++;
    } 

tot表示全域性變數,鄰接邊邊數;

head[a]儲存結點a的第一個邊的陣列edge下標,表示這條邊aedge[head[a]].to

,費用為c.

edge[tot].next表示與這條邊相鄰的結點,初始化head[i]-1,表示一開始沒有相鄰結點。


圖來源:https://www.cnblogs.com/LQ-double/p/5971323.html

如果要遍歷所有的點則for兩層迴圈就可以了。

—————————————————————————————我是分割線———————————————————————————————

圖的遍歷方式:

DFS(深度優先搜尋):從某個狀態開始,不斷遍歷可以到達的狀態直到狀態無法轉移,然後回退到前一步的狀態,然後繼續轉移到其他狀態,如此不斷重複,直到到達指定的狀態或求出解。

1.找到初始點V0,訪問此結點。

2.依次找到所有與V0鄰接的未被訪問的結點並進行深度優先搜尋遍歷圖。

3.直到所有與V0相通的點都被訪問。

圖解:

先看一幅有向圖

可以發現,其遍歷的順序為

0->3->1->2->4

           其的概念就是一條路走到黑之後回頭到上一個路口換條路走

圖的表示方法包括鄰接表,鄰接矩陣等,鄰接矩陣表示的是用一個二維陣列表示圖的聯通,其中i行j列表示了i結點和j結點的聯通情況,如果其為1,說明是聯通的,如果其為0,反之;鄰接表表示的是一個一維陣列,但是陣列中每個列表包含著是連結串列;

看個圖加深理解:

其中a是有向圖/原圖,b是鄰接表表示圖,c是鄰接矩陣表示圖;

圖解來源:https://www.cnblogs.com/George1994/p/6399889.html

虛擬碼

遞迴實現

1. 訪問陣列初始化:visited[n] = 0
訪問頂點:visited[v] = 1
取v的第一個鄰接點w;
迴圈遞迴:
    while(w存在)
        if(w未被訪問過)
            從頂點w出發遞迴執行;
        w = v的下一個鄰接點;

非遞迴實現(使用棧的資料結構)

1.  棧初始化:visited[n] = 0
訪問頂點:visited[v] = 1
入棧
while(棧不為空)
    x = 棧的頂元素,並且出棧;
    if (存在並找到未被訪問的x的鄰接點w)
        訪問w:visited[w] = 1
        w進棧

實現程式碼(計算距離)

using namespace std;
struct node{
	int to,nex,val;
}edge[200005];
int head[100005],cnt;//head[i]代表  以i結點開始的第一條邊的下標 
void add(int u,int v,int w){
	edge[cnt].to=v;
	edge[cnt].val=w;
	edge[cnt].nex=head[u];
	head[u]=cnt;
	cnt++; 
}
void dfs(int t,int f,int w){
	for(int i=head[t];~i;i=edge[i].nex){
		int v=edge[i].to;
		if(v==f)continue;    //這裡的f代指父親結點,用來防止搜回去
		dis[v]=w+edge[i].val;
		dfs(v,t,w+edge[i].val);
	}
}
int main(){
	int n,m,i,j;
	memset(head,-1,sizeof(head));
	cin>>n>>m;
	for(i=1;i<=m;i++){
		int x,y,w;
		cin>>x>>y;
		w=1;
		add(x,y,w);
		add(y,x,w); 		//根據無向圖和有向圖兩種情況進行選擇性註釋此行
	}
	dfs(1,1,0);
	return 0;
}

BFS(寬度優先搜尋):從某狀態開始訪問,不斷遍歷從該狀態訪問可以直接到達的狀態,然後從這些狀態出發,不斷訪問這些狀態可以直接到達的狀態,直到所有可以直接或間接到達的狀態都被訪問。(這種訪問方式需要藉助佇列實現)

先看一幅有向圖

可以發現,其遍歷的順序為

0->3->4->1->2

虛擬碼

非遞迴實現

1. 初始化佇列:visited[n] = 0
2. 訪問頂點:visited[v] = 1
3. 頂點v加入佇列
4. 迴圈:
    while(佇列是否為空)
        v = 佇列頭元素
        w = v的第一個鄰接點
        while(w存在)
            if(如果w未訪問)
                visited[w] = 1;
                頂點w加入佇列
                w = 頂點v的下一個鄰接點

上面的尋找下一個鄰接點,是尋找之前結點的下一個鄰接點,而不是當前的,否則就變成DFS了;

實現程式碼:

struct node{
	int to,nex,val;
}edge[200005];
int head[100005],cnt;//head[i]代表以i結點開始的第一條邊的下標 
void add(int u,int v,int w)
{
	edge[cnt].to=v;
	edge[cnt].val=w;
	edge[cnt].nex=head[u];
	head[u]=cnt;
	cnt++; 
}
int vis[100005];
queue<int>tp;
int main(){
	int n,m,i,j;
	memset(head,-1,sizeof(head));
	cin>>n>>m;
	for(i=1;i<=m;i++)
	{
		int x,y,w;
		cin>>x>>y;
		w=1;
		add(x,y,w);
//		add(y,x,w);		//根據無向圖和有向圖兩種情況進行選擇性註釋此行
	}
	vis[1]=1;
	tp.push(1);
	while(!tp.empty()){
		int f=tp.front();
		tp.pop();
		for(i=head[f];~i;i=edge[i].nex)
		{
			int v=edge[i].to;
			if(vis[v]) continue;
			vis[v]=vis[f]+1;
			tp.push(v);
		}
	}
	return 0;
}

鏈式前向星的優點在於可以通過該表示式:for(int i=head[u];~i;i=edge[i].next),很好的對各個點所連有的點進行遍歷。通常在題目中只需執行起始頂點的相應bfs/dfs函式,即可完成對整個圖的遍歷。


相關推薦

儲存DFSBFS

圖的儲存方式:1.圖的陣列(鄰接矩陣)儲存表示,其中無向圖的儲存方式為對稱矩陣陣列,有向圖的儲存方式為非對稱矩陣陣列。求最短路徑時常常採用陣列儲存表示各點間的路徑。2.邊集方法                    邊的定義:     stuct edge_set{     

鄰接表存或vector

#include<bits/stdc++.h> #define maxn 100005 using namespace std; // 鏈式前向星 常數優秀,使用結構體可獲得更優秀的常數 int info[maxn],to[maxn<<1],Prev[maxn&

洛谷P3371單源最短路徑Dijkstra版處理

jks 沒有 style bool while add 是什麽 最短 短路徑 首先講解一下鏈式前向星是什麽。簡單的來說就是用一個數組(用結構體來表示多個量)來存一張圖,每一條邊的出結點的編號都指向這條邊同一出結點的另一個編號(怎麽這麽的繞) 如下面的程序就是存鏈式前向星。(

儲存-池子法可用於樹形dp建樹

歡迎點選檢視 不過您仍可閱讀本文在網易部落格的副本: ======================================================  “鏈式前向星”是我創造的(至少Baidu上沒有搜到)名詞,或許這種資料結構有其他更加正規易懂的名字,但我還是沒有搜到。(有一個資

三種存方式鄰接矩陣,鄰接表,

#include<cstdio> #include<vector> #include<cstring> #include<algorithm> #include <iostream> using namespace std; const i

樹、簡單儲存方法——鄰接矩陣 鄰接表 和 學習筆記

ps:樹是一種特殊的圖,樹有自己特殊的儲存方式,圖的儲存方式都能應用於樹。 對於圖、樹來講,一般給出一個n表是有n個節點(標號1~n)m個二元組(a,b)表示ab之間有一條邊。這樣就能確定一個圖。 對於樹來講沒有環,所以m=n-1 part one、鄰接矩陣 鄰接矩陣

+ ——儲存

轉載連結 一、前向星 1、 我們首先來看一下什麼是前向星. 前向星是一種特殊的 邊集 陣列 ,我們把邊集陣列中的每一條邊按照起點從小到大排序,  如果起點相同就按照終點從小到大排序, 並記錄下以某個點為起點的所有邊在陣列中的起始位置和儲存長度,那麼前向星就構

UESTC30-最短路-Floyd最短路、spfa+

ring 輸入 sam -m 努力 成都 edge 輸出 工作 最短路 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) 在每年的校賽裏,所有進入決

算法筆記--的存儲之

算法筆記 div soft 鏈式前向星 target href 圖的存儲 blank 所有 鏈式前向星 這個博客寫的不錯:http://www.cnblogs.com/Tovi/p/6194786.html 模板: ①add_edge void add_e

最短路 spfa 算法 &&

.com mem ont .aspx 百度 dfs edit 時間復雜度 tails 推薦博客 https://i.cnblogs.com/EditPosts.aspx?opt=1      http://blog.csdn.net/mcdonnell_douglas/

POJ 3159 Candies差分約束+spfa+

void tdi div con pre ace != view ash 題目鏈接:http://poj.org/problem?id=3159 題目大意:給n個人派糖果,給出m組數據,每組數據包含A,B,C三個數,意思是A的糖果數比B少的個數不多於C,即B的糖果數 -

img detail pre nlog 避免 target 我們 ext edge 轉自大佬博客https://blog.csdn.net/ACdreamers/article/details/16902023 我們首先來看一下什麽是前向星. 前向星是一種特殊的邊

-深度理解

前向星 在接觸鏈式前向星之前,先了解一下什麼是前向星。 前向星就是一種邊集陣列。我們先把每條邊的起點按照從小到大的順序排序如果起點一樣,那麼就按照終點從小到達來排 序。並記錄下以某個點為起點的所有邊在陣列中的起始位置和邊的數量,那麼前向星就構造好了。 head[i]表示以i為起點

Python實現二叉樹的建立以及遞迴序、序、後序,隊棧序、序、後序、層次

class Node: def __init__(self,data): self.data=data self.lchild=None self.rchild=None class Tree: def __init__(se

系列

看名字很難,實際上賊簡單... 本蒟蒻瑟瑟發抖,請大佬們不要噴... 寫的有點長,如果覺得讀不下去... 肯定讀的下去,我寫得多通俗易懂啊! 不要管右面的表格...看左面的圖...好,讓我們開始: PS:n代表點的個數,m代表邊的個數   Part 1:鄰接矩陣 先列出來矩陣,然

P1462 通往奧格瑞瑪的道路SPFA++二分

題目背景 在艾澤拉斯大陸上有一位名叫歪嘴哦的神奇術士,他是部落的中堅力量 有一天他醒來後發現自己居然到了聯盟的主城暴風城 在被眾多聯盟的士兵攻擊後,他決定逃回自己的家鄉奧格瑞瑪 題目描述 在艾澤拉斯,有n個城市。編號為1,2,3,...,n。 城市之間有m條雙向的公路,連線著

方法之+BFS例項精講

存圖方法有很多,最暴力的方法就是開一個二維陣列 int maze[1000][1000]; //最多能大概5000 5000 int a, b, c; // 一條從a到b的權值為c的邊 while( cin >> a >> b >>

BFS反向BFS反向建邊

題目描述 在有向圖G 中,每條邊的長度均為1 ,現給定起點和終點,請你在圖中找一條從起點到終點的路徑,該路徑滿足以下條件: 1 .路徑上的所有點的出邊所指向的點都直接或間接與終點連通。 2 .在滿足條件1 的情況下使路徑最短。 注意:圖G 中可能存在重邊和自環,題目保證終點沒有出邊。 請你輸出符合條件的路徑

POJ 2387 經典解法,優先佇列的dijkstra+儲存

這是很經典的解法,採用鏈式前向星的方式儲存邊,最短路Dijkstra+優先佇列。時間複雜度減少很多 Til the Cows Come Home Time Limit: 1000MSMemory Limit: 65536KTotal Submissions:

前向星 span 鏈式前向星 pan ont 學會 family style mil 鏈式前向星 鏈式前向星 鏈式前向星 重要的事情說三遍 明天不學會鏈式前向星我絕食三天鏈式前向星