1. 程式人生 > >資料結構之圖的關節點和重連通分量

資料結構之圖的關節點和重連通分量

               本著業界良心,我感覺這個連結中關於圖的關節點講得很不錯。什麼是關節點?在某圖中,若刪除頂點V以及V相關的邊後,圖的一個連通分量分割為兩個或兩個以上的連通分量,則稱頂點V為該圖的一 個關節點

                                               

如圖所示,圖中有四個關節點A/B/D和G,如頂點B和它的邊被刪除,圖就會被分為3個連通分量A,C,F,L,M,J;G,H,I,K;D,E.一個沒有關節點的連通圖稱為重連通圖,上圖顯然不是重連通圖

       利用深度優先搜尋便可以求的圖的關節點,本由此可判別圖是否重連通。

  上圖右邊是從頂點A出發深度優先搜尋遍歷所得的深度優先生成樹。對於樹中任一頂點V而言,其孩子節點為鄰接點。由深度優先生成樹可得出兩類關節點的特性:

  (1)若生成樹的根有兩棵或兩棵以上的子樹,則此根頂點必為關節點。因為圖中不存在連線不同子樹頂點的邊,若刪除此節點,則樹便成為森林。

  (2)若生成樹中某個非葉子頂點V,其某棵子樹的根和子樹中的其他節點均沒有指向V的祖先的回邊,則V為關節點。因為刪去v,則其子樹和圖的其它部分被分割開來

        若對圖Graph=(V,{Edge}) 重新定義遍歷時的訪問函式visited,並引入一個新的函式low,則由一次深度優先遍歷便可求得連通圖中存在的所有關節點。

               
        定義visited[v]為深度優先搜尋遍歷連通圖時訪問頂點v 的次序號;定義:

                   

          
            對於某個頂點v,存在孩子結點w 且low[w]≧visited[v],則該頂點v 必為關節點。因為當w 是v 的孩子結點時,low[w]≧visited[v],表明w 及其子孫均無指向v 的祖先的回邊。由定義可知,visited[v]值即為v 在深度優先生成樹的前序序列的序號,只需將DFS 函式中頭兩個語句改為visited[v0]=++count(在DFSTraverse 中設初值count=1)即可;low[v]可由後序遍歷深度優先生成樹求得,而v 在後序序列中的次序和遍歷時退出DFS 函式的次序相同,由此修改深度優先搜尋遍歷的演算法便可得到求關節點的演算法.

     程式碼如下(註釋比較詳細了):

/*
* @description:求關節點,關節點的定義;假如刪除頂點v及相關各邊後,將圖的一個
	聯通分量分割成兩個或是兩個以上的聯通分量,則頂點v為圖的關節點
* @more:注意根節點的情況是需要單獨處理的,其關節點成立的條件是:
	生成樹的根有兩棵或兩顆以上的子樹
	因為圖中不存在連線不同子樹的根節點的邊,這樣在遍歷子樹的過程,
	會存在有節點子樹是無法遍歷到的,這樣把根節點刪除後,就會把圖分成
	森林
*/
void FindArticul(ALGraph G) {
	int i,v;
	ArcNode *p;
	

	count = 1;
	low[0] = visited[0] = 1;	//表示鄰接表上0號頂點為生成樹的根

	//標誌其他的節點都沒有訪問
	for(i = 1; i < G.vexnum ; i++) 
		visited[i] = FALSE;

	p = G.vertices[0].firstarc;
	v = p->adjvex;

	DFSArticul(G,v);	//從第一個鄰接點開始進行查詢

	if(count < G.vexnum ) {
		//根節點為關節點,輸出
		printf("%d,%d\n",0,G.vertices[0].data);
		//繼續往下找
		while(p->nextarc) {
			p = p->nextarc;
			v = p->adjvex;
			if(visited[v] == 0) 
				DFSArticul(G,v);
		}
	}

	
}


/*
* @descirption:從第v的節點出發深度優先遍歷圖查詢圖的關節點
* @more:注意visited[]現在不再是單純的訪問標誌(0/1)而是1/vexnum-1,
	是通過深度優先搜尋遍歷得到的,且在遍歷的過程的中生成樹中
	父親節點的總是並孩子節點先遍歷到
	而low[]是類似後序遍歷得到的,也就是說孩子節點是先於父親節點
	遍歷到的
*/
void DFSArticul(ALGraph G,int v) {
	int min,w;
	ArcNode *p;


	//v是第count訪問的節點
	visited[v] = min = ++count;
	//對v的每個鄰接點進行遍歷
	for(p = G.vertices[v].firstarc ; p ; p = p->nextarc ) {
		//w是v的鄰接點
		w = p->adjvex;

		//w未曾訪問,是v的孩子
		if(visited[w] == 0) {
			//返回前求得low[w]
			DFSArticul(G,w);
			/*如果v的孩子節點的low小,說明其還有祖先節點和孩子節點相連,
			這也是為什麼上面要先返回low[w]的原因
			*/
			if(low[w] < min)
				min = low[w];

			if(low[w] >= visited[v])
				printf("%d,%d\n",v,G.vertices[v].data);
		}
		//w已經訪問過,w是v0在生成樹上的祖先
		else if(visited[w] < min)
			min = visited[w];
	}

	/*
	v的節點的low為visited[v]/low[w]/visited[k]中最小的
	w是頂點v的在深度優先生成樹上的孩子節點
	k是頂點v在深度優先生成樹有回邊連線的祖先節點
	*/
	low[v] = min; 

	Order_Low[v] = lowcount++;	//用於理解
}

