Necesito encontrar el k-ésimo elemento más pequeño en el árbol de búsqueda binaria sin usar ninguna variable estática / global. ¿Cómo lograrlo de manera eficiente? La solución que tengo en mente es hacer la operación en O (n), el peor de los casos ya que planeo hacer un recorrido en orden de todo el árbol. Pero en el fondo siento que no estoy usando la propiedad BST aquí. ¿Es correcta mi solución supuesta o hay una mejor disponible?
algorithm
data-structures
binary-tree
binary-search
fanfarrón
fuente
fuente
Respuestas:
Aquí hay solo un resumen de la idea:
En una BST, el subárbol izquierdo del nodo
T
contiene solo elementos más pequeños que el valor almacenado enT
. Sik
es menor que el número de elementos del subárbol izquierdo, elk
elemento más pequeño debe pertenecer al subárbol izquierdo. De lo contrario, sik
es más grande, entonces elk
elemento más pequeño está en el subárbol derecho.Podemos aumentar la BST para que cada nodo almacene el número de elementos en su subárbol izquierdo (suponga que el subárbol izquierdo de un nodo dado incluye ese nodo). Con esta información, es simple recorrer el árbol preguntando repetidamente por el número de elementos en el subárbol izquierdo, para decidir si hacer recursividad en el subárbol izquierdo o derecho.
Ahora, suponga que estamos en el nodo T:
T
.k
más pequeño. Entonces, reducimos el problema a encontrar elk - num_elements(left subtree of T)
elemento más pequeño del subárbol derecho.k
th más pequeño está en algún lugar del subárbol izquierdo, por lo que reducimos el problema a encontrar elk
elemento más pequeño en el subárbol izquierdo.Análisis de complejidad:
Esto lleva
O(depth of node)
tiempo, que esO(log n)
en el peor de los casos en una BST equilibrada, oO(log n)
en promedio para una BST aleatoria.Un BST requiere
O(n)
almacenamiento y se necesita otroO(n)
para almacenar la información sobre la cantidad de elementos. Todas las operaciones de BST tomanO(depth of node)
tiempo y se necesitaO(depth of node)
más tiempo para mantener la información de "número de elementos" para la inserción, eliminación o rotación de nodos. Por lo tanto, almacenar información sobre el número de elementos en el subárbol izquierdo mantiene la complejidad espacial y temporal de una BST.fuente
Una solución más sencilla sería hacer un recorrido en orden y realizar un seguimiento del elemento que se va a imprimir actualmente (sin imprimirlo). Cuando llegamos a k, imprimimos el elemento y saltamos el resto del recorrido del árbol.
fuente
esta es mi implementación en C # basada en el algoritmo anterior, solo pensé en publicarlo para que la gente pueda entender mejor que funciona para mí
gracias IVlad
fuente
Una solución más sencilla sería realizar un recorrido en orden y realizar un seguimiento del elemento que se va a imprimir actualmente con un contador k. Cuando llegamos a k, imprime el elemento. El tiempo de ejecución es O (n). Recuerde que el tipo de retorno de la función no se puede anular, debe devolver su valor actualizado de k después de cada llamada recursiva. Una mejor solución para esto sería una BST aumentada con un valor de posición ordenado en cada nodo.
fuente
// agrega una versión de Java sin recursividad
fuente
Puede usar un recorrido de orden iterativo: http://en.wikipedia.org/wiki/Tree_traversal#Iterative_Traversal con una simple verificación del elemento kth después de sacar un nodo de la pila.
fuente
Dado solo un árbol de búsqueda binario simple, todo lo que puede hacer es comenzar desde el más pequeño y recorrer hacia arriba para encontrar el nodo correcto.
Si va a hacer esto con mucha frecuencia, puede agregar un atributo a cada nodo que indique cuántos nodos hay en su subárbol izquierdo. Con eso, puede descender el árbol directamente al nodo correcto.
fuente
Paseo recursivo en orden con contador
La idea es similar a la solución @prasadvk, pero tiene algunas deficiencias (consulte las notas a continuación), por lo que estoy publicando esto como una respuesta separada.
Notas (y diferencias con la solución de @ prasadvk):
if( counter == k )
La prueba se requiere en tres lugares: (a) después del subárbol izquierdo, (b) después de la raíz y (c) después del subárbol derecho. Esto es para asegurar que se detecte el k-ésimo elemento para todas las ubicaciones , es decir, independientemente del subárbol en el que se encuentre.if( result == -1 )
prueba requerida para garantizar que solo se imprima el elemento del resultado ; de lo contrario, se imprimen todos los elementos desde el k-ésimo más pequeño hasta la raíz.fuente
O(k + d)
dónded
está la profundidad máxima del árbol. Por lo tanto, usa una variable globalcounter
pero es ilegal para esta pregunta.Para un árbol de búsqueda no equilibrado, se necesita O (n) .
Para un árbol de búsqueda equilibrado , se necesita O (k + log n) en el peor de los casos, pero solo O (k) en el sentido Amortizado .
Tener y administrar el número entero adicional para cada nodo: el tamaño del subárbol proporciona complejidad de tiempo O (log n) . Este árbol de búsqueda equilibrado se suele llamar RankTree.
En general, hay soluciones (basadas no en árbol).
Saludos.
fuente
Esto funciona bien: estado: es la matriz que contiene si se encuentra el elemento. k: es el k-ésimo elemento que se encuentra. count: realiza un seguimiento del número de nodos atravesados durante el recorrido del árbol.
fuente
Si bien esta definitivamente no es la solución óptima al problema, es otra solución potencial que pensé que algunas personas podrían encontrar interesante:
fuente
firma:
llamar como:
definición:
fuente
Bueno, aquí están mis 2 centavos ...
fuente
Esto es lo que pensé y funciona. Se ejecutará en o (log n)
fuente
Bueno, simplemente podemos usar el recorrido en orden y empujar el elemento visitado a una pila. pop k varias veces, para obtener la respuesta.
también podemos detenernos después de k elementos
fuente
Solución para caja BST completa: -
fuente
El kernel de Linux tiene una excelente estructura de datos de árbol rojo-negro aumentada que admite operaciones basadas en rangos en O (log n) en linux / lib / rbtree.c.
También se puede encontrar un puerto Java muy burdo en http://code.google.com/p/refolding/source/browse/trunk/core/src/main/java/it/unibo/refolding/alg/RbTree.java , junto con RbRoot.java y RbNode.java. El enésimo elemento se puede obtener llamando a RbNode.nth (nodo RbNode, int n), pasando la raíz del árbol.
fuente
Aquí hay una versión concisa en C # que devuelve el k-ésimo elemento más pequeño, pero requiere pasar k como un argumento de referencia (es el mismo enfoque que @prasadvk):
Es O (log n) para encontrar el nodo más pequeño, y luego O (k) para atravesar el k-ésimo nodo, por lo que es O (k + log n).
fuente
http://www.geeksforgeeks.org/archives/10379
esta es la respuesta exacta a esta pregunta: -
1.utilizando el recorrido en orden en el tiempo O (n) 2.usando el árbol aumentado en el tiempo k + log n
fuente
No pude encontrar un algoritmo mejor ... así que decidí escribir uno :) Corrígeme si esto está mal.
}
fuente
Aquí está el código de Java,
max (raíz de nodo, int k) - para encontrar el kth más grande
min (raíz de nodo, int k) - para encontrar kth más pequeño
fuente
esto también funcionaría. simplemente llame a la función con maxNode en el árbol
def k_largest (self, node, k): if k <0: return None
if k == 0: return node else: k - = 1 return self.k_largest (self.predecessor (node), k)
fuente
Creo que esto es mejor que la respuesta aceptada porque no necesita modificar el nodo del árbol original para almacenar el número de sus nodos secundarios.
Solo necesitamos usar el recorrido en orden para contar el nodo más pequeño de izquierda a derecha, dejar de buscar una vez que el recuento sea igual a K.
fuente
El mejor enfoque ya está ahí, pero me gustaría agregar un código simple para eso
}
fuente
Usar la clase de resultado auxiliar para rastrear si se encuentra el nodo y el k actual.
fuente
Complejidad del tiempo de la solución de Python: O (n) Complejidad del espacio: O (1)
La idea es utilizar Morris Inorder Traversal
fuente
Escribí una función ordenada para calcular el k-ésimo elemento más pequeño. Utilizo el recorrido en orden y se detiene cuando alcanza el k-ésimo elemento más pequeño.
fuente
fuente
fuente
}
fuente