📜  从树中选择一个随机节点的概率相等

📅  最后修改于: 2021-04-27 05:39:05             🧑  作者: Mango

给定具有子节点的二叉树,返回一个随机节点,其选择树中任何节点的可能性相同。

考虑根为1的给定树。

10
    /    \
   20     30
  / \      / \
40   50   60   70

例子:

Input : getRandom(root);
Output : A Random Node From Tree : 3

Input : getRandom(root);
Output : A Random Node From Tree : 2

一个简单的解决方案是将树的有序遍历存储在数组中。设节点数为n。为了获得一个随机节点,我们生成一个从0到n-1的随机数,将该数字用作数组中的索引,然后返回index处的值。

一种解决方案是修改树结构。我们在每个节点中存储孩子数。考虑上面的树。我们在这里也使用有序遍历。我们生成一个小于或等于节点数的数字。我们遍历树并转到该索引处的节点。我们使用计数来快速到达所需的节点。通过计数,我们到达O(h)时间,其中h是树的高度。

10,6
    /      \
  20,2       30,2
 /   \       /   \
40,0 50,0  60,0  70,0
The first value is node and second
value is count of children.

我们开始遍历这棵树,在每个节点上,我们都转到左子树或右子树,考虑子代数是否小于随机数。

如果随机数小于孩子数,则我们向左走,否则我们向右走。

下面是上述算法的实现。 getElements将返回root的子代计数,InsertChildrenCount将子代数据插入每个节点,RandomNode在实用程序函数RandomNodeUtil的帮助下返回随机节点。

C++
// CPP program to Select a Random Node from a tree
#include 
using namespace std;
  
struct Node {
    int data;
    int children;
    Node *left, *right;
};
  
Node* newNode(int data)
{
    Node *temp = new Node;
    temp->data = data;
    temp->left = temp->right = NULL;
    temp->children = 0;
    return temp;
}
  
// This is used to fill children counts.
int getElements(Node* root)
{
    if (!root)
        return 0;
    return getElements(root->left) +
          getElements(root->right) + 1;
}
  
// Inserts Children count for each node
void insertChildrenCount(Node*& root)
{
    if (!root)
        return;
  
    root->children = getElements(root) - 1;
    insertChildrenCount(root->left);
    insertChildrenCount(root->right);
}
  
// returns number of children for root
int children(Node* root)
{
    if (!root)
        return 0;
    return root->children + 1;
}
  
// Helper Function to return a random node
int randomNodeUtil(Node* root, int count)
{
    if (!root)
        return 0;
  
    if (count == children(root->left))
        return root->data;
  
    if (count < children(root->left))
        return randomNodeUtil(root->left, count);
  
    return randomNodeUtil(root->right,
              count - children(root->left) - 1);
}
  
// Returns Random node
int randomNode(Node* root)
{
    srand(time(0));
  
    int count = rand() % (root->children + 1);
    return randomNodeUtil(root, count);
}
  
int main()
{
    // Creating Above Tree
    Node* root = newNode(10);
    root->left = newNode(20);
    root->right = newNode(30);
    root->left->right = newNode(40);
    root->left->right = newNode(50);
    root->right->left = newNode(60);
    root->right->right = newNode(70);
  
    insertChildrenCount(root);
  
    cout << "A Random Node From Tree : "
         << randomNode(root) << endl;
  
    return 0;
}


Java
// Java program to Select a Random Node from a tree
import java.util.*;
import java.lang.*;
import java.io.*;
  
class GFG
{
static class Node 
{
    int data;
    int children;
    Node left, right;
}
  
static Node newNode(int data)
{
    Node temp = new Node();
    temp.data = data;
    temp.left = temp.right = null;
    temp.children = 0;
    return temp;
}
  
// This is used to fill children counts.
static int getElements(Node root)
{
    if (root == null)
        return 0;
    return getElements(root.left) +
        getElements(root.right) + 1;
}
  
// Inserts Children count for each node
static Node insertChildrenCount(Node root)
{
    if (root == null)
        return null;
  
    root.children = getElements(root) - 1;
    root.left = insertChildrenCount(root.left);
    root.right = insertChildrenCount(root.right);
    return root;
}
  
// returns number of children for root
static int children(Node root)
{
    if (root == null)
        return 0;
    return root.children + 1;
}
  
// Helper Function to return a random node
static int randomNodeUtil(Node root, int count)
{
    if (root == null)
        return 0;
  
    if (count == children(root.left))
        return root.data;
  
    if (count < children(root.left))
        return randomNodeUtil(root.left, count);
  
    return randomNodeUtil(root.right,
         count - children(root.left) - 1);
}
  
// Returns Random node
static int randomNode(Node root)
{
  
    int count = (int) Math.random() * 
                     (root.children + 1);
    return randomNodeUtil(root, count);
}
  
// Driver Code
public static void main(String args[])
{
      
    // Creating Above Tree
    Node root = newNode(10);
    root.left = newNode(20);
    root.right = newNode(30);
    root.left.right = newNode(40);
    root.left.right = newNode(50);
    root.right.left = newNode(60);
    root.right.right = newNode(70);
  
    insertChildrenCount(root);
  
    System.out.println( "A Random Node From Tree : " + 
                                    randomNode(root));
}
}
  
