返回

树的深度优先遍历+树的重心详解

后端

深度优先遍历

深度优先遍历(DFS)是一种遍历树或图的算法。它通过递归或栈的方式,沿着树或图的深度遍历其节点。DFS 的基本思想是:从一个节点出发,访问该节点的所有子节点,然后依次访问这些子节点的子节点,依此类推,直到所有节点都被访问。

DFS 的优点是:

  • 对于树来说,DFS 的时间复杂度为 O(V + E),其中 V 是树中的节点数,E 是树中的边数。
  • DFS 可以很容易地找到树中的路径。
  • DFS 可以很容易地找到树中的环。

DFS 的缺点是:

  • DFS 可能会访问到重复的节点。
  • DFS 可能会导致栈溢出。

树的重心

树的重心是指一棵树中一个或多个具有最小总距离和的节点。换句话说,树的重心是树中到所有其他节点的距离之和最小的节点。

树的重心可以用来解决许多问题,例如:

  • 在树中寻找一个位置,使得从该位置到所有其他节点的距离之和最小。
  • 在树中寻找一个位置,使得从该位置到所有其他节点的距离之和最大。
  • 在树中寻找一个位置,使得从该位置到所有其他节点的距离之和平均最小。

算法实现

我们可以使用 DFS 来计算树的重心。

def find_centroid(tree, root):
  """
  Finds the centroid of a tree.

  Args:
    tree: A tree represented as a list of lists of integers.
    root: The root node of the tree.

  Returns:
    The centroid of the tree.
  """

  # Initialize the visited array.
  visited = [False] * len(tree)

  # Initialize the size array.
  size = [0] * len(tree)

  # Initialize the distance array.
  distance = [0] * len(tree)

  # Initialize the centroid array.
  centroid = [-1] * len(tree)

  # Find the size of the tree.
  dfs_size(tree, root, visited, size)

  # Find the distance from each node to the root.
  dfs_distance(tree, root, visited, distance)

  # Find the centroid of the tree.
  find_centroid_dfs(tree, root, visited, size, distance, centroid)

  # Return the centroid of the tree.
  return centroid

def dfs_size(tree, root, visited, size):
  """
  Finds the size of a tree.

  Args:
    tree: A tree represented as a list of lists of integers.
    root: The root node of the tree.
    visited: A list of booleans indicating whether each node has been visited.
    size: A list of integers storing the size of each node.
  """

  # Mark the current node as visited.
  visited[root] = True

  # Initialize the size of the current node.
  size[root] = 1

  # Recursively visit the children of the current node.
  for child in tree[root]:
    if not visited[child]:
      dfs_size(tree, child, visited, size)

      # Add the size of the child to the size of the current node.
      size[root] += size[child]

def dfs_distance(tree, root, visited, distance):
  """
  Finds the distance from each node to the root.

  Args:
    tree: A tree represented as a list of lists of integers.
    root: The root node of the tree.
    visited: A list of booleans indicating whether each node has been visited.
    distance: A list of integers storing the distance from each node to the root.
  """

  # Mark the current node as visited.
  visited[root] = True

  # Initialize the distance from the current node to the root.
  distance[root] = 0

  # Recursively visit the children of the current node.
  for child in tree[root]:
    if not visited[child]:
      dfs_distance(tree, child, visited, distance)

      # Add the distance from the child to the root to the distance from the current node to the root.
      distance[root] += distance[child] + 1

def find_centroid_dfs(tree, root, visited, size, distance, centroid):
  """
  Finds the centroid of a tree.

  Args:
    tree: A tree represented as a list of lists of integers.
    root: The root node of the tree.
    visited: A list of booleans indicating whether each node has been visited.
    size: A list of integers storing the size of each node.
    distance: A list of integers storing the distance from each node to the root.
    centroid: A list of integers storing the centroid of the tree.
  """

  # Mark the current node as visited.
  visited[root] = True

  # Check if the current node is a centroid.
  if size[root] * 2 <= len(tree):
    centroid[root] = True

  # Recursively visit the children of the current node.
  for child in tree[root]:
    if not visited[child]:
      find_centroid_dfs(tree, child, visited, size, distance, centroid)

      # Check if the child is a centroid.
      if centroid[child]:
        centroid[root] = False

  # Check if the current node is the centroid.
  if centroid[root]:
    for child in tree[root]:
      if not visited[child]:
        dfs_distance(tree, child, visited, distance)

        # Check if the child is a centroid.
        if distance[child] * 2 >= len(tree):
          centroid[root] = False

参考文献

结语

深度优先遍历和树的重心是两个重要的图论概念。它们可以用来解决许多问题,例如:找到树中到所有其他节点的距离之和最小的节点、找到树中到所有其他节点的距离之和最大的节点、找到树中到所有其他节点的距离之和平均最小的节点等。