Download [ editar ] árboles binarios de búsqueda óptima

Document related concepts

Árbol binario de búsqueda wikipedia , lookup

Árbol binario wikipedia , lookup

Recorrido de árboles wikipedia , lookup

Árbol biselado wikipedia , lookup

Treap wikipedia , lookup

Transcript
Notice something different? We've made a few improvements to Wikipedia. Learn
more!
Árbol binario de búsqueda
De Wikipedia, la enciclopedia libre
Saltar a navegación , búsqueda
Un árbol de búsqueda binaria de tamaño 9 y la profundidad de 3, con raíz y hojas de 8
1, 4, 7 y 13
En ciencias de la computación , un árbol binario de búsqueda (BST) o solicitarse en
árbol binario es un nodo basado en árbol binario estructura de datos que tiene las
siguientes propiedades: [1]



La izquierda subárbol de un nodo contiene sólo los nodos con claves de menos
de nodo tecla.
El subárbol derecho de un nodo contiene sólo los nodos con claves de mayor o
igual a la clave del nodo.
Tanto el subárboles izquierdo y derecho también debe ser árboles binarios de
búsqueda.
De las propiedades anteriores la consecuencia natural es que:

Cada nodo (elemento del árbol) tiene una clave distinta.
En general, la información representada por cada nodo es un registro en lugar de un
único elemento de datos. Sin embargo, para la secuenciación de los propósitos, los
nodos son comparados de acuerdo a sus teclas en lugar de cualquier parte de sus
registros asociados.
La principal ventaja de los árboles de búsqueda binaria sobre otras estructuras de datos
es que los relacionados con algoritmos de clasificación y algoritmos de búsqueda como
el recorrido en orden puede ser muy eficiente.
árboles binarios de búsqueda son fundamentales una estructura de datos utilizada para
construir estructuras de datos más abstractos, tales como conjuntos , conjuntos múltiples
, y arrays asociativos .
Contenido
[hide]






