Cómo organizar y buscar un árbol de búsqueda binario donde cada nodo tiene más de un campo de datos

En general, una estructura de “búsqueda” funciona en un solo campo dentro de los nodos. Suele denominarse campo clave y se utiliza para evaluar la igualdad y la clasificación. No solo se limita a los árboles de búsqueda binarios, sino a todas las estructuras en las que desea encontrar un nodo en particular según un valor específico de uno de sus campos.

Dependiendo de la biblioteca, debería poder redefinir una función de comparación de modo que solo funcione en ese campo particular de cada nodo, ignorando los valores en los otros campos. Por ejemplo, supongamos que está utilizando la clase SortedSet (T) (System.Collections.Generic) en DotNet. Esa clase usa un árbol Rojo-Negro (una forma de árbol de búsqueda binaria autoequilibrado) para almacenar los nodos.

Tenga en cuenta que uno de sus constructores acepta un argumento IComparer. Esto le permite dar a la estructura una función de comparación personalizada. Dentro de esto, puede cambiar qué parte de cada nodo se compara entre sí cuando la estructura intenta encontrar la posición de cada nodo.

Alternativamente, podría implementar la interfaz IComparable en el tipo que está agregando al conjunto. Es decir, escribiría un método CompareTo para la clase / estructura que desea colocar dentro del conjunto. Similar se aplica a la definición de una clase de Comparer personalizada separada.

Varias otras bibliotecas (y otros entornos / idiomas) tienen formas similares de definir comparaciones personalizadas. Pero el principio es el mismo.

Otro tipo de estructura similar es una clase SortedDictionary (TKey, TValue) (System.Collections.Generic). Sin embargo, en este caso, genera su propio nodo combinando un valor y una clave en un tipo de par clave-valor y luego usándolo para insertarlo en la estructura de árbol de respaldo. Eso ya tiene su propio método CompareTo implementado. Y eso solo usa la clave para comparar entre dos nodos. De esta forma, podría extraer un nodo dependiendo del valor de su clave. Si bien usarlo en la forma en que el valor ya tiene un campo que define la clave significa que está duplicando el valor contenido en esa clave, sigue siendo bastante útil y muy simple de usar.

La razón por la que no hay una estructura implementada en la que pueda buscar un nodo especificando uno donde solo haya ingresado su clave es porque hace que la estructura sea menos general. Por ejemplo, si quisiera tener algo como un método GetValue en un SortedSet, necesitaría extender la clase SortedSet. Y necesitaría definir que su tipo de nodo debe implementar al menos una función de comparación. La idea del Diccionario simplemente hace que esto sea innecesario al comprometer el uso de la memoria.

Si quiere decir que desea buscar en cualquiera de los campos dentro del nodo, deberá crear una estructura de árbol para cada uno de los campos. Duplicar los datos (o al menos la referencia a ellos) en cada árbol, con un comparador para trabajar solo en el campo relevante. De nuevo, no es algo que sucede generalmente. Y de nuevo, mucho más simple de implementar usando la idea del diccionario, aunque comprometiendo el uso de la memoria.

Una vez más, otras bibliotecas y / o entornos pueden tener estructuras incorporadas similares que hacen más o menos lo mismo.

Usted no

El problema es que un árbol solo puede tener una clave.

Ahora PUEDE (aunque complicado) usar múltiples árboles, donde cada nodo está en todos los árboles.

Esto le permitiría tener 4 raíces (una para cada árbol), pero cada nodo debe insertarse en cada árbol; por lo tanto, el nodo requeriría 4 * 2 enlaces (dos para cada árbol). Y cada vez que se agrega un nodo a un árbol, también se debe agregar a los otros árboles según las otras claves del nodo.

Esto funciona para árboles relativamente pequeños … (mi estimación aproximada sería inferior a un par de miles).

Lo que sucede con más frecuencia es que, en lugar de almacenar los datos en árboles, los datos sin procesar se almacenan en un hash (o una matriz simple), luego se mantienen árboles separados que solo tienen un enlace a la entrada hash / array. Esto tiene un par de ventajas: el nodo solo contiene los datos. Los árboles de índice son más pequeños: un enlace a los datos en el hash / array y dos enlaces para el árbol.

La ventaja ahora es que todos los árboles son equivalentes en estructura, PERO su inserción / eliminación del árbol puede hacer referencia a una clave específica (consulte qsort para ver una forma de pasar una referencia a una función de comparación). Esto hace que los datos generales sean más pequeños y las funciones del árbol más simples (solo necesita un conjunto).

