关节点算法(深度优先搜索)

文章介绍了关节点的概念,即在连通图中,必须经过的顶点才能到达其他部分。通过深度优先搜索两次,首先计算访问次序num数组,然后确定low数组,从而识别关节点。算法复杂度为O(|E|+|V|),适用于查找图的结构关键点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关节点算法

  1. 关节点的定义
    在连通图当中,对于某个顶点的孩子顶点或其子树中顶点,如果要访问某个顶点的双亲节点或更上级节点,必须经过此顶点,那么此顶点我们称之为关节点。 对于关节点之下的某个子树,这个关节点充当"一夫当关,万夫莫开"的角色。在算法中,关节点可以通过多次深度优先搜或合并的深度优先搜索求得。
  2. 关节点算法中的基本规则
    对于本文中的图,我们抽象出下属几个变量和规则来完成关节点的算法。
    在这里插入图片描述
    对于每个顶点,都具备以下属性:
  • num[v]: 通过DFS访问某个顶点的次序,为了方便描述我们定义A为0号元素,以此类推,那么从顶点A开始遍历,num[v]的可能数组为num[0]=1, num[3]=1, num[4]=3, num[5]=4,num[2]=5, num[6]=6; num[1]=7;
  • visited[v]: 标记元素v是否被访问,未方位标记为0,已访问标记为1
  • low[v]数组,对于某个元素的low[v]的值,取决于下列三类值的递归大小
    • num[v] - Rule 1
    • the lowest num[w] among all back edges(v,w)- Rule 2
    • the lowest low[w] among all tree edges(v,w) -Rule 3

对于num[v],代表节点自身访问次序号,它不考虑任何tree edge 或者 back edge,可以采用先序深度遍历实现;对于num[w]只得是v的某个孩子节点或更下的孩子节点有回边到v的父节点之上的顶点(v的直接父节点不考虑);对于low[w]为在孩子节点中不断搜寻最小的值,逐个孩子进行比较,这里涉及到后续遍历处理完成退出递归后的比较处理,在这个过程中可能也涉及到回边的处理。

  1. 判断为节点的条件,有两种情况可以认定某个顶点为节点
  • 如果根节点有两个或两个以上的独立的子树,那么根节点就是关节点,因为如果移除根节点,那么就会形成两棵独立的子树
  • 对于非根节点,如果其low(w)>=num(v), 其中w为v的邻接点,这时候,如果w要回达到v以上的祖先节点,那么v就是必经点,此时v为关节点。如果v为根节点,那么此关系总成立,所以需要进行独立判断。
  1. 代码实现,本代码采用两个DFS进行遍历,其中第一个DFS求出num数组,第二个DFS进行遍历,求出low数组,同时打印出关节点。在第二个DFS遍历过程中,需要判断(v,w)边的类型,可以利用num数组进行判断,对于tree edge(直接遍历边),num[w]>num[v],对于back edge(回边)num[w]<num[v], 通过比较两个顶点大小,便可判断访问边的基本类型。
/*
@brief, 
This function will work out the vertex visiting order via DFS traversal and the order will be kept in the num[s] in the pre-order mode
@param G, Adjacent List Graph
@param s, Starting Search Point
*/
void assign_num(ALGraph G,int s)
{
    int v;
    int w;
    
    //counter is the global variable to indicate the visiting order
    //num is also the global varaible shared in different functions
    //visited[] indicate if the vertex had been visited or not    
    num[s]=counter++;
    visited[s]=1;
    v = s;

    for(w=FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w))
    {
        if(!visited[w])
        {
        	//parent[] will be used if keep the parent of vertex
            parent[w]=v;
            assign_num(G,w);
        }
    }
}



void assign_low(ALGraph G, int s,void (*visit)(VertexType e))
{
    int v;
    int w;

    v=s;

    low[v]=num[v]; //Rule 1, taking no edges into account/consideration

    for(w=FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w))
    {
        if(num[w]>num[v]) //tree(forward) edge, rule 3
        {
            assign_low(G,w,visit);

            if(low[w]>=num[v])
            {
                visit(G.vertices[v].data);
            }

//select the minimum low[v] from variout w children
            if(low[v]>low[w]) 
            {
                low[v]=low[w];
            }
        }
        //parent[v]!=w will exclude the v's direct parent 
        //since it had been visited in the recursive call
        else if(parent[v]!=w) //backward edge rule 2
        {
            if(low[v]>num[w])
            {
                low[v]=num[w];
            }
        }
    }
}


//@param s Search start point and will take as the root node
void find_articulation_point(ALGraph G, int s, void (*visit)(VertexType e))
{
    int v;
    int w;
    v=s;
    counter =1;
    memset(visted,0,sizeof(int)*MAX_NUM_VERTEX);

    visited[s]=1;
    num[s]=counter++;

    w=FirstAdjVex(G,v);
    assign_num(G,w);
    assign_low(G,w,visit);

	//if counter is less than the total number of vertex
	// it indciates root vertex will have more than 1 tree
	// the root node will be articulation point
    if(counter<G.vexnum)
    {
        visit(G.vertices[s].data);

        while(NextAdjVex(G,v,w)>=0)
        {
            w=NextAdjVex(G,v,w);
            if(!visited[w])
            {
                assign_num(G, w);
                assign_low(G, w, visit);
            }
        }
    }
    
}
  1. 总结
    对于关节点,其关键思想在于探测某个顶点的子树中节点是否存在回边(back edge),如果某个子树中所有顶点都不存在回边,无论其它子树是否存在回边,那么此顶点就是关节点。其程序实现的核心在于利用 先序和后续处理相结合的方式,最终求得图的所有关节点,其算法复杂度都为O(|E|+|V|).
    求low[v]过程为,比上(祖先节点)比下(孩子节点)比自己(初始访问次序号或根节点号),最后取最小。

2023-2 上海

Reference book
《Data structure and Algorithm Analysis in C, Second Edition》
by Mark Ellen Weiss

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值