📌  相关文章
📜  打印树的任意两个节点之间的路径。 DFS

📅  最后修改于: 2021-05-31 18:31:50             🧑  作者: Mango

给定一棵具有N-1个边缘的不同节点N和一对节点P的树。任务是使用DFS查找并打印树的两个给定节点之间的路径。

Input: N = 10
          1
       /    \
      2      3
    / | \  / | \
   4  5 6  7 8  9
Pair = {4, 8}
Output: 4 -> 2 -> 1 -> 3 -> 8

Input: N = 3
      1
     /  \
    2    3
Pair = {2, 3}
Output:  2 -> 1 -> 3

例如,在上面的树中,节点53之间的路径是5-> 2-> 1-> 3
节点48之间的路径是4-> 2-> 1-> 3-> 8

方法:

  • 想法是从源节点运行DFS,并将遍历的节点推入堆栈,直到遍历目标节点。
  • 每当发生回溯时,从堆栈中弹出节点。

注意:在给定的节点对之间应该有一条路径。
下面是上述方法的实现:

C++
// C++ implementation
#include 
using namespace std;
 
// An utility function to add an edge in an
// undirected graph.
void addEdge(vector v[],
             int x,
             int y)
{
    v[x].push_back(y);
    v[y].push_back(x);
}
 
// A function to print the path between
// the given pair of nodes.
void printPath(vector stack)
{
    int i;
    for (i = 0; i < (int)stack.size() - 1;
         i++) {
        cout << stack[i] << " -> ";
    }
    cout << stack[i];
}
 
// An utility function to do
// DFS of graph recursively
// from a given vertex x.
void DFS(vector v[],
         bool vis[],
         int x,
         int y,
         vector stack)
{
    stack.push_back(x);
    if (x == y) {
 
        // print the path and return on
        // reaching the destination node
        printPath(stack);
        return;
    }
    vis[x] = true;
 
    // if backtracking is taking place
    if (!v[x].empty()) {
        for (int j = 0; j < v[x].size(); j++) {
            // if the node is not visited
            if (vis[v[x][j]] == false)
                DFS(v, vis, v[x][j], y, stack);
        }
    }
 
    stack.pop_back();
}
 
// A utility function to initialise
// visited for the node and call
// DFS function for a given vertex x.
void DFSCall(int x,
             int y,
             vector v[],
             int n,
             vector stack)
{
    // visited array
    bool vis[n + 1];
 
    memset(vis, false, sizeof(vis));
 
    // DFS function call
    DFS(v, vis, x, y, stack);
}
 
// Driver Code
int main()
{
    int n = 10;
    vector v[n], stack;
 
    // Vertex numbers should be from 1 to 9.
    addEdge(v, 1, 2);
    addEdge(v, 1, 3);
    addEdge(v, 2, 4);
    addEdge(v, 2, 5);
    addEdge(v, 2, 6);
    addEdge(v, 3, 7);
    addEdge(v, 3, 8);
    addEdge(v, 3, 9);
 
    // Function Call
    DFSCall(4, 8, v, n, stack);
 
    return 0;
}


Java
// Java implementation of the above approach
import java.util.*;
class GFG
{
    static Vector> v = new Vector>();
     
    // An utility function to add an edge in an
    // undirected graph.
    static void addEdge(int x, int y){
        v.get(x).add(y);
        v.get(y).add(x);
    }
     
    // A function to print the path between
    // the given pair of nodes.
    static void printPath(Vector stack)
    {
        for(int i = 0; i < stack.size() - 1; i++)
        {
            System.out.print(stack.get(i) + " -> ");
        }
        System.out.println(stack.get(stack.size() - 1));
    }
     
