Ordenar con un árbol binario
Ordenar usando un árbol binario (binary tree sorting, tree sorting, tree sorting, sorting using a binary tree, eng. tree sort ) es un algoritmo de clasificación universal que consiste en construir un árbol de búsqueda binaria por las claves de una matriz (lista), seguido de ensamblar la matriz resultante recorriendo los nodos del árbol construido en el orden requerido de las claves. Esta clasificación es óptima cuando se reciben datos mediante la lectura directa de una secuencia (por ejemplo, un archivo, un socket o una consola).
Algoritmo
- Construcción de un árbol binario.
- Ensamblar la matriz resultante atravesando los nodos en el orden requerido de las claves.
Eficiencia
El procedimiento para agregar un objeto a un árbol binario tiene una complejidad algorítmica promedio del orden . En consecuencia, para n objetos, la complejidad será , que clasifica la ordenación mediante un árbol binario como un grupo de "clasificaciones rápidas". Sin embargo, la complejidad de agregar un objeto a un árbol desequilibrado puede ser tan alta como , lo que puede conducir a una complejidad general del orden de .




Al expandir físicamente una estructura de árbol en la memoria, se requieren al menos celdas de memoria adicionales (cada nodo debe contener referencias a un elemento de la matriz original, al elemento principal, a la hoja izquierda y derecha), sin embargo, hay formas de reducir la memoria adicional requerida.

Ejemplos de implementación
En una forma simple de programación funcional en Haskell , este algoritmo se vería así:
árbol de datos a = hoja | Nodo ( Árbol a ) a ( Árbol a )
insert :: Ord a => a -> Tree a -> Tree a
insert x Leaf = Node Leaf x Leaf
insert x ( Node t y t' ) | x <= y = Nodo ( insertar x t ) y t'
insertar x ( Nodo t y t' ) | x > y = Nodo t y ( insertar x t' )
aplanar :: Árbol a -> [ a ]
aplanar Hoja = []
aplanar ( Nodo t x t' ) = aplanar t ++ [ x ] ++ aplanar t'
treesort :: Ord a => [ a ] -> [ a ]
treesort = flatten . Hoja de inserción plegable
Implementación en C++14 :
#include <memoria>
#incluir <cassert>
#incluye <algoritmo>
#incluir <vector>
#incluir <iostream>
utilizando el espacio de nombres estándar ;
// clase que representa un árbol binario
class BinaryTree
{
protegido :
// estructura de nodo de árbol
binario BinaryTreeNode
{
shared_ptr < BinaryTreeNode > izquierda , derecha ; // subárbol izquierdo y derecho int key ; // clave };
shared_ptr < BinaryTreeNode > m_root ; // raíz del árbol protegida :
// procedimiento de inserción de clave recursiva
// cur_node - el nodo actual del árbol con el que se compara el nodo insertado // node_to_insert - el nodo insertado void insert_recursive ( const shared_ptr < BinaryTreeNode >& cur_node , const shared_ptr < BinaryTreeNode >& node_to_insert )
{
afirmar ( cur_node != nullptr );
// comparar
bool insertIsLess = node_to_insert -> key < cur_node -> key ;
si ( insertarEsMenos )
{
// insertar en el subárbol izquierdo
si ( cur_node -> left == nullptr )
cur_node -> izquierda = nodo_a_insertar ;
más
insert_recursive ( cur_node -> izquierda , node_to_insert );
}
más
{
// insertar en el subárbol derecho
if ( cur_node -> right == nullptr )
cur_node -> right = node_to_insert ;
más
insert_recursive ( cur_node -> right , node_to_insert );
}
}
público :
inserción vacía ( tecla int )
{
shared_ptr < BinaryTreeNode > node_to_insert ( new BinaryTreeNode );
nodo_a_insertar -> clave = clave ;
if ( m_raíz == punto nulo )
{
m_root = nodo_a_insertar ;
volver ;
}
insert_recursive ( m_root , node_to_insert );
}
público :
función typedef < void ( tecla int ) > Visitante ;
protegido :
// procedimiento de recorrido de árbol recursivo
// cur_node - nodo visitado actualmente void visit_recursive ( const shared_ptr < BinaryTreeNode >& cur_node , const Visitor & visitante )
{
afirmar ( cur_node != nullptr );
// primero visita el subárbol izquierdo
if ( cur_node -> left != nullptr )
visit_recursive ( cur_node -> izquierda , visitante );
// visita el
visitante del elemento actual ( cur_node -> key );
// visita el subárbol derecho
if ( cur_node -> right != nullptr )
visit_recursive ( cur_node -> right , visitante );
}
público :
visita nula ( visitante const & visitante )
{
if ( m_raíz == punto nulo )
volver ;
visit_recursive ( m_root , visitante );
}
};
int principal ()
{
ArbolBinario ; _
// agregar elementos al
vector de árbol < int > data_to_sort = { 10 , 2 , 7 , 3 , 14 , 7 , 32 };
para ( valor int : data_to_sort )
{
árbol _ insertar ( valor );
}
// árbol transversal
del árbol . visita ([]( int clave_visitada )
{
cout << clave_visitada << " " ;
});
cout << endl ;
// resultado de la ejecución: 2 3 7 7 10 14 32
return 0 ;
}
Un ejemplo de creación de un árbol binario y clasificación en Java :
// Compila y escribe java TreeSort
class Tree {
public Tree left ; // subárboles izquierdo y derecho y clave
public Tree right ;
clave de entrada pública ; _
public Tree ( int k ) { // constructor con clave de inicialización
clave = k ;
}
/* insertar (agregar un nuevo subárbol (clave))
comparar la clave del subárbol que se agregará (K) con la clave del nodo raíz (X).
Si K>=X, agregue recursivamente un nuevo árbol al subárbol derecho.
Si K<X, agrega recursivamente un nuevo árbol al subárbol izquierdo.
Si no hay un subárbol, inserte un nuevo árbol en este lugar
*/
public void insert ( Tree aTree ) {
if ( aTree . key < key )
if ( left != null ) left . insertar ( unárbol );
otra cosa a la izquierda = aTree ;
else
if ( right != null ) right . insertar ( unárbol );
otra cosa a la derecha = unárbol ;
}
/* recorrer
Recursivamente recorrer el subárbol izquierdo.
Aplique la función f (imprimir) al nodo raíz.
Atraviesa el subárbol derecho recursivamente.
*/
public void traverse ( visitante TreeVisitor ) { if ( left != null ) left . atravesar ( visitante );
visitante _ visitar ( esto );
si ( correcto ! = nulo )
correcto . atravesar ( visitante );
}
}
interfaz TreeVisitor {
visita pública vacía ( nodo de árbol ); };
class KeyPrinter implementa TreeVisitor {
public void visit ( Tree node ) {
System . fuera _ println ( " " + nodo . clave );
}
};
class TreeSort {
public static void main ( String args [] ) {
Tree myTree ;
miÁrbol = nuevo Árbol ( 7 ); // crea un árbol (con clave)
myTree . insertar ( nuevo árbol ( 5 ) ); // adjuntar subárboles
myTree . insertar ( nuevo árbol ( 9 ) );
miÁrbol . atravesar ( nueva KeyPrinter ());
}
}
Véase también