Seleccione aleatoriamente un nodo de un árbol binario

Mi clase de árbol:

public class BT<E>{
   E value;
   BT<E> left, right;

   public BT(E value)
   {
      this.value=value;
   }   

   public BT (E value, BT left, BT right) 
   {
      this.value = value;
      this.left = left;
      this.right = right;
   }

¿Cómo haría para devolver un nodo aleatorio de un árbol después de haber generado un árbol? Sé la profundidad y la cantidad de nodos para cada árbol que genero.

Respuesta 1

Los algoritmos de Dennis y Jeroen son simples de implementar pero O(n). Creo que tengo un O(log n)algoritmo que es un poco más complicado.

Cada nodo necesita una oportunidad igual de ser seleccionado. Entonces, en algún árbol T, LN(T)sea ​​el número de nodos en el árbol izquierdo, RN(T)sea ​​el número de nodos en el árbol derecho y N(T)sea ​​el número de nodos totales, incluido este (así N(T) = 1 + LN(T) + RN(T)). Seleccione un número aleatorio Rde 0 to N(T) - 1. Si R == 0, devuelve este nodo. Si 1 <= R <= LT(N), repita este método en el subárbol izquierdo. De lo contrario, repita este método en el subárbol derecho.

Código no probado (suponiendo que BTtenga un .size()método que funcione O(1)):

public BT randomNode() {
    int r = new Random().nextInt(this.size());
    if (r == 0) {
        return this;
    } else if (left != null && 1 <= r && r <= left.size()) {
        return left.randomNode();
    } else {
        return right.randomNode();
    }
}

Y, por supuesto, puede hacer cosas como levantar new Random()el método, pero el algoritmo es el mismo.

Editar: se corrigió la excepción de puntero nulo cuando el subárbol izquierdo era nulo.

Respuesta: 2

Por lo tanto, use un método de Random Integer y devuelva un número entero entre 0 y el tamaño del árbol.

Luego, haga un primer recorrido de amplitud / profundidad en el árbol, con un contador, que devuelve el nodo cuando alcanza el entero aleatorio.

Random rand = new Random();
int randomNum = rand.nextInt(treesize);
int count = -1;
Node randNode;

public static void getRandomTraversal(Node root){

    count++;

    if(count == randomNum)
        randNode = root;

    if(root.leftChild != null)
        getRandomTraversal(root.leftChild);

    if(root.rightChild != null)
        getRandomTraversal(root.rightChild);
}

Alternativamente, podría eliminar count como global y agregarlo como argumento a la función recursiva. Aunque esto no es tan fácil con los árboles binarios cuando el árbol tiene más de un hijo.

Respuesta: 3
  1. Seleccione un número aleatorio ( new Random().nextInt(numberOfNodes))
  2. Camina por tu árbol como quieras (profundidad primero, anchura primero, postorder, inorder, preorder)
  3. Para cada nodo que visite, incremente un contador
  4. Si el valor del contador es igual al número elegido al azar, elija ese nodo
Respuesta: 4

Soy un principiante de Java y estoy teniendo problemas con una simple animación de swing que creé. La animación se retrasa cuando se ejecuta a menos que ocurra algo más, como el movimiento del mouse o una tecla presionada. ...

Estamos utilizando Spring Batch para algunas operaciones de back-end. Necesitamos conocer la forma auténtica de 1) ¿Cómo cerrar con gracia un proceso por lotes de primavera en ejecución? 2) Cómo asegurarse de que un lote de primavera en particular ...

Necesito sumar todos los bytes de datos en ByteArrayOutputStream, agregando +1 al resultado y tomando los 2 bytes menos significativos. int checkum = 1; para (byte b: byteOutputStream.toByteArray ()) {...

¿Alguien sabe por qué Java 7 no recopila la generación permanente de la aplicación, lo que resulta en java.lang.OutOfMemoryError: PermGen, mientras que Java 5 recopila la generación permanente y la aplicación funciona bien? La aplicación hace ...