关节点算法

总结一下关节点算法:


主要分为三部分:

1.叶子节点一定不是关节点

2.根节点是一个关节点当他有多个孩子节点时

3.中间节点时一个关节点当它的子树没有回边到它的祖先节点

见代码。

邻接表表示法建树

struct Node{			  //边表节点
	int adjvex;           //改弧所指向的顶点的位置
	Node *next;			  //指向下一条弧的指针
};

struct Vnode{			  //顶点表节点
	int vertex;		  //顶点标志	
	Node* firstEdge;	  //顶点第一条弧的指针
};

struct Graph{
	struct Vnode* adjList;	   //邻接表数组
	int vNum;				   //点的总数
	int eNum;				   //边的总数
};

建立树:

void createGraph(Graph* G){
	
	int V_NUM = 4010;
	//int v_num = 0;
	//int e_num = 0;
	int v_index = 0;
	Node* s;
	//cout<<"请输入顶点数:";
	//cin>>v_num;
	//cout<<"请输入边数:";
	//cin>>e_num;
	//G->eNum = V_NUM;
	G->vNum = V_NUM;
	//cout<<"请输入顶点编号(从0开始):"<<endl;
	cout<<"顶点编号为(从0开始):"<<endl;
	G->adjList = new Vnode[V_NUM];
	for(int i=0; i < G->vNum; i++){
		//cin>>v_index;
		cout<<i<<"  ";
		G->adjList[i].vertex = i;//v_index;
		G->adjList[i].firstEdge = NULL;
	}
	cout<<endl;
	cout<<"请输入由两个顶点构成的边,实例: 0 1"<<endl;
	ifstream in("data\\data3.txt");
	if(! in.is_open()){
		cout<<"Error opening file";
		exit(1);
	}
	int index1, index2;
	char* s1;
	int count = 0;
	//for(int j=0; j < G->eNum; j++){
	while(in>>index1>>index2>>s1){
		count ++;
		//cin>>index1;
		//cin>>index2;
		s = new Node();
		s->adjvex = index2;
		s->next = NULL;
		//无向图,插入边
		Node* p = G->adjList[index1].firstEdge;
		if( p == NULL){
			G->adjList[index1].firstEdge = s;
		}else{
			while(p ->next != NULL){
				p = p ->next;
			}
			p->next = s;
		}
		s = new Node();
		s->adjvex = index1;
		s->next = NULL;
		Node* q = G->adjList[index2].firstEdge;
		if(q == NULL){
			G->adjList[index2].firstEdge = s;
		}else{

			while(q ->next != NULL){
				q = q ->next;
			}
			q->next = s;
		}
	}
	G->eNum = count;
	//}
}

关节点代码:

void artPoint(Graph* G, int u, int *color, int *low, int *d, int *pred){
	color[u] = 1; //表示已访问
	low[u] = d[u] = ++ cnt;
	for(Node * p = G->adjList[u].firstEdge; p != NULL; p = p ->next){
		int v = p ->adjvex;
		if(color[v] == 0){  //(u,v)是树边,v未被访问
			pred[v] = u;
			artPoint(G, v, color, low, d, pred); //访问v
			low[u] = min(low[u], low[v]);
			if(pred[u] == -1){ //u是根节点
				//判断u是否还有第二个子节点
				Node* q = p;
				while(q->next != NULL){
					if(color[q->next->adjvex] == 0){ //未访问
						//判断关节点是否已存在

						bool isExists = false;
						for(int k=0; k < artPoints.size(); k++){
							if(artPoints[k].vertex == G->adjList[u].vertex){
								isExists = true;
							}
						}
						if(!isExists){
							artPoints.push_back(G->adjList[u]);	
						}
					}
					q = q -> next;
				}
			}else if(low[v] >= d[u]){	
				//判断关节点是否已存在
				bool isExists = false;
				for(int k=0; k < artPoints.size(); k++){
					if(artPoints[k].vertex == G->adjList[u].vertex){
						isExists = true;
					}
				}
				if(!isExists){
					//添加u到articulation points中
					artPoints.push_back(G->adjList[u]);	
				}
			}
		}else if(v !=pred[u]){ //(u,v)是回边
			low[u] = min(low[u], d[v]);
		}
	}
	color[u] = 2; //表示访问结束
}


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值