貼個測試程式碼:

/*---------------------------------------------------------------------------
 * file:ALGraph.c
 * date:10-14-2014
 * author:[email protected]
 * version:1.0
 * description:鄰接表實現圖的基本操作及求圖的關節點
 ----------------------------------------------------------------------------*/


#include <stdio.h>
#include "findarticul.h"

int main() {
	int i;
	ALGraph G;
	
	//建立圖
	CreateGraph(&G);

	//深度優先遍歷圖
	DFSTraverse(G,PrintElem);
	
	printf("\n");

	//求關節點
	FindArticul(G);

	printf("i	G.vertices[i].data	visited[i]	low[i]	Order_Low\n");
	for(i = 0; i < G.vexnum ; i++) 
		printf("%d	%d	%d	%d	%d\n",i,G.vertices[i].data,visited[i],low[i],Order_Low[i]);

	return 0;


	/*
	please enter the kind of graph(DG:0,DN:1,UDG:2,UDN:3):2
	please the vexnum and arcnum:13,17
	please enter the value of each vertex:1,2,3,4,5,6,7,8,9,10,11,12,13
	please enter the heads and tails:
	1,2
	1,3
	1,6
	1,12
	2,3
	2,4
	2,7
	2,8
	2,13
	4,5
	7,8
	7,9
	7,11
	8,11
	10,12
	10,13
	12,13

	>>(可以看到2輸出了兩次,這是因為刪除2會將圖分割成三顆樹)
	1	2	3	4	5	7	8	11	9	13	10	12	6	
	6,7
	1,2
	3,4
	1,2
	0,1
	i	G.vertices[i].data	visited[i]	low[i]	Order_Low
	0	1	1	1	0
	1	2	5	1	9
	2	3	12	1	8
	3	4	10	5	7
	4	5	11	10	6
	5	6	13	1	12
	6	7	8	5	3
	7	8	6	5	5
	8	9	9	8	2
	9	10	4	2	1
	10	11	7	5	4
	11	12	2	1	11
	12	13	3	1	10

	*/
}

完整的原始碼看:GitHub
 

相關推薦

資料結構關節點連通分量

               本著業界良心,我感覺這個連結中關於圖的關節點講得很不錯。什麼是關節點?在某圖中,若刪除頂點V以及V相關的邊後,圖的一個連通分量分割為兩個或兩個以上的連通分量,則稱頂點V為該圖的一 個關節點。                         

關節點連通分量

一、介紹 關節點問題主要是用線上路架設上,一旦關節點損壞,線路網就斷開了。因此為避免這種情況,需要將網做出重連通圖。關節點更像是把圖分成了兩部分,而這兩部分只通過這個關節點連結。顯然如果這個關節點斷了,這兩個子圖就無法再通訊了。 二、演算法 基於深

->連通性->關節點連通分量

文字描述   相關定義:假若在刪去頂點v以及和v相關聯的各邊之後,將圖的一個連通分量分割成兩個或兩個以上的連通分量,則稱頂點v為該圖的一個關節點.一個沒有關節點的連通圖稱為重連通圖. 在重連通圖上,任意一對頂點之間至少存在兩條路徑, 則在刪去某個頂點以及依附於該頂點的各邊時也不破壞圖的連通性.若在連通圖上至

資料結構篇(2):的基本操作 深度廣度遍歷

程式碼實現 main.cpp(主函式) #include <iostream> #include "CMap.h" using namespace std; /** 圖的的儲存:鄰接矩陣 圖的遍歷:深度+廣度 A / \

資料結構的深度優先遍歷廣度優先遍歷

1.圖的簡單介紹 上圖就是一個圖(無線圖),由頂點和連線組成 圖可以分為無向圖和有向圖(這個又有出度、入度的概念)、網,一般來說圖有兩種常用的表示方式,鄰接矩陣(用二維陣列的形式表示)和鄰接表(主要是陣列+連結串列的形式表示),圖常用的遍歷方式有深度優先遍歷(DFS)和廣

資料結構的遍歷部分性質