1 Operaciones
o
1,1 búsqueda
o
1.2 Inserción
o
1.3 Supresión
o
1.4 Traversal
o
Ordenar 1,5
2 Tipos
o
2.1 Comportamiento comparaciones
o
2,2 árboles de búsqueda binaria óptima
3 Véase también
4 Referencias
5 Véase también
6 Enlaces externos
[ editar ] Operaciones
Las operaciones en un árbol binario requieren comparaciones entre los nodos. Estas
comparaciones se hacen con llamadas a un comparador , que es una subrutina que
calcula el total del pedido (orden lineal) en cualquiera de los dos valores. Esta
comparación puede ser explícita o implícitamente definido, según el idioma en que se
aplica el BST.
[ editar ] Búsqueda
Buscando un árbol binario de un valor específico puede ser un recursivo o iterativo
proceso. Esta explicación abarca un método iterativo.
Comenzamos examinando el nodo raíz . Si el árbol es nulo, el valor que está buscando
no existe en el árbol. De lo contrario, si el valor es igual a la raíz, la búsqueda tiene
éxito. Si el valor es inferior a la raíz, busque en el subárbol izquierdo. Del mismo
modo, si ésta es superior a la raíz, busque en el subárbol derecho. Este proceso se repite
hasta que el valor se encuentra o el subárbol indicado es nulo. Si el valor buscado no se
encuentra ante un subárbol nula es alcanzado, entonces el tema no debe estar presente
en el árbol.
Aquí está el algoritmo de búsqueda en el lenguaje de programación Python :
# 'Nodo' se refiere a la relación padre-nodo en este caso
def search_binary_tree (nodo, clave):
si el nodo es None:
Ninguno de retorno que no se encuentra la tecla #
si el nodo <clave. clave:
search_binary_tree retorno (node. leftChild, clave)
elif nodo> clave. clave:
search_binary_tree retorno (node. rightChild, clave)
else: # clave es igual al nodo clave
nodo de retorno. valor # encontrados clave
... O equivalente Haskell :
searchBinaryTree NullNode _ = Nothing
searchBinaryTree clave (nodeKey nodeValue Nodo (leftChild,
rightChild)) =
caso comparar nodeKey clave de
LT - searchBinaryTree> Tecla leftChild
GT - searchBinaryTree> Tecla rightChild
EQ -> Solamente nodeValue
Esta operación requiere O (log n) en el caso promedio, pero necesita O (n) el tiempo en
el peor de los casos, cuando el árbol se parece a un desequilibrio lista enlazada ( árbol
degenerado ).
Suponiendo que BinarySearchTree es una clase con una función miembro "de
búsqueda (int)" y un puntero al nodo raíz, el algoritmo también es fácil de implementar
en términos de un enfoque iterativo. El algoritmo entra en un bucle, y decide si la rama
izquierda o derecha según el valor del nodo en cada nodo primario.
bool BinarySearchTree:: buscar (int val)
(
Nodo * siguiente = esto - root> ();
while (siguiente! = 0)
(
if (val == siguiente - valor> ())
(
return true;
)
else if (val <Los - valor> ())
(
next = siguiente - a la izquierda> ();
)
else if (val siguiente> - valor> ())
(
next = siguiente -> derecha ();
)
)
/ / No encontrado
return false;
)
Aquí está el algoritmo de búsqueda en el lenguaje de programación Java :
búsqueda booleana pública (nodo TreeNode, los datos int) (
if (nodo == null) (
return false;
)
if (node. getData () == data) (
return true;
) Else if (datos <nodo. GetData ()) (
/ / Datos deben estar en subárbol izquierdo
búsqueda de retorno (node. getLeft (), datos);
Else ()
/ / Datos deben estar en subárbol derecho
búsqueda de retorno (node. GetRight (), datos);
)
)
[ editar ] Inserción
La inserción comienza como una búsqueda comenzaría, si la raíz no es igual al valor,
buscamos la izquierda o derecha subárboles como antes. Con el tiempo, llegaremos a
un nodo externo y agregue el valor como su hijo derecho o izquierdo, dependiendo del
valor del nodo. En otras palabras, se examinan la raíz y de forma recursiva insertar el
nuevo nodo al subárbol izquierdo si el nuevo valor es inferior a la raíz, o el subárbol de
la derecha si el nuevo valor es mayor o igual a la raíz.
Así es como una típica búsqueda de la inserción árbol binario puede ser realizado en C
++:
/ * Inserta el nodo apuntado por "nodo_nuevo" en el subárbol con
raíz en "TreeNode" * /
insertarNodo vacío (* Nodo y TreeNode Nodo * nodo_nuevo)
(
if (TreeNode == NULL)
TreeNode = nodo_nuevo;
else if (nodo_nuevo - clave TreeNode <> -> Clave)
InsertarNodo (TreeNode - izquierda>, nodo_nuevo);
más
InsertarNodo (TreeNode -> derecha, nodo_nuevo);
)
Lo anterior "destructiva" variante de procedimiento modifica el árbol en su lugar.
Utiliza solamente el espacio constante, pero la versión anterior del árbol se pierde. Por
otra parte, como en el siguiente Python ejemplo, podemos reconstruir todos los
ancestros del nodo insertado, cualquier referencia a la raíz del árbol original sigue
siendo válida, haciendo que el árbol de una estructura de datos persistente :
def binary_tree_insert (nodo, clave, valor):
si el nodo es None:
volver TreeNode (Ninguno, clave, valor, ninguno)
si la clave == nodo. clave:
TreeNode retorno (node. izquierda, la tecla, el valor, el
nodo. Derecha)
si el nodo <clave. clave:
volver TreeNode (binary_tree_insert (node. izquierda, clave,
valor), el nodo. clave, nodo. valor, nodo. derecha)
otra cosa:
TreeNode retorno (node. izquierda, nodo. Clave, nodo. Valor,
binary_tree_insert (node. derecho, clave, valor))
La parte que se vuelve a generar usos Θ (log n) de espacio en el caso promedio y Ω (n)
en el peor de los casos (véase la notación-O ).
En cualquier versión, esta operación requiere un tiempo proporcional a la altura del
árbol en el peor de los casos, que es O (log n) en el caso promedio de todos los árboles,
pero (n Ω) tiempo en el peor de los casos.
Otra manera de explicar la inserción es que para insertar un nuevo nodo en el árbol, su
valor se compara primero con el valor de la raíz. Si su valor es inferior a la raíz, que se
compara con el valor del hijo izquierdo de la raíz. Si su valor es mayor, se la compara
con el hijo derecho de la raíz. Este proceso continúa hasta que el nuevo nodo se
compara con un nodo hoja, y luego se añade como derecho de este nodo o un niño a la
izquierda, dependiendo de su valor.
Hay otras maneras de insertar nodos en un árbol binario, pero esta es la única manera
de insertar nodos en las hojas y, al mismo tiempo preservar la estructura de BST.
Aquí hay un enfoque iterativo para la inserción en un árbol de búsqueda binaria en el
Lenguaje de Programación Java :
public void insertar (datos int) (
if (raiz == null) (
root = TreeNode nueva (datos, null, null);
Else ()
TreeNode actual root =;
while (actual! = null) (
if (datos <actual. getData ()) (
/ / Inserto la izquierda
if (current. getLeft () == null) (
actual. setLeft (nuevo TreeNode
(datos, null, null));
de retorno;
Else ()
actual = actual. getLeft ();
)
Else ()
/ / Inserto la derecha
if (current. GetRight () == null) (
actual. setRight (nuevo
TreeNode (datos, null, null));
de retorno;
Else ()
actual = actual. GetRight ();
)
)
)
)
)
A continuación se muestra un enfoque recursivo al método de inserción. Como los
punteros no están disponibles en Java tenemos que devolver un puntero nuevo nodo a la
persona que llama como se indica por la línea final en el método.
pública insertar TreeNode (nodo TreeNode, los datos int) (
if (nodo == null) (
= nodo TreeNode nueva (datos, null, null);
Else ()
if (datos <nodo. getData ()) (
/ / Inserto la izquierda
nodo. izquierda = inserción (node. getLeft (),
datos);
Else ()
/ / Inserto la derecha
nodo. derecha = inserción (node. GetRight (),
datos);
)
)
volver nodo;
)
[ editar ] Supresión
Hay tres posibles casos a considerar:



Eliminación de una hoja (nodo sin hijos): Cómo eliminar una hoja es fácil, ya
que simplemente puede eliminarlo del árbol.
Eliminar un nodo con un hijo: Eliminarlo y sustituirlo por su hijo.
Eliminar un nodo con dos hijos: Llame al nodo que se borró "N". No elimine
N. En su lugar, elegir entre su nodo en el sucesor de orden o su nodo antecesor
en orden, "R". Vuelva a colocar el valor de N con el valor de R, a continuación,
elimine R. (Nota: R se tiene hasta un niño.)
Al igual que con todos los árboles binarios, en orden sucesor un nodo es el hijo más a
la izquierda de su subárbol derecho, y en orden un predecesor del nodo es el hijo más a
la derecha de su subárbol izquierdo. En cualquier caso, este nodo tiene cero o un niño.
Eliminar de acuerdo con uno de los dos casos más sencillos anteriores.
El uso constante de la orden o el sucesor en orden antecesor en cada instancia del caso
de dos niños-puede conducir a un desequilibrio de árboles, por lo que añadimos una
buena implementaciones inconsistencia de esta selección.
Tiempo de análisis: Aunque esta operación no siempre recorrer el árbol hasta una hoja,
esto es siempre una posibilidad, por lo que en el peor de los casos se requiere un tiempo
proporcional a la altura del árbol. No requiere más aún cuando el nodo tiene dos hijos,
dado que todavía sigue un camino único y no visita ningún nodo dos veces.
Este es el código en Python:
def findMin (self):
'''
Busca el elemento más pequeño que es un hijo de la libre * *
'''
current_node = auto
mientras current_node. left_child:
current_node = current_node. left_child
volver current_node
def replace_node_in_parent (self, = Ninguno new_value):
'''
Elimina la referencia a * * * * yo de self.parent y lo reemplaza
con * new_value *.
'''
si trabaja por cuenta propia ==. padres. left_child:
uno mismo. padres. left_child = new_value
otra cosa:
uno mismo. padres. right_child = new_value
si new_value:
new_value. padres = yo. padres
def binary_tree_delete (self, clave):
si <clave auto. clave:
uno mismo. left_child. binary_tree_delete (clave)
elif clave auto>. clave:
uno mismo. right_child. binary_tree_delete (clave)
else: # eliminar la clave aquí
si uno mismo. left_child y yo. right_child: # si ambos la
presencia de niños
# Obtiene el más pequeño nodo que es más grande que uno
mismo * *
sucesor = yo. right_child. findMin ()
key = sucesor. auto. clave
# * * Si el sucesor tiene un hijo, que se sustituya por
# En este momento, sólo puede tener un right_child * *
# Si no tiene hijos, * * right_child será "Ninguno"
sucesor. replace_node_in_parent (successor. right_child)
elif auto. left_child o por cuenta propia. right_child: # si
el nodo tiene un solo hijo
si uno mismo. left_child:
uno mismo. replace_node_in_parent (auto. left_child)
otra cosa:
uno mismo. replace_node_in_parent (auto. right_child)
else: # este nodo no tiene hijos
uno mismo. replace_node_in_parent (Ninguno)
[ editar ] Recorrido
Artículo principal: recorrido de árbol
Una vez que el árbol de búsqueda binaria se ha creado, sus elementos pueden ser
recuperados en orden de forma recursiva que atraviesa el subárbol izquierdo del nodo
raíz, el acceso a la misma nodo, a continuación, recorrer recursivamente el subárbol
derecho del nodo, continuando este patrón con cada nodo El árbol ya que es visitada de
forma recursiva. Al igual que con todos los árboles binarios, se puede realizar un
recorrido pre-orden o una orden de recorrido de post , pero tampoco son susceptibles de
ser utilizadas para los árboles binarios de búsqueda.
El código en el orden de recorrido en Python es la siguiente. Se ha previsto de
devolución de llamada para cada nodo en el árbol.
def traverse_binary_tree (nodo, de devolución de llamada):
si el nodo es None:
volver
traverse_binary_tree (node. leftChild, devolución de llamada)
de devolución de llamada (node. valor)
traverse_binary_tree (node. rightChild, devolución de llamada)
Traversal requiere Ω (n) el tiempo, ya que debe visitar cada nodo. Este algoritmo es O
(n), por lo que es asintóticamente óptima .
[ editar ] Ordenar
Un árbol de búsqueda binaria se puede utilizar para poner en práctica un sencillo pero
eficiente algoritmo de ordenación . Al igual que heapsort , insertamos todos los valores
que desea ordenar en nuevos ordenó la estructura de datos, en este caso un árbol de
búsqueda binaria, y luego recorrer en ella el orden, la construcción de nuestro resultado:
def build_binary_tree (valores):
árbol = Ninguno
para v en valores:
= árbol binary_tree_insert (árbol, v)
retorno de árboles
get_inorder_traversal def (root):
'''
Devuelve una lista que contiene todos los valores en el árbol,
comenzando en la raíz * *.
Recorre el árbol en orden (leftChild, raíz, rightChild).
'''
resultado = []
traverse_binary_tree (raíz, elemento lambda: resultado. append
(elemento))
return resultado
El caso peor tiempo de build_binary_tree es Θ (n 2)-Si le das una lista ordenada de
valores, se los encadena en una lista enlazada sin subárboles izquierdo. Por ejemplo,
traverse_binary_tree([1, 2, 3, 4, 5]) se obtiene el árbol (1 (2 (3 (4
(5))))) .
Hay varios planes para superar esta falencia con simples árboles binarios, el más
común es el de equilibrio de árbol binario de búsqueda auto . Si este mismo
procedimiento se realiza mediante un árbol, el peor de los casos el tiempo total es O (n
log n), que es asintóticamente óptima para un tipo de comparación . En la práctica, los
pobres caché de rendimiento y agregó sobrecarga en el tiempo y espacio para una base
tipo de árboles (en particular para el nodo de asignación ) que sea asintóticamente
óptima a otros tipos inferiores, tales como heapsort para ordenar la lista estática. Por
otra parte, es uno de los métodos más eficientes de selección adicionales, agregar
elementos a una lista con el tiempo, manteniendo la lista ordenada en todo momento.
[ editar ] Tipos
Hay muchos tipos de árboles binarios de búsqueda. AVL árboles y los árboles rojonegro son las formas de auto-equilibrio de los árboles binarios de búsqueda . Un árbol
de angulación es un árbol de búsqueda binaria que se mueve automáticamente visitada
con frecuencia los elementos más cerca de la raíz. En un treap ("árbol montón "), cada
nodo también tiene una prioridad y el nodo primario tiene mayor prioridad que a sus
hijos.
Otros dos títulos que describen los árboles de búsqueda binaria es que de un árbol
completo y degenerada.
Un árbol completo es un árbol con n niveles, donde para cada nivel d <= n - 1, el
número de nodos existentes a nivel d es igual a 2 d. Esto significa que todos los nodos
posibles existen en estos niveles. Un requisito adicional para que un árbol binario
completo es que para n º nivel, mientras que cada nodo no tiene que existir, los nodos
que existan deben llenar de izquierda a derecha.
Un árbol degenerado es un árbol donde cada nodo primario, sólo hay un nodo
secundario asociado. Lo que esto significa es que en una medición del rendimiento, el
árbol esencialmente se comportará como una lista enlazada estructura de datos.
[ editar ] comparaciones de rendimiento
DA Heger (2004) [2] presenta una comparación de rendimiento de los árboles binarios
de búsqueda. Treap se encontró que la media de mejor rendimiento, mientras que -negro
árbol rojo se encontró que la cantidad más pequeña de las fluctuaciones de rendimiento.
[ editar ] árboles binarios de búsqueda óptima
Si no va a modificar un árbol de búsqueda, y sabemos exactamente con qué frecuencia
cada artículo será accesible, podemos construir un árbol binario de búsqueda óptimo,
que es un árbol de búsqueda donde el coste medio de buscar un artículo (el esperado
coste de búsqueda) se reduce al mínimo.
Incluso si sólo tenemos estimaciones de los costos de búsqueda, este sistema puede
acelerar considerablemente las búsquedas en promedio. Por ejemplo, si usted tiene una
BST de las palabras utilizadas en Inglés un corrector ortográfico , que podría equilibrar
el árbol basado en la frecuencia de palabras en el corpus de texto , colocando palabras
como "el" cerca de la raíz y palabras como "agerasia" cerca de las hojas. Este árbol
puede ser comparado con los árboles Huffman , que igualmente pretenden poner
Artículos de uso frecuente cerca de la raíz a fin de producir una densa información de
codificación, sin embargo, los árboles Huffman elementos de datos única tienda en
hojas, y esos elementos no tiene que ser ordenado.
Si no sabemos la secuencia en que los elementos en el árbol se tendrá acceso con
antelación, podemos utilizar árboles splay que son asintóticamente tan bueno como
cualquier árbol de búsqueda estática podemos construir para cualquier secuencia
particular de operaciones de búsqueda.
alfabético árboles son árboles Huffman con la restricción adicional sobre el orden, o,
equivalentemente, árboles de búsqueda con la modificación que todos los elementos se
almacenan en las hojas. algoritmos más rápidos existentes para una óptima árboles
binarios alfabéticos (OABTs).
Ejemplo:
procedimiento de búsqueda del árbol óptimo (f, f, c):
para j = 0 hasta n hacer
c [j, j] = 0, M j [, j] = f'j
para d = 1 hasta n hacer
para i = 0 a (n - d) hacer
j = i + d
M [i, j] = F [i, j - 1] + f '+ f'j
c [i, j] = MIN (i <k <= j) (c [i, k - 1] + c [k, j]) + F [i, j]
[ editar ] Véase también






Búsqueda binaria
Árbol binario
Uno mismo-equilibrio del árbol de búsqueda binaria
árbol de búsqueda binaria aleatorios
B-tree