Interview Questions: Undirected Graphs

Undirected Graphs

Nonrecursive depth-first search. Implement depth-first search in an undirected graph without using recursion.

非递归实现DFS。

public void DFS(Graph G, int v, boolean[] marked) {
        Deque<Integer> stack = new ArrayDeque<>();
        stack.push(v);
	    System.out.println(v);
    	marked[v] = true;
        while (!stack.isEmpty()) {
            boolean flag = true;
            int cur = stack.peek();
            for (int w : G.adj(cur)) {
                // 当前栈顶结点存在未被访问的邻接点则将该邻接点入栈
                if (!marked[w]) {
                    stack.push(w);
                    System.out.println(w);
                    marked[w] = true;
                    flag = false;
                    break;
                }
            }
            // 若栈顶结点不存在未被访问的邻接点,则将栈顶结点出栈
            if (flag) {
                stack.pop();
            }
        }
    }

Diameter and center of a tree. Given a connected graph with no cycles

  • Diameter: design a linear-time algorithm to find the longest simple path in the graph.
  • Center: design a linear-time algorithm to find a vertex such that its maximum distance from any other vertex is minimized.

求一个无环树图的直径和中心,直径为树图中长度最长的路径,中心为到其他点的最大距离最小的点。

具体方法:任意选取图中一个点,找到距离这个点最远的点A(对DFS来说,就是递归层次最深的点;对BFS来说,就是队列中最后加入的点),再以点A为起点,找到距离点A最远的点B,那么从A到B构成的路径AB就是所要求的直径,而中心就是这条直径上的中点。所使用的时间为两次遍历,即 O ( 2 V ) O(2V) O(2V)

该方法的正确性证明参考 求最深根贪心证明

Euler cycle. An Euler cycle in a graph is a cycle (not necessarily simple) that uses every edge in the graph exactly once.

  • Show that a connected graph has an Euler cycle if and only if every vertex has even degree.
  • Design a linear-time algorithm to determine whether a graph has an Euler cycle, and if so, find one.

欧拉回路指的是包含了图中所有边(且仅包含一次)的路径。

对于A-B这条边,要么是从A走到B时遍历到这条边(以A的角度为出),要么是从B走到A时遍历到这条边(以A的角度为入)。对于一个结点来说,只有当它的入度等于出度的时候,才能将所有与它连接的边包含到一条路径中。无向图中没有入度出度的概念,转换过来就是对于无向图中的一个结点,只有当与它连接的边的数量为偶数时,才能将这些边包含到一条路径中。

所以一个图只有每一个结点都有偶数条边,且图中只含有一个连通分量,才具有欧拉回路。

关于欧拉回路的路径寻找,参考 【欧拉回路】讲解+判定+输出“点”路径

import java.util.*;

public class Euler {
    Graph g;

    public Euler(Graph g) {
        this.g = g;
    }

    public boolean hasEulerCycle() {
        int[] degree = g.degree();
        // 判断是否每个结点都有偶数条边相连
        for (int i = 0; i < g.V(); i++) {
            if (degree[i] % 2 == 1) {
                return false;
            }
        }
        // 判断是否只有一个连通分量
        return isConnected();
    }

    public Iterable<Integer> findPath() {
        List<Integer> path = new ArrayList<>();
        DFS(0, g.getEdges(), path);
        Collections.reverse(path);
        return path;
    }
    
    // Hierholzers算法寻找欧拉回路
    private void DFS(int v, List<List<Integer>> edges, List<Integer> path) {
        for (int i = 0; i < g.V(); i++) {
            if (edges.get(v).contains(i)) {
                edges.get(v).remove(Integer.valueOf(i));
                edges.get(i).remove(Integer.valueOf(v));
                DFS(i, edges, path);
            }
        }
        path.add(v);
    }

    // 判断是否只有一个连通分量
    private boolean isConnected() {
        Queue<Integer> q = new ArrayDeque<>();
        boolean[] visited = new boolean[g.V()];
        int count = 0;
        q.offer(0);
        visited[0] = true;
        while (!q.isEmpty()) {
            int cur = q.poll();
            count++;
            for (int i : g.adj(cur)) {
                if (!visited[i]) {
                    visited[i] = true;
                    q.add(i);
                }
            }

        }
        return count == g.V();
    }
}

class Graph {
    private List<List<Integer>> edges;
    private int V;
    private int E;
    private int[] degree;

    public Graph() {
        Scanner sc = new Scanner(System.in);
        V = sc.nextInt();
        E = sc.nextInt();
        edges = new ArrayList<>();
        degree = new int[V];
        for (int i = 0; i < V; i++) {
            edges.add(new ArrayList<>());
        }
        for (int i = 0; i < E; i++) {
            int a = sc.nextInt();
            int b = sc.nextInt();
            edges.get(a).add(b);
            degree[a]++;
            edges.get(b).add(a);
            degree[b]++;
        }
        sc.close();
    }


    public Iterable<Integer> adj(int v) {
        return edges.get(v);
    }

    public int V() {
        return V;
    }

    public int E() {
        return E;
    }

    public int[] degree() {
        return degree;
    }

    // 复制一个edges列表传递
    public List<List<Integer>> getEdges() {
        List<List<Integer>> temp = new ArrayList<>();
        for (List<Integer> list : edges) {
            temp.add(new ArrayList<>(list));
        }
        return temp;
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值