無向圖和有向圖 1、無向圖中,任意兩個頂點之間都存在邊的話,就是無向完全圖。   含有n個頂點的無向完全圖有n×(n−1)2條邊。   有向圖中,若任意兩個頂點之間都存在方向互為相反的有向邊,則就是有向完全圖。   含有n個頂點的有向完全圖有n×(

資料結構(鄰接表儲存,DFSBFS遍歷)

     來看下面的一個簡單的圖,       那麼這樣的一個圖,我們應該用什麼儲存結構來儲存它呢?常用的是鄰接矩陣和鄰接表,這裡鄰接矩陣不做講解,如下所有程式碼都是以鄰接表作為儲存結構,所以這裡就只講解下鄰接表。那麼什麼是鄰接表呢?如何構造呢?       鄰接表是一

資料結構的關鍵路徑

title: 資料結構之圖的關鍵路徑 tags: 資料結構與演算法之美 一、AOE和AOV網 1.AOE網 AOE-網:指用邊表示活動的網,是一個帶權的有向無環圖,其中,頂點表示事件弧表示活動,權表示活動持續的時間,通常一個AOE-網可用來估算工程的完成時間。 2.AOV網 指用頂點表示活動

資料結構(帶權 迪傑斯特拉演算法)

// 主要思想是: 每次尋找最小的邊  這樣的話從上一個節點 到這個節點的值 是最小的 當找到最小的邊時,把final[v] = true 表示從原點到這個節點的最小值 已經找到了   <!DOCTYPE html> <html> &l

資料結構(鄰接表 稀疏

<!DOCTYPE html> <html> <head>     <title>鄰接表</title>     <meta charset="utf-8">

資料結構的最小生成樹

我們把構造連通網的最小代價生成樹稱為最小生成樹,找連通網的最小生成樹,經典的有兩種演算法:普里姆演算法(Prim)和克魯斯卡爾演算法(Kruskal)。 普里姆演算法 有如下鄰接矩陣,9個頂點,左側數字為行號,INFINITY為極大值65535,MAXVEX為頂點個數最大值,此處

資料結構的遍歷

圖的遍歷是和樹的遍歷類似,我們希望從圖中某一點出發訪問圖中其餘頂點,且使每一個頂點僅被訪問一次,這一過程就叫做圖的遍歷。 深度優先遍歷 深度優先遍歷,也稱之為深度優先搜尋,簡稱DFS。首先指定一個規則,在沒有碰到重複頂點的情況下,始終向右手邊走,A-B-C-D-E-F,走到F時發

資料結構篇(1):概述

圖的概念 1.有向圖(由節點和方向箭頭構成)無向圖(只有節點,相當於每條連線都是雙向的) 2.出度:頂點的箭頭指出;入度:頂點的箭頭指入; 3.有向圖:弧;無向圖:邊; 5.權值:弧或者邊上的資料 圖的儲存結構 陣列儲存 1.鄰接矩陣(頂點陣列【索引+資料】+鄰接矩

資料結構學習筆記

一、圖的定義:     圖(Graph)是由頂點的有窮非空集合和頂點之間邊的集合組成,通常表示為:G(V,E),其中,G表示一個圖,V表示圖G中頂點的集合,E是圖G中的邊集合。     a.線性表中的資料元素我們稱為元素,樹中資料元素稱為節點,而圖中的

資料結構鄰接表

還是插入一段程式碼來解釋鄰接表的建立過程。 //自己建立一個鄰接表 //邊表結點 typedef struct { int adjvex;//該邊的頭結點 int weight;//權值 EdgeNode *next;//該邊尾結點的下一條邊 }EdgeNo

資料結構深度搜索八皇后

//八皇后問題 #include<cstdio> #include<iostream> #include<cstdlib> #include<cmath> using namespace std; int a[100],coun

python資料結構串——概述基本演算法

概述: 字串(string)簡稱串,也是一種線性結構。在python中和array差不多,因為py的陣列也可以包括各種字元(在C/Java一類的語法中,陣列必須是同一種資料型別的元素)。線性結構,有限序列,是主要特點。串其中可以包含各種元素,也是計算機主要處理的一類物件。因

資料結構

1.圖的定義 圖(graph)是由一些點(vertex)和這些點之間的連線(edge)所組成的;其中,點通常稱為頂點(vertex),而點到點之間的連線通常稱之為邊或者弧(edge)。通常記為G=(V,E)。 2.圖的分類 圖通常分為有向圖和無向圖,而其表示表示方式

資料結構(的基本操作)

由於圖的基本操作的程式碼較多,我放到這一章來寫。圖可以用兩種方法來儲存,但是本人偏愛連結串列的表示方法,所以以下程式碼也都是是基於鄰接連結串列的儲存方式。 1 /* 2 以下儲存結構參考嚴蔚敏版資料結構,不懂的可以翻閱檢視 3 */ 4 const int UNDIGR

資料結構的簡介)

圖的定義:   一個圖G = (V,E)由頂點(vertex)集 V 合邊(edge)集 E 組成。每條邊(v,w)就是一個點對,其中v,w ∈ V。有時也把邊稱作弧。如果點對是有序的,那麼圖就叫做有向圖。頂點 v 和 w 領接邊 (v,w) ∈ E。在一個具有邊(