树与图的深度优先遍历,树的DFS序、深度和重心

深度优先遍历:时间复杂度为 O(n+m)

void dfs(int x){
    v[x] = 1;// 记录点 x 已被访问过
    for(int i = head[x]; i; i = next[i]) {
        int y = ver[i];
        if(v[y]) continue;// 点 y 已经被访问过了
        dfs(y);
    }
}

 树的DFS序:对于每个节点,在刚进入递归后递归后以及即将回溯前各ji记录一次该点的编号,最后产生的长度为 2N 的节点序列就称为树的DFS序。

DFS序的特点是:每个节点 x 的编号在序列中恰好出现两次。设这两次出现的位置为 L[x] 与 R[x],那么bi’q闭区间 [L[x],R[x]] 就是以 x为根的子树的DFS序。

void dfs(int x){
    a[++m] = x;//存储 DFS序
    v[x] = 1;//记录点 x 被访问过
    for(int i = head[x]; i; i = next[i]) {
        int y = ver[i];
        if(v[y]) continue;
        dfs(y);
    }
    a[++m]=x;
}

树的深度:树中各个节点的深度shi’是一种自顶向下的的统计信息。根节点的深度为0。若节点 x 的深度为 d[x],则它的子节点 y 的深度为: d[y] = d[x] +1。

void dfs(int x){
   v[x] = 1;
   for(int i = head[x]; i; i = next[i]) {
       int y = ver[i];
       if(v[y]) continue;
       d[y] = d[x] + 1;//从父节点向子节点递推,计算深度
       dfs(y);
   }
}

树的重心: 对于叶子节点,我们已知 “以它为根的子树” 大小为1。若节点 x 有 k 个子节点 y1~yk,则以 x 为根的子树的大小就是:size[x] = size[y1]+ size[y2] + … + size[yk]。

对于一个节点 x ,如果我们把它从树中删除,那么原来的一棵树可能会分成若干个不相连的部分,其中每一部分都是一颗子树。设max_part 表示在删除节点 x 后产生的子树中最大的一棵的大小。使得 max_part 取得最小值的节点 p 就称为整棵树的重心。

void dfs(int x){
    v[x] = 1;
    Size[x] = 1;
    int max_part=0;
    for(int i = head[x]; i; i = next[i]) {
        int y = ver[i];
        if(v[y]) continue;
        dfs(y);
        Size[x] += Size[y];//从子节点向父节点递推
        max_part = max(max_part, Size[y]);
    }
    max_part = max(max_part, n - Size[x]);//n 为整棵树的节点数目
    if(max_part < ans){
        ans = max_part;//全局变量 ans 记录重心对应的 max_part值
        pos = i;//全局变量 pos 记录了重心
    }
}

图的连通块划分:每从 x 开始一次遍历,就会访问 x 能够到达的所有的点与边。因此,通过多次深度优先遍历,可以划分处一张无向图中的各个连通块。同理,对一个森林进行深度优先遍历,可以划分处森林中的每棵树。

void dfs(int x){
   v[x] = cnt;
   for(int i = head[x]; i; i = next[i]){
       int y = ver[i];
       if(v[y]) continue;
       dfs(y);
   }
}
for(int i = 1; i <= n; i++){//在 main()函数中
    if(!v[i]){
        cnt++;
        dfs(i);
    }
}

 

 

    原文作者:数据结构之图
    原文地址: https://blog.csdn.net/qq_37867156/article/details/82468838
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