Una cosa añadida … Dependiendo de lo que esté haciendo, incluso puede eliminar los árboles y simplemente ordenar referencias de índice. Cada matriz usa una clave diferente y usted usa una búsqueda binaria en la matriz. La inserción / eliminación se vuelve más lenta, pero si realiza más búsquedas que insertar / eliminar, puede ser ventajoso.

Primero, un árbol de búsqueda binaria debe mantener la propiedad del árbol de búsqueda binaria: que los elementos mantengan un orden parcial dentro del árbol. Si tomo dos nodos, necesito una forma de decirme si el nodo viene antes o después (o “igual”) que el otro en el pedido. Es por eso que probablemente solo lo haya visto con una clave en un nodo.

Para lidiar con 4 campos de datos como ese, debe tener una manera de decir que el elemento secundario izquierdo “viene antes” del nodo en sí, y el elemento secundario derecho “viene después o tiene el mismo orden” que el nodo. Luego tiene una forma de insertar, eliminar y buscarlo correctamente. Así que solo encuentra una manera de hacer esto, y listo. Tenga en cuenta que si solo está interesado en la implementación de esto, en un lenguaje de programación como Java, esto sería equivalente a implementar la interfaz Comparable para los nodos o elementos (elija uno), luego use el método compareTo para saber si necesita ir a la izquierda o derecha o es el nodo que está buscando.

La forma en que lo hago en C ++ es que uso una estructura, siendo el primer campo la clave. Tiendo a usar mapas stl, pero cualquier BST en casa debería funcionar.

Deberá sobrecargar el operador == y uno de los operadores ‘>’ o ‘<'. Olvidé cuál.

Así por ejemplo:

struct myData

{

int iKey;

std :: string strName;

std :: string str Dirección;

etc.

operador bool == (const myData & rhs) const

{return (iKey == rhs.iKey); };

operador bool <(const myData & rhs) const

{return (iKey

};

Ahora toda la estructura myData se puede insertar en un BST, pero se puede organizar explícitamente en función del campo de datos de iKey.

Esto también es útil para std :: maps de la siguiente manera:

std :: map myMap;

datos myData; // alguna instancia de la estructura que desea insertar y organizar del campo iKey.

myMap.instert (std :: make_pair (myMap.iKey, myData));

Siempre que no haya hecho ningún problema de sintaxis abierta, esta es la forma general en que lo hago. Me gusta de esta manera, ya que también mantiene al miembro iKey como un componente integral del campo de valor myData y da la sensación de la forma general en que las bases de datos de relaciones tienden a funcionar también.

Los árboles de búsqueda binaria se ordenan según un valor de “clave”. Para poder buscar en otra clave se requeriría un BST por separado. Sin embargo, los nodos en cada árbol pueden tener punteros a los mismos elementos de datos.

More Interesting

Para una computadora, ¿qué tan aleatorio es ser aleatorio?

Encontré un problema algorítmico y no sé cómo resolverlo. ¿Alguien me puede ayudar?

¿Qué se siente al resolver bien los problemas de programación dinámica?

¿Qué algoritmos de programación utiliza cada sistema operativo común?

Te dan n pilas con p monedas, y cada jugador elimina al menos 1 moneda. El número de monedas eliminadas por un jugador no puede ser eliminado por el otro. ¿Quién ganará?

¿Dónde se puede encontrar una foto y detalles biográficos de Burton Howard Bloom, inventor del filtro Bloom?

¿Puedo encontrar el camino hamiltoniano más corto en un gráfico completo ponderado no dirigido en tiempo polinómico (donde todos los pesos no son negativos)?

¿Cuál es la técnica para crear una solución DP iterativa a partir de su solución recursiva?

¿Por qué los algoritmos de compresión de datos sin pérdida no funcionan bien en archivos de video?

Cómo crear una ordenación rápida en C

¿Cuál es la estrategia de divide y vencerás? Escribe un algoritmo para encontrar x a la enésima potencia usando el método de dividir y conquistar.

¿Cuál es el mejor curso de algoritmo para comenzar a resolver problemas y convertirse en un ingeniero de software? Encontré tres cursos. ¿Me pueden ayudar a elegir uno?

Cómo comenzar a aprender cómo crear algoritmos de comercio Quant en Java

¿Cómo se puede observar fácilmente que la complejidad temporal del código escrito es exponencial?

¿Puede la longitud de un comando Mathematica o Wolfram | Alpha ser una aproximación aproximada de su complejidad de Kolmogorov?