// This code is contributed by Arnab Kundu


Python3
# Python3 program to Select a 
# Random Node from a tree
from random import randint
  
class Node:
      
    def __init__(self, data):
        self.data = data
        self.children = 0
        self.left = None
        self.right = None
  
# This is used to fill children counts. 
def getElements(root): 
  
    if root == None: 
        return 0
          
    return (getElements(root.left) +
            getElements(root.right) + 1) 
  
# Inserts Children count for each node 
def insertChildrenCount(root): 
  
    if root == None:
        return
  
    root.children = getElements(root) - 1
    insertChildrenCount(root.left) 
    insertChildrenCount(root.right) 
  
# Returns number of children for root 
def children(root):
  
    if root == None: 
        return 0
    return root.children + 1
  
# Helper Function to return a random node 
def randomNodeUtil(root, count): 
  
    if root == None: 
        return 0
  
    if count == children(root.left): 
        return root.data 
  
    if count < children(root.left): 
        return randomNodeUtil(root.left, count) 
  
    return randomNodeUtil(root.right, 
            count - children(root.left) - 1) 
  
# Returns Random node 
def randomNode(root): 
  
    count = randint(0, root.children) 
    return randomNodeUtil(root, count)
  
# Driver Code
if __name__ == "__main__":
  
    # Creating Above Tree 
    root = Node(10) 
    root.left = Node(20) 
    root.right = Node(30) 
    root.left.right = Node(40) 
    root.left.right = Node(50) 
    root.right.left = Node(60) 
    root.right.right = Node(70) 
  
    insertChildrenCount(root) 
  
    print("A Random Node From Tree :",
           randomNode(root))
  
# This code is contributed by Rituraj Jain


C#
// C# program to Select a Random Node from a tree
using System;
  
class GFG
{
      
class Node 
{
    public int data;
    public int children;
    public Node left, right;
}
  
static Node newNode(int data)
{
    Node temp = new Node();
    temp.data = data;
    temp.left = temp.right = null;
    temp.children = 0;
    return temp;
}
  
// This is used to fill children counts.
static int getElements(Node root)
{
    if (root == null)
        return 0;
    return getElements(root.left) +
        getElements(root.right) + 1;
}
  
// Inserts Children count for each node
static Node insertChildrenCount(Node root)
{
    if (root == null)
        return null;
  
    root.children = getElements(root) - 1;
    root.left = insertChildrenCount(root.left);
    root.right = insertChildrenCount(root.right);
    return root;
}
  
// returns number of children for root
static int children(Node root)
{
    if (root == null)
        return 0;
    return root.children + 1;
}
  
// Helper Function to return a random node
static int randomNodeUtil(Node root, int count)
{
    if (root == null)
        return 0;
  
    if (count == children(root.left))
        return root.data;
  
    if (count < children(root.left))
        return randomNodeUtil(root.left, count);
  
    return randomNodeUtil(root.right,
        count - children(root.left) - 1);
}
  
// Returns Random node
static int randomNode(Node root)
{
  
    int count = (int) new Random().Next(0, root.children + 1);
    return randomNodeUtil(root, count);
}
  
// Driver Code
public static void Main(String []args)
{
      
    // Creating Above Tree
    Node root = newNode(10);
    root.left = newNode(20);
    root.right = newNode(30);
    root.left.right = newNode(40);
    root.left.right = newNode(50);
    root.right.left = newNode(60);
    root.right.right = newNode(70);
  
    insertChildrenCount(root);
  
    Console.Write( "A Random Node From Tree : " + 
                                    randomNode(root));
}
}
  
// This code is contributed by Arnab Kundu


randomNode的时间复杂度为O(h),其中h是树的高度。请注意,我们一次或向右移动或向左移动。