Muchos algoritmos especificarán que los duplicados están excluidos. Por ejemplo, los algoritmos de ejemplo en el libro MIT Algorithms generalmente presentan ejemplos sin duplicados. Es bastante trivial implementar duplicados (ya sea como una lista en el nodo o en una dirección particular).
La mayoría (que he visto) especifican los hijos izquierdos como <= y los hijos derechos como>. Hablando en términos prácticos, un BST que permite que cualquiera de los hijos derechos o izquierdos sea igual al nodo raíz, requerirá pasos computacionales adicionales para finalizar una búsqueda donde se permiten nodos duplicados.
Es mejor utilizar una lista en el nodo para almacenar duplicados, ya que insertar un valor '=' en un lado de un nodo requiere reescribir el árbol en ese lado para colocar el nodo como hijo, o el nodo se coloca como un gran -child, en algún momento a continuación, lo que elimina parte de la eficiencia de búsqueda.
Debe recordar que la mayoría de los ejemplos de aulas se simplifican para representar y entregar el concepto. No vale la pena ponerse en cuclillas en muchas situaciones del mundo real. Pero la declaración, "cada elemento tiene una clave y no hay dos elementos tienen la misma clave", no se viola mediante el uso de una lista en el nodo del elemento.
¡Así que ve con lo que dice tu libro de estructuras de datos!
Editar:
La definición universal de un árbol de búsqueda binaria implica almacenar y buscar una clave basada en atravesar una estructura de datos en una de dos direcciones. En el sentido pragmático, eso significa que si el valor es <>, atraviesa la estructura de datos en una de dos 'direcciones'. Entonces, en ese sentido, los valores duplicados no tienen ningún sentido.
Esto es diferente de BSP, o partición de búsqueda binaria, pero no tan diferente. El algoritmo para buscar tiene una de dos direcciones para 'viajar', o se hace (con éxito o no). Así que me disculpo porque mi respuesta original no abordaba el concepto de una 'definición universal', ya que los duplicados son realmente distintos tema (algo con lo que trata después de una búsqueda exitosa, no como parte de la búsqueda binaria).
Si su árbol de búsqueda binario es un árbol rojo negro, o tiene la intención de realizar cualquier tipo de operaciones de "rotación de árboles", los nodos duplicados causarán problemas. Imagina que tu regla de árbol es esta:
izquierda <raíz <= derecha
Ahora imagine un árbol simple cuya raíz es 5, el niño izquierdo es nulo, y el niño derecho es 5. Si hace una rotación izquierda en la raíz, termina con un 5 en el niño izquierdo y un 5 en la raíz con el niño derecho siendo nulo Ahora algo en el árbol de la izquierda es igual a la raíz, pero su regla anterior supuso left <root.
Pasé horas tratando de averiguar por qué mis árboles rojos / negros ocasionalmente se desplazaban fuera de servicio, el problema era lo que describí anteriormente. ¡Ojalá alguien lea esto y se ahorre horas de depuración en el futuro!
fuente
left <= node <= right
, o solo insertar antes de la primera aparición de un valor.Las tres definiciones son aceptables y correctas. Definen diferentes variaciones de un BST.
El libro de la estructura de datos de su universidad no pudo aclarar que su definición no era la única posible.
Ciertamente, permitir duplicados agrega complejidad. Si usa la definición "left <= root <right" y tiene un árbol como:
luego agregar una clave duplicada "3" a este árbol dará como resultado:
Tenga en cuenta que los duplicados no están en niveles contiguos.
Este es un gran problema cuando se permiten duplicados en una representación BST como la anterior: los duplicados pueden estar separados por cualquier número de niveles, por lo que verificar la existencia de duplicados no es tan simple como verificar los hijos inmediatos de un nodo.
Una opción para evitar este problema es no representar duplicados estructuralmente (como nodos separados) sino utilizar un contador que cuente el número de ocurrencias de la clave. El ejemplo anterior tendría un árbol como:
y después de insertar la clave duplicada "3" se convertirá en:
Esto simplifica las operaciones de búsqueda, eliminación e inserción, a expensas de algunos bytes adicionales y operaciones de contador.
fuente
En un BST, todos los valores que descienden en el lado izquierdo de un nodo son menores que (o iguales a, ver más adelante) el propio nodo. De manera similar, todos los valores que descienden en el lado derecho de un nodo son mayores que (o iguales) al valor de los nodos (a) .
Algunos BST pueden optar por permitir valores duplicados, de ahí los calificadores "o igual a" anteriores.
El siguiente ejemplo puede aclarar:
Esto muestra un BST que permite duplicados: puede ver que para encontrar un valor, comienza en el nodo raíz y baja por el subárbol izquierdo o derecho dependiendo de si su valor de búsqueda es menor o mayor que el valor del nodo.
Esto se puede hacer recursivamente con algo como:
y llamándolo con:
Los duplicados agregan un poco de complejidad, ya que es posible que deba seguir buscando una vez que haya encontrado su valor para otros nodos del mismo valor.
(a) En realidad, podría ordenarlos en la dirección opuesta si así lo desea, siempre que ajuste la forma en que busca una clave específica. Un BST solo necesita mantener un cierto orden, ya sea que sea ascendente o descendente no es relevante.
fuente
En el libro "Introducción a los algoritmos", tercera edición, de Cormen, Leiserson, Rivest y Stein, un árbol de búsqueda binario (BST) se define explícitamente como permitir duplicados . Esto se puede ver en la figura 12.1 y en lo siguiente (página 287):
Además, un árbol rojo-negro se define en la página 308 como:
Por lo tanto, los árboles rojo-negros definidos en este libro admiten duplicados.
fuente
Cualquier definición es válida. Siempre y cuando sea consistente en su implementación (siempre coloque nodos iguales a la derecha, siempre los ponga a la izquierda o nunca los permita), entonces está bien. Creo que es más común no permitirlos, pero sigue siendo un BST si están permitidos y se colocan a la izquierda o a la derecha.
fuente
Trabajando en una implementación de árbol rojo-negro, tuve problemas para validar el árbol con varias teclas hasta que me di cuenta de que con la rotación de inserción rojo-negro, debe aflojar la restricción para
left <= root <= right
Como ninguna de la documentación que estaba buscando permitía claves duplicadas y no quería reescribir los métodos de rotación para dar cuenta de ello, decidí modificar mis nodos para permitir múltiples valores dentro del nodo, y no duplicar claves en el árbol.
fuente
Esas tres cosas que dijiste son todas ciertas.
Supongo que podría invertir su árbol y colocar las teclas más pequeñas a la derecha, pero en realidad el concepto "izquierda" y "derecha" es solo eso: un concepto visual que nos ayuda a pensar en una estructura de datos que realmente no tiene una izquierda o bien, entonces realmente no importa.
fuente
Puede que tenga que ir y desenterrar mis libros de algoritmos, pero en la parte superior de mi cabeza (3) está la forma canónica.
(1) o (2) solo aparecen cuando comienza a permitir nodos duplicados y coloca nodos duplicados en el árbol (en lugar del nodo que contiene una lista).
fuente
>=
. Ideal depende de sus requisitos, pero si tiene muchos valores duplicados y permite que existan los duplicados en la estructura, su bst puede terminar siendo lineal, es decir, O (n).Claves duplicadas • ¿Qué sucede si hay más de un elemento de datos con la misma clave? - Esto presenta un pequeño problema en los árboles rojo-negros. - Es importante que los nodos con la misma clave se distribuyan en ambos lados de otros nodos con la misma clave. - Es decir, si las claves llegan en el orden 50, 50, 50, • desea que los segundos 50 vayan a la derecha de la primera, y los terceros 50 a la izquierda de la primera. • De lo contrario, el árbol se desequilibra. • Esto podría manejarse mediante algún tipo de proceso de aleatorización en el algoritmo de inserción. - Sin embargo, el proceso de búsqueda se vuelve más complicado si se deben encontrar todos los elementos con la misma clave. • Es más sencillo prohibir artículos con la misma clave. - En esta discusión asumiremos que no se permiten duplicados
Se puede crear una lista vinculada para cada nodo del árbol que contiene claves duplicadas y almacenar datos en la lista.
fuente
Solo quiero agregar más información a lo que respondió @Robert Paulson.
Supongamos que el nodo contiene clave y datos. Por lo tanto, los nodos con la misma clave pueden contener datos diferentes.
(Por lo tanto, la búsqueda debe encontrar todos los nodos con la misma clave)
1) y 2) funciona bien si el árbol no tiene ninguna función relacionada con la rotación para evitar la asimetría.
Pero esta forma no funciona con el árbol AVL o el árbol Rojo-Negro , porque la rotación romperá el principal.
E incluso si search () encuentra el nodo con la clave, debe atravesar hasta el nodo hoja para los nodos con clave duplicada.
Hacer la complejidad del tiempo para la búsqueda = theta (logN)
3) funcionará bien con cualquier forma de BST con funciones relacionadas con la rotación.
Pero la búsqueda tomará O (n) , arruinando el propósito de usar BST.
Digamos que tenemos el árbol como abajo, con 3) principal.
Si buscamos (12) en este árbol, incluso si encontramos 12 en la raíz, debemos seguir buscando tanto el niño izquierdo como el derecho para buscar la clave duplicada.
Esto toma O (n) tiempo, como he dicho.
4) es mi favorito personal. Digamos que hermano significa el nodo con la misma clave.
Podemos cambiar el árbol de arriba a abajo.
Ahora cualquier búsqueda tomará O (logN) porque no tenemos que atravesar hijos para la clave duplicada.
Y este director también funciona bien con el árbol AVL o RB .
fuente
La relación de orden de elementos <= es un orden total, por lo que la relación debe ser reflexiva, pero comúnmente un árbol de búsqueda binario (también conocido como BST) es un árbol sin duplicados.
De lo contrario, si hay duplicados, debe ejecutar dos veces o más la misma función de eliminación.
fuente