    // An utility function to do
    // DFS of graph recursively
    // from a given vertex x.
    static void DFS(boolean vis[], int x, int y, Vector stack)
    {
        stack.add(x);
        if (x == y)
        {
           
            // print the path and return on
            // reaching the destination node
            printPath(stack);
            return;
        }
        vis[x] = true;
       
        // if backtracking is taking place     
        if (v.get(x).size() > 0)
        {
            for(int j = 0; j < v.get(x).size(); j++)
            {
               
                // if the node is not visited
                if (vis[v.get(x).get(j)] == false)
                {
                    DFS(vis, v.get(x).get(j), y, stack);
                }
            }
        }
         
        stack.remove(stack.size() - 1);
    }
     
    // A utility function to initialise
    // visited for the node and call
    // DFS function for a given vertex x.
    static void DFSCall(int x, int y, int n,
                        Vector stack)
    {
       
        // visited array
        boolean vis[] = new boolean[n + 1];
        Arrays.fill(vis, false);
       
        // memset(vis, false, sizeof(vis))
       
        // DFS function call
        DFS(vis, x, y, stack);
    }
     
  // Driver code
    public static void main(String[] args)
    {
        for(int i = 0; i < 100; i++)
        {
            v.add(new Vector());
        }
     
        int n = 10;
        Vector stack = new Vector();
           
        // Vertex numbers should be from 1 to 9.
        addEdge(1, 2);
        addEdge(1, 3);
        addEdge(2, 4);
        addEdge(2, 5);
        addEdge(2, 6);
        addEdge(3, 7);
        addEdge(3, 8);
        addEdge(3, 9);
           
        // Function Call
        DFSCall(4, 8, n, stack);
    }
}
 
// This code is contributed by divyeshrabadiya07


Python3
# Python3 implementation of the above approach
v = [[] for i in range(100)]
 
# An utility function to add an edge in an
# undirected graph.
def addEdge(x, y):
    v[x].append(y)
    v[y].append(x)
 
# A function to print the path between
# the given pair of nodes.
def printPath(stack):
    for i in range(len(stack) - 1):
        print(stack[i], end = " -> ")
    print(stack[-1])
 
# An utility function to do
# DFS of graph recursively
# from a given vertex x.
def DFS(vis, x, y, stack):
    stack.append(x)
    if (x == y):
 
        # print the path and return on
        # reaching the destination node
        printPath(stack)
        return
    vis[x] = True
 
    # if backtracking is taking place
 
    if (len(v[x]) > 0):
        for j in v[x]:
             
            # if the node is not visited
            if (vis[j] == False):
                DFS(vis, j, y, stack)
                 
    del stack[-1]
 
# A utility function to initialise
# visited for the node and call
# DFS function for a given vertex x.
def DFSCall(x, y, n, stack):
     
    # visited array
    vis = [0 for i in range(n + 1)]
 
    #memset(vis, false, sizeof(vis))
 
    # DFS function call
    DFS(vis, x, y, stack)
 
# Driver Code
n = 10
stack = []
 
# Vertex numbers should be from 1 to 9.
addEdge(1, 2)
addEdge(1, 3)
addEdge(2, 4)
addEdge(2, 5)
addEdge(2, 6)
addEdge(3, 7)
addEdge(3, 8)
addEdge(3, 9)
 
# Function Call
DFSCall(4, 8, n, stack)
     
# This code is contributed by Mohit Kumar


C#
// C# implementation of the above approach
using System;
using System.Collections;
using System.Collections.Generic;
 
class GFG
{
    static List> v = new List>();
     
    // An utility function to Add an edge in an
    // undirected graph.
    static void addEdge(int x, int y)
    {
        v[x].Add(y);
        v[y].Add(x);
    }
     
    // A function to print the path between
    // the given pair of nodes.
    static void printPath(List stack)
    {
        for(int i = 0; i < stack.Count - 1; i++)
        {
            Console.Write(stack[i] + " -> ");
        }
        Console.WriteLine(stack[stack.Count - 1]);
    }
     
    // An utility function to do
    // DFS of graph recursively
    // from a given vertex x.
    static void DFS(bool []vis, int x, int y, List stack)
    {
        stack.Add(x);
        if (x == y)
        {
           
            // print the path and return on
            // reaching the destination node
            printPath(stack);
            return;
        }
        vis[x] = true;
       
        // if backtracking is taking place     
        if (v[x].Count > 0)
        {
            for(int j = 0; j < v[x].Count; j++)
            {
               
                // if the node is not visited
                if (vis[v[x][j]] == false)
                {
                    DFS(vis, v[x][j], y, stack);
                }
            }
        }        
        stack.RemoveAt(stack.Count - 1);
    }
     
    // A utility function to initialise
    // visited for the node and call
    // DFS function for a given vertex x.
    static void DFSCall(int x, int y, int n,
                        List stack)
    {
       
        // visited array
        bool []vis = new bool[n + 1];
        Array.Fill(vis, false);
       
        // memset(vis, false, sizeof(vis))
       
        // DFS function call
        DFS(vis, x, y, stack);
    }
     
  // Driver code
    public static void Main(string[] args)
    {
        for(int i = 0; i < 100; i++)
        {
            v.Add(new List());
        }
     
        int n = 10;
        List stack = new List();
           
        // Vertex numbers should be from 1 to 9.
        addEdge(1, 2);
        addEdge(1, 3);
        addEdge(2, 4);
        addEdge(2, 5);
        addEdge(2, 6);
        addEdge(3, 7);
        addEdge(3, 8);
        addEdge(3, 9);
           
        // Function Call
        DFSCall(4, 8, n, stack);
    }
}
 
// This code is contributed by rutvik_56


C++
// C++ implementation for the above approach
#include 
using namespace std;
 
// An utility function to add an edge in the tree
void addEdge(vector adj[], int x,
             int y)
{
    adj[x].push_back(y);
    adj[y].push_back(x);
}
 
// running dfs to find level and parent of every node
void dfs(vector adj[], int node, int l,
            int p, int lvl[], int par[])
{
   lvl[node] = l;
   par[node] = p;
   
   for(int child : adj[node])
   {
      if(child != p)
        dfs(adj, child, l+1, node, lvl, par);
   }
}
 
int LCA(int a, int b, int par[], int lvl[])
{ 
   // if node a is at deeper level than
   // node b
   if(lvl[a] > lvl[b])
    swap(a, b);
    
   // finding the difference in levels
   // of node a and b
   int diff = lvl[b] - lvl[a];
    
   // moving b to the level of a
   while(diff != 0)
   {
      b = par[b];
      diff--;
   }
    
   // means we have found the LCA
   if(a == b)
    return a;
    
   // finding the LCA
   while(a != b)
    a=par[a], b=par[b];
 
   return a;
}
 
void printPath(vector adj[], int a, int b, int n)
{
    // stores level of every node
    int lvl[n+1];
   
    // stores parent of every node
    int par[n+1];
   
    // running dfs to find parent and level
    // of every node in the tree
    dfs(adj, 1, 0, -1, lvl, par);
     
    // finding the lowest common ancestor
    // of the nodes a and b
    int lca = LCA(a, b, par, lvl);
   
    // stores path between nodes a and b
    vector path;
     
    // traversing the path from a to lca
    while(a != lca)
      path.push_back(a), a = par[a];
 
    path.push_back(a);
 
    vector temp;
     
    // traversing the path from b to lca
    while(b != lca)
      temp.push_back(b), b=par[b];
     
    // reversing the path to get actual path
    reverse(temp.begin(), temp.end());
   
    for(int x : temp)
      path.push_back(x);
   
    // printing the path
    for(int i = 0; i < path.size() - 1; i++)
      cout << path[i] << " -> ";
   
    cout << path[path.size() - 1] << endl;
}
 
// Driver Code
int main()
{  
  /*                          1
  
                        /            \
 
                     2                7
 
               /             \
 
             3                6
 
    /        |        \
 
  4          8          5
   
 */
    // number of nodes in the tree
    int n = 8;
     
    // adjacency list representation of the tree
    vector adj[n+1];
   
    addEdge(adj, 1, 2);
    addEdge(adj, 1, 7);
    addEdge(adj, 2, 3);
    addEdge(adj, 2, 6);
    addEdge(adj, 3, 4);
    addEdge(adj, 3, 8);
    addEdge(adj, 3, 5);
     
    // taking two input nodes
    // between which path is
    // to be printed
    int a = 4, b = 7;
   
    printPath(adj, a, b, n);
    
    return 0;
}


输出:
4 -> 2 -> 1 -> 3 -> 8

高效的方法:

在这种方法中,我们将使用最低共同祖先(LCA)的概念。

1.我们将使用DFS查找每个节点的级别和父级。

2.我们将找到两个给定节点的最低公共祖先(LCA)。

3.从第一个节点开始,我们将前往LCA并继续推动

路径向量中的中间节点。

4.然后,从第二个节点,我们将再次前往LCA,但这一次

我们将反转遇到的中间节点,然后将它们推入

我们的路径向量。

5.最后,打印路径矢量以获得两个节点之间的路径。

C++

// C++ implementation for the above approach
#include 
using namespace std;
 
// An utility function to add an edge in the tree
void addEdge(vector adj[], int x,
             int y)
{
    adj[x].push_back(y);
    adj[y].push_back(x);
}
 
// running dfs to find level and parent of every node
void dfs(vector adj[], int node, int l,
            int p, int lvl[], int par[])
{
   lvl[node] = l;
   par[node] = p;
   
   for(int child : adj[node])
   {
      if(child != p)
        dfs(adj, child, l+1, node, lvl, par);
   }
}
 
int LCA(int a, int b, int par[], int lvl[])
{ 
   // if node a is at deeper level than
   // node b
   if(lvl[a] > lvl[b])
    swap(a, b);
    
   // finding the difference in levels
   // of node a and b
   int diff = lvl[b] - lvl[a];
    
   // moving b to the level of a
   while(diff != 0)
   {
      b = par[b];
      diff--;
   }
    
   // means we have found the LCA
   if(a == b)
    return a;
    
   // finding the LCA
   while(a != b)
    a=par[a], b=par[b];
 
   return a;
}
 
void printPath(vector adj[], int a, int b, int n)
{
    // stores level of every node
    int lvl[n+1];
   
    // stores parent of every node
    int par[n+1];
   
    // running dfs to find parent and level
    // of every node in the tree
    dfs(adj, 1, 0, -1, lvl, par);
     
    // finding the lowest common ancestor
    // of the nodes a and b
    int lca = LCA(a, b, par, lvl);
   
    // stores path between nodes a and b
    vector path;
     
    // traversing the path from a to lca
    while(a != lca)
      path.push_back(a), a = par[a];
 
    path.push_back(a);
 
    vector temp;
     
    // traversing the path from b to lca
    while(b != lca)
      temp.push_back(b), b=par[b];
     
    // reversing the path to get actual path
    reverse(temp.begin(), temp.end());
   
    for(int x : temp)
      path.push_back(x);
   
    // printing the path
    for(int i = 0; i < path.size() - 1; i++)
      cout << path[i] << " -> ";
   
    cout << path[path.size() - 1] << endl;
}
 
// Driver Code
int main()
{  
  /*                          1
  
                        /            \
 
                     2                7
 
               /             \
 
             3                6
 
    /        |        \
 
  4          8          5
   
 */
    // number of nodes in the tree
    int n = 8;
     
    // adjacency list representation of the tree
    vector adj[n+1];
   
    addEdge(adj, 1, 2);
    addEdge(adj, 1, 7);
    addEdge(adj, 2, 3);
    addEdge(adj, 2, 6);
    addEdge(adj, 3, 4);
    addEdge(adj, 3, 8);
    addEdge(adj, 3, 5);
     
    // taking two input nodes
    // between which path is
    // to be printed
    int a = 4, b = 7;
   
    printPath(adj, a, b, n);
    
    return 0;
}
输出
4 -> 3 -> 2 -> 1 -> 7

时间复杂度: O(N)

空间复杂度: O(N)

如果您希望与行业专家一起参加现场课程,请参阅《 Geeks现场课程》和《 Geeks现场课程美国》。