数据结构 || 求连通图的关节点

29 篇文章 5 订阅
27 篇文章 1 订阅

对图的存储结构基于无向图的邻接多重表。

关节点和重连通图:

假若在删去顶点v以及v相关联的各边之后,将图的一个连通分量分割成两个或两个以上的连通分量,则称顶点v为该图的一个关节点

如果没有关节点的连通图则称为重连通图(双连通图)

算法实现:

1. 方法一:

最简单也是最直接的算法是,删除一个点然后判断连通性,如果删除此点,图不再连通,则此点是关节点,反之不是关节点(图的连通性一般通过深搜来判定,是否能一次搜索完全部顶点);

2. 方法二:

通过深搜优先生成树来判定。从任一点出发深度优先遍历得到优先生成树,对于树中任一顶点V而言,其孩子节点为邻接点。由深度优先生成树可得出两类邻接点的特性:

(1)若生成树的根有两棵或两棵以上的子树,则此根顶点必为邻接点。因为图中不存在连接不同子树顶点的边,若删除此节点,则树便成为森林;

(2)若生成树中某个非叶子顶点V,其某棵子树的根和子树中的其他节点均没有指向V的祖先的回边,则V为割点。因为删去v,则其子树和图的其它部分被分割开来。

仍然利用深搜算法,只不过在这里定义visit[v]表示为深度优先搜索遍历图时访问顶点v的次序号,也就是第1,2,3…次访问,定义low[v]=Min{visit[v],low[w],visit[k]},其中w是顶点v在深度优先生成树上的孩子节点;k是顶点v在深度优先生成树上由回边联结的祖先节点。

关节点判定条件:如果对于某个顶点v,存在孩子节点w且low[w]>=visit[v],则该顶点v必为关节点。因为当w是v的孩子节点时,low[w]>=visit[v],表明w及其子孙均无指向v的祖先的回边,那么当删除顶点v后,v的孩子节点将于其他节点被分割开来,从来形成新的连通分量。

代码实现:

#include <iostream>
#include <stack>
#include <list>
using namespace std;
#define MAX_VERTEX_NUM 20
class EBox {
public:
	int ivex, jvex; //该边依附的两个顶点位置
	EBox *ilink, *jlink; //分别指向依附这两个顶点的下一条边
};

class VexBox {
public:
	int visit; //访问标记
	int low; //Low函数标记
	string data;
	EBox *firstedge; //指向第一条依附该顶点的边
};

class AMLGraph {
public:
	VexBox adjmulist[MAX_VERTEX_NUM];
	int vexnum, edgenum; //无向图的当前顶点数和边数
};

int LocateVex(VexBox adj[], int num, string v) {
	for (int i = 0; i < num; i++) {
		if (adj[i].data == v) {
			return i;
		}
	}
}

void CreateGraph(AMLGraph *G) {
	cout << "请输入顶点数和弧数: " << endl;
	cin >> G->vexnum >> G->edgenum;
	cout << "请输入顶点: " << endl;
	for (int i = 0; i < G->vexnum; i++) {
		cin >> G->adjmulist[i].data;
		G->adjmulist[i].firstedge = NULL;
		G->adjmulist[i].visit = 0;
		G->adjmulist[i].low = 0;
	}
	for (int i = 0; i < G->edgenum; i++) {
		cout << "请输入边的两个顶点: " << endl;
		string v1, v2;
		cin >> v1 >> v2;
		int i1 = LocateVex(G->adjmulist, G->vexnum, v1);
		int i2 = LocateVex(G->adjmulist, G->vexnum, v2);
		EBox *p = new EBox;
		p->ivex = i1;
		p->jvex = i2;
		p->ilink = G->adjmulist[i1].firstedge;
		p->jlink = G->adjmulist[i2].firstedge;
		G->adjmulist[i1].firstedge = p;
		G->adjmulist[i2].firstedge = p;
	}
}

int FirstAdjVex(AMLGraph G, int v) {
	int i = v;
	if (G.adjmulist[i].firstedge) {
		if (G.adjmulist[i].firstedge->ivex == i) {
			return G.adjmulist[i].firstedge->jvex;
		}
		else {
			return G.adjmulist[i].firstedge->ivex;
		}
	}
	else
		return -1;
}
//v是G中的某个顶点,w是v的邻接顶点
//返回v的(相对于w的)下一个邻接顶点。若w是v的最后一个邻接点,则返回空

int NextAdjVex(AMLGraph G, int v, int w) {
	int i1 = v;
	int i2 = w;
	EBox *p = G.adjmulist[i1].firstedge;
	while (p) {
		if (p->ivex == i1 && p->jvex != i2) {
			p = p->ilink;
		}
		else {
			if (p->ivex != i2 && p->jvex == i1) {
				p = p->jlink;
			}
			else {
				break;
			}
		}
	}
	if (p && p->ivex == i1 && p->jvex == i2) {
		p = p->ilink;
		if (p&&p->ivex == i1) {
			return p->jvex;
		}
		else if (p&&p->jvex == i1)
			return p->ivex;
	}
	if (p && p->ivex == i2 && p->jvex == i1) {
		p = p->jlink;
		if (p&&p->ivex == i1) {
			return p->jvex;
		}
		else if (p&&p->jvex == i1)
			return p->ivex;
	}
	return -1;
}

void DFS(AMLGraph *G, int i) {
	cout << G->adjmulist[i].data << endl;
	G->adjmulist[i].visit += 1;
	for (int w = FirstAdjVex(*G, i); w >= 0; w = NextAdjVex(*G,i,w)) {
		if (G->adjmulist[w].visit == 0) {
			DFS(G, w);
		}
	}
}

void DFSTraverse(AMLGraph *G) {
	for (int i = 0; i < G->vexnum; i++) {
		if (G->adjmulist[i].visit == 0) {
			DFS(G, i);
		}
	}
}

void clearVisited(AMLGraph *G) {
	for (int i = 0; i < G->vexnum; i++) {
		G->adjmulist[i].visit = 0;
	}
}

void DFSArticul(AMLGraph *G, int v0, int *count) {
	int min = 0;
	G->adjmulist[v0].visit = min = ++(*count); //v是第count个被访问的点
	for (int w = FirstAdjVex(*G, v0); w >= 0; w = NextAdjVex(*G, v0, w)) {
		if (G->adjmulist[w].visit == 0) {
			DFSArticul(G, w, count); //返回前求得low[w]
			if (G->adjmulist[w].low < min) {
				min = G->adjmulist[w].low;
			}
			if (G->adjmulist[w].low >= G->adjmulist[v0].visit) {
				cout << G->adjmulist[v0].data << endl;
			}
		}
		else if (G->adjmulist[w].visit < min) {
			min = G->adjmulist[w].visit;
		}
	}
	G->adjmulist[v0].low = min;
}

void FindArticul(AMLGraph *G) {
	int count = 1;
	G->adjmulist[0].visit = 1;
	int v = FirstAdjVex(*G, 0);
	DFSArticul(G, v, &count);
	//根是关节点
	if (count < G->vexnum) {
		cout << G->adjmulist[0].data << endl;
		while (v >= 0) {
			v = NextAdjVex(*G, 0, v);
			if (G->adjmulist[v].visit == 0) {
				DFSArticul(G, v, &count);
			}
		} 
	}
}

int main () {
	AMLGraph g;
	CreateGraph(&g);
	cout << "深度优先遍历: " << endl;
	DFSTraverse(&g);
	clearVisited(&g);
	cout << "------------------" << endl;
	cout << "关节点有: " << endl;
	FindArticul(&g);
	return 0;
}

实现效果:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值