fbpx
Wikipedia

Árbol binario de búsqueda

Un árbol binario de búsqueda también llamado BST (acrónimo del inglés Binary Search Tree) es un tipo particular de árbol binario que presenta una estructura de datos en forma de árbol usada en informática.

Descripción

Veamos la definición de árbol binario de búsqueda:

Árbol binario de búsqueda

Sea A un árbol binario de raíz R e hijos izquierdo y derecho (posiblemente nulos) HI y HD , respectivamente.

Decimos que A es un árbol binario de búsqueda (ABB) si y solo si se satisfacen las dos condiciones al mismo tiempo:

  • "HI es vacío"   ("R es mayor que todo elemento de HI"   "HI es un ABB").
  • "HD es vacío"   ("R es menor que todo elemento de HD"   "HD es un ABB").

Donde " " es la conjunción lógica "y", y " " es la disyunción lógica "o".

 
Un árbol binario de búsqueda de tamaño 9 y profundidad 3, con raíz 8 y hojas 1, 4, 7 y 13

Para una fácil comprensión queda resumido en que es un árbol binario que cumple que el subárbol izquierdo de cualquier nodo (si no está vacío) contiene valores menores que el que contiene dicho nodo, y el subárbol derecho (si no está vacío) contiene valores mayores.

Para estas definiciones se considera que hay una relación de orden establecida entre los elementos de los nodos. Que cierta relación esté definida, o no, depende de cada lenguaje de programación. De aquí se deduce que puede haber distintos árboles binarios de búsqueda para un mismo conjunto de elementos.

La altura h en el peor de los casos es siempre el mismo tamaño que el número de elementos disponibles. Y en el mejor de los casos viene dada por la expresión  .

El interés de los árboles binarios de búsqueda (ABB) radica en que su recorrido en in orden proporciona los elementos ordenados de forma ascendente y en que la búsqueda de algún elemento suele ser muy eficiente.

Dependiendo de las necesidades del usuario que trate con una estructura de este tipo, se podrá permitir la igualdad estricta en alguno, en ninguno o en ambos de los subárboles que penden de la raíz. Permitir el uso de la igualdad provoca la aparición de valores dobles y hace la búsqueda más compleja.

Un árbol binario de búsqueda no deja de ser un caso particular de árbol binario, así usando la siguiente especificación de árbol binario en maude:

 fmod ARBOL-BINARIO {X :: TRIV}is sorts ArbolBinNV{X} ArbolBin{X} . subsort ArbolBinNV{X} < ArbolBin{X} . *** generadores op crear : -> ArbolBin{X} [ctor] . op arbolBin : X$Elt ArbolBin{X} ArbolBin{X} -> ArbolBinNV{X} [ctor] . endfm 

podemos hacer la siguiente definición para un árbol binario de búsqueda (también en maude):

 fmod ARBOL-BINARIO-BUSQUEDA {X :: ORDEN} is protecting ARBOL-BINARIO{VOrden}{X} . sorts ABB{X} ABBNV{X} . subsort ABBNV{X} < ABB{X} . subsort ABB{X} < ArbolBin{VOrden}{X} . subsort ABBNV{X} < ArbolBinNV{VOrden}{X} . *** generadores op crear : -> ArbolBin{X} [ctor] . op arbolBin : X$Elt ArbolBin{X} ArbolBin{X} -> ArbolBinNV{X} [ctor] . endfm 

con la siguiente teoría de orden:

 fth ORDEN is protecting BOOL . sort Elt . *** operaciones op _<_ : Elt Elt -> Bool . endfth 

para que un árbol binario pertenezca al tipo árbol binario de búsqueda debe cumplir la condición de ordenación siguiente que iría junto al módulo ARBOL-BINARIO-BUSQUEDA:

 var R : X$Elt . vars INV DNV : ABBNV{X} . vars I D : ABB{X} . mb crear : ABB{X} . mb arbolBin(R, crear, crear) : ABBNV{X} . cmb arbolBin(R, INV, crear) : ABBNV{X} if R > max(INV) . cmb arbolBin(R, crear, DNV) : ABBNV{X} if R < min(DNV) . cmb arbolBin(R, INV, DNV) : ABBNV{X} if (R > max(INV)) and (R < min(DNV)) . ops min max : ABBNV{X} -> X$Elt . eq min(arbolBin(R, crear, D)) = R . eq min(arbolBin(R, INV, D)) = min(INV) . eq max(arbolBin(R, I, crear)) = R . eq max(arbolBin(R, I, DNV)) = max(DNV) . 
class nodo: izq , der, dato = None, None, 0 def __init__(self, dato): # crea un nodo self.izq = None self.der = None self.dato = dato 
class arbolBinario: def __init__(self): # inicializa la raiz self.raiz = None def agregarNodo(self, dato): # crea un nuevo nodo y lo devuelve return nodo(dato) def insertar(self, raiz, dato): # inserta un dato nuevo en el árbol if raiz == None: # si no hay nodos en el árbol lo agrega return self.agregarNodo(dato) else: # si hay nodos en el árbol lo recorre if dato <= raiz.dato: # si el dato ingresado es menor que el dato guardado va al subárbol izquierdo raiz.izq = self.insertar(raiz.izq, dato) else: # si no, procesa el subárbol derecho raiz.der = self.insertar(raiz.der, dato) return raiz 

Operaciones

Todas las operaciones realizadas sobre árboles binarios de búsqueda están basadas en la comparación de los elementos o clave de los mismos, por lo que es necesaria una subrutina, que puede estar predefinida en el lenguaje de programación, que los compare y pueda establecer una relación de orden entre ellos, es decir, que dados dos elementos sea capaz de reconocer cual es mayor y cual menor. Se habla de clave de un elemento porque en la mayoría de los casos el contenido de los nodos será otro tipo de estructura y es necesario que la comparación se haga sobre algún campo al que se denomina clave.

Búsqueda

La búsqueda en un árbol binario de búsqueda consiste en acceder a la raíz del árbol, si el elemento a localizar coincide con este la búsqueda ha concluido con éxito, si el elemento es menor se busca en el subárbol izquierdo y si es mayor en el derecho. Si se alcanza un nodo hoja y el elemento no ha sido encontrado es que no existe en el árbol.

Cabe destacar que la búsqueda en este tipo de árboles es muy eficiente, representa una función logarítmica. El máximo número de comparaciones que necesitaríamos para saber si un elemento se encuentra en un árbol binario de búsqueda estaría entre [log2(N+1)] y N, siendo N el número de nodos.

La búsqueda de un elemento en un ABB (Árbol Binario de Búsqueda) se puede realizar de dos formas, iterativa o recursiva.

Ejemplo de versión iterativa en el lenguaje de programación C, suponiendo que estamos buscando una clave alojada en un nodo donde está el correspondiente "dato" que precisamos encontrar:

data Buscar_ABB(abb t,clave k)  {  abb p;  dato e;  e=NULL;  p=t;  if (!estaVacio(p))  {  while (!estaVacio(p) && (p->k!=k) )  {  if (k < p->k)  {  p=p->l;  }  if (p->k < k)  {  p=p->r;  }  }  if (!estaVacio(p) &&(p->d!=NULL) )  {  e=copiaDato(p->d);   }   }  return e; } 

Véase ahora la versión recursiva en ese mismo lenguaje:

int buscar(tArbol *a, int elem) {  if (a == NULL)  {  return 0;  }  else if (a->clave < elem)  {  return buscar(a->hDerecho, elem);  }  else if (a->clave > elem)  {  return buscar(a->hIzquierdo, elem);  }  else  {  return 1;  } } 

Otro ejemplo en Python:

def buscar(raiz, clave): # busca el valor clave dentro del arbol if raiz == None: print 'No se encuentra' else: if clave == raiz.dato: print 'El valor ',clave,' se encuentra en el ABB' elif clave < raiz.dato: # lado izquierdo return buscar(raiz.izq, clave) else: # lado derecho return buscar(raiz.der, clave) 

En Pascal:

Function busqueda(T:ABR, y: integer):ABR begin if (T=nil) or (^T.raiz=y) then busqueda:=T; else if (^T.raiz<y) then busqueda:=busqueda(^T.dch,y); else busqueda:=busqueda(^T.izq,y); end; 

Una especificación en maude para la operación de búsqueda quedaría de la siguiente forma:

 op esta? : X$Elt ABB{X} -> Bool . var R R1 R2 : X$Elt . vars I D : ABB{X} . eq esta?(R, crear) = false . eq esta?(R1, arbolBin(R2, I, D)) = if R1 == R2 then  true else  if R1 < R2 then esta?(R1, I) else  esta?(R1, D) fi fi . 

Inserción

La inserción es similar a la búsqueda y se puede dar una solución tanto iterativa como recursiva. Si tenemos inicialmente como parámetro un árbol vacío se crea un nuevo nodo como único contenido el elemento a insertar. Si no lo está, se comprueba si el elemento dado es menor que la raíz del árbol inicial con lo que se inserta en el subárbol izquierdo y si es mayor se inserta en el subárbol derecho.

 
Evolución de la inserción del elemento "5" en un ABB.

Como en el caso de la búsqueda puede haber varias variantes a la hora de implementar la inserción en el TAD (Tipo Abstracto de Datos), y es la decisión a tomar cuando el elemento (o clave del elemento) a insertar ya se encuentra en el árbol, puede que este sea modificado o que sea ignorada la inserción. Es obvio que esta operación modifica el ABB perdiendo la versión anterior del mismo.

A continuación se muestran las dos versiones del algoritmo en pseudolenguaje, iterativa y recursiva, respectivamente.

PROC InsertarABB(árbol:TABB; dato:TElemento) VARIABLES nuevonodo,pav,pret:TABB clavenueva:Tclave ele:TElemento INICIO nuevonodo <- NUEVO(TNodoABB) nuevonodo^.izq <- NULO nuevonodo^.der <- NULO nuevonodo^.elem <- dato SI ABBVacío (árbol) ENTONCES árbol <- nuevonodo ENOTROCASO clavenueva <- dato.clave pav <- árbol // Puntero Avanzado pret <- NULO // Puntero Retrasado MIENTRAS (pav <- NULO) HACER pret <- pav ele = pav^.elem SI (clavenueva < ele.clave ) ENTONCES pav <- pav^.izq EN OTRO CASO pav <- pav^.dch FINSI FINMIENTRAS ele = pret^.elem SI (clavenueva < ele.clave ) ENTONCES pret^.izq <- nuevonodo EN OTRO CASO pret^.dch <- nuevonodo FINSI FINSI FIN 
PROC InsertarABB(árbol:TABB; dato:TElemento) VARIABLES ele:TElemento INICIO SI (ABBVacío(árbol)) ENTONCES árbol <- NUEVO(TNodoABB) árbol^.izq <- NULO árbol^.der <- NULO árbol^.elem <- dato EN OTRO CASO ele = InfoABB(árbol) SI (dato.clave < ele.clave) ENTONCES InsertarABB(árbol^.izq, dato) EN OTRO CASO InsertarABB(árbol^.dch, dato) FINSI FINSI FIN 

Se ha podido apreciar la simplicidad que ofrece la versión recursiva, este algoritmo es la traducción en C. El árbol es pasado por referencia para que los nuevos enlaces a los subárboles mantengan la coherencia.

void insertar(tArbol **a, int elem) {  if (*a == NULL)  {  *a = (tArbol *) malloc(sizeof(tArbol));  (*a)->clave = elem;  (*a)->hIzquierdo = NULL;  (*a)->hDerecho = NULL;  }  else if ((*a)->clave < elem)  insertar(&(*a)->hDerecho, elem);  else if ((*a)->clave > elem)  insertar(&(*a)->hIzquierdo, elem); } 

En Python el mecanismo de inserción se define, por ejemplo, dentro de la clase que defina el ABB (ver más arriba).

Otro ejemplo en Pascal:

Procedure Insercion(var T:ABR, y:integer) var ultimo:ABR; actual:ABR; nuevo:ABR; begin ultimo:=nil; actual:=T; while (actual<>nil) do begin ultimo:=actual; if (actual^.raiz<y) then actual:=actual^.dch else actual:=actual^.izq; end; new(nuevo); ^nuevo.raiz:=y; ^nuevo.izq:=nil; ^nuevo.dch:=nil; if ultimo=nil then T:=nuevo else if ultimo^.raiz<y then ultimo^.dch:=nuevo else ultimo^.izq:=nuevo; end; 

Véase también un ejemplo de algoritmo recursivo de inserción en un ABB en el lenguaje de programación Maude:

 op insertar : X$Elt ABB{X} -> ABBNV{X} . var R R1 R2 : X$Elt . vars I D : ABB{X} . eq insertar(R, crear) = arbolBin(R, crear, crear) . eq insertar(R1, arbolBin(R2, I, D)) = if R1 < R2 then arbolBin(R2, insertar(R1, I), D) else  arbolBin(R2, I, insertar(R1, D)) fi . 

La operación de inserción requiere, en el peor de los casos, un tiempo proporcional a la altura del árbol.

Borrado

La operación de borrado no es tan sencilla como las de búsqueda e inserción. Existen varios casos a tener en consideración:

  • Borrar un nodo sin hijos o nodo hoja: simplemente se borra y se establece a nulo el apuntador de su padre.
 
  • Borrar un nodo con un subárbol hijo: se borra el nodo y se asigna su subárbol hijo como subárbol de su padre.
 
  • Borrar un nodo con dos subárboles hijo: la solución está en reemplazar el valor del nodo por el de su predecesor o por el de su sucesor en inorden y posteriormente borrar este nodo. Su predecesor en inorden será el nodo más a la derecha de su subárbol izquierdo (mayor nodo del subarbol izquierdo), y su sucesor el nodo más a la izquierda de su subárbol derecho (menor nodo del subarbol derecho). En la siguiente figura se muestra cómo existe la posibilidad de realizar cualquiera de ambos reemplazos:
 

El siguiente algoritmo en C realiza el borrado en un ABB. El procedimiento reemplazar busca la mayor clave del subárbol izquierdo y la asigna al nodo a eliminar.

void reemplazar(tArbol **a, tArbol **aux); /*Prototipo de la funcion ''reemplazar''*/ void borrar(tArbol **a, int elem) {  tArbol *aux;  if (*a == NULL)  return;  if ((*a)->clave < elem)  borrar(&(*a)->hDerecho, elem);  else if ((*a)->clave > elem)  borrar(&(*a)->hIzquierdo, elem);  else if ((*a)->clave == elem)  {  aux = *a;  if ((*a)->hIzquierdo == NULL)  *a = (*a)->hDerecho;  else if ((*a)->hDerecho == NULL)  *a = (*a)->hIzquierdo;  else  reemplazar(&(*a)->hIzquierdo, &aux);  free(aux);  } } void reemplazar(tArbol **a, tArbol **aux) {  if ((*a)->hDerecho == NULL)  {  (*aux)->clave = (*a)->clave;  *aux = *a;  *a = (*a)->hIzquierdo;  }  else  reemplazar(&(*a)->hDerecho, aux); } 

Otro ejemplo en Pascal.

Procedure Borrar(var T:ABR, x:ABR) var aBorrar:ABR; anterior:ABR; actual:ABR; hijo:ABR; begin if (^x.izq=nil) or (^x.dch=nil) then aBorrar:=x; else aBorrar:=sucesor(T,x); actual:=T; anterior:=nil; while (actual<>aBorrar) do begin anterior:=actual; if (^actual.raiz<^aBorrar.raiz) then actual:=^actual.dch; else actual:=^actual.izq; end; if (^actual.izq=nil) then hijo:=^actual.dch; else hijo:=^actual.izq; if (anterior=nil) then T:=hijo; else if (^anterior.raiz<^actual.raiz) then ^anterior.dch:=hijo; else ^anterior.izq:=hijo; if (aBorrar<>x) then ^x.raiz:=^aBorrar.raiz; free(aBorrar); end; 

Véase también un ejemplo de algoritmo recursivo de borrado en un ABB en el lenguaje de programación Maude, considerando los generadores crear y arbolBin. Esta especificación hace uso de la componente clave a partir de la cual se ordena el árbol.

 op eliminar : X$Elt ABB{X} -> ABB{X} . varS R M : X$Elt . vars I D : ABB{X} . vars INV DNV : ABBNV{X} . ops max min : ArbolBin{X} -> X$Elt . eq min(arbolBin(R, crear, D)) = R . eq max(arbolBin(R, I, crear)) = R . eq min(arbolBin(R, INV, D)) = min(INV) . eq max(arbolBin(R, I, DNV )) = max(DNV) . eq eliminar(M, crear) = crear . ceq eliminar(M, arbolBin(R, crear, D)) = D if M == clave(R) . ceq eliminar(M, arbolBin(R, I, crear)) = I if M == clave(R) . ceq eliminar(M, arbolBin(R, INV, DNV)) = arbolBin(max(INV), eliminar(clave(max(INV)), INV), DNV) if M == clave(R) . ceq eliminar(M, arbolBin(R, I, D)) = arbolBin(R, eliminar(M, I), D) if M < clave(R) . ceq eliminar(M, arbolBin(R, I, D)) = arbolBin(R, I, eliminar(M, D)) if clave(R) < M . 

Otras Operaciones

Otra operación sería por ejemplo comprobar que un árbol binario es un árbol binario de búsqueda. Su implementación en maude es la siguiente:

 op esABB? : ABB{X} -> Bool . var R : X$Elt . vars I D : ABB{X} . eq esABB?(crear) = true . eq esABB?(arbolbBin(R, I, D)) = (Max(I) < R) and (Min(D) > R) and (esABB?(I)) and (esABB?(D)) . 

Recorridos

Se puede hacer un recorrido de un árbol en profundidad o en anchura.

Los recorridos en anchura son por niveles, se realiza horizontalmente desde la raíz a todos los hijos antes de pasar a la descendencia de alguno de los hijos.

El coste de recorrer el ABB es O(n), ya que se necesitan visitar todos los vértices.

El recorrido en profundidad lleva al camino desde la raíz hacia el descendiente más lejano del primer hijo y luego continúa con el siguiente hijo. Como recorridos en profundidad tenemos inorden, preorden y postorden.

Una propiedad de los ABB es que al hacer un recorrido en profundidad inorden obtenemos los elementos ordenados de forma ascendente.

 

Resultado de hacer el recorrido en:

Inorden = [6, 9, 13, 14, 15, 17, 20, 26, 64, 72].

Preorden = [15, 9, 6, 14, 13, 20, 17, 64, 26, 72].

Postorden =[6, 13, 14, 9, 17, 26, 72, 64, 20, 15].

Recorridos en Visual Basic .Net

'función de recorrido en PREORDEN Public Function preorden() As String cadenasalida = "" rePreorden(raíz) Return cadenasalida End Function Private Sub rePreorden(ByVal padre As Nodo) If IsNothing(padre) Then Return End If cadenasalida = cadenasalida & "-" & padre.dato rePreorden(padre.ant) rePreorden(padre.sig) End Sub 
 'función de recorrido en POSTORDEN Public Function postorden() As String cadenasalida = "" repostorden(raíz) Return cadenasalida End Function Private Sub repostorden(ByVal padre As Nodo) If IsNothing(padre) Then Return End If repostorden(padre.ant) repostorden(padre.sig) cadenasalida = cadenasalida & "-" & padre.dato End Sub 
 'función de recorrido en ENORDEN Public Function inorden() As String cadenasalida = "" reinorden(raíz) Return cadenasalida End Function Private Sub reinorden(ByVal padre As Nodo) If IsNothing(padre) Then Return End If reinorden(padre.ant) cadenasalida = cadenasalida & "-" & padre.dato reinorden(padre.sig) End Sub 

Recorridos en C con funciones recursivas

struct Nodo{  char nombre[30];  struct Nodo *izq;  struct Nodo *der; }; typedef struct Nodo Nodo; typedef Nodo *Arbol; void preOrden(Arbol abb){  if(abb)  {  printf("%s\n", abb->nombre);  preOrden(abb->izq);  preOrden(abb->der);  } } void postOrden(Arbol abb){  if(abb)  {  postOrden(abb->izq);  postOrden(abb->der);  printf("%s\n", abb->nombre);  } } void inOrden(Arbol abb){  if(abb)  {  inOrden(abb->izq);  printf("%s\n", abb->nombre);  inOrden(abb->der);  } } 

Tipos de árboles binarios de búsqueda

Hay varios tipos de árboles binarios de búsqueda. Los árboles AVL, árbol rojo-negro, son árboles autobalanceables . Los árbol biselado son árboles también autobalanceables con la propiedad de que los elementos accedidos recientemente se accederá más rápido en posteriores accesos. En el montículo, como en todos los árboles binarios de búsqueda, cada nodo padre tiene un valor mayor que sus hijos y además es completo, esto es cuando todos los niveles están llenos con excepción del último que puede no estarlo. Por último, en lo montículos con prioridad cada nodo mantiene una prioridad y siempre un nodo padre tendrá una prioridad mayor a la de su hijo.

Otras dos maneras de configurar un árbol binario de búsqueda podría ser como un árbol completo o degenerado.

Un árbol completo es un árbol con "n" niveles, donde cada nivel d <= n-1; el número de nodos existentes en el nivel "d" es igual que 2d. Esto significa que todos los posibles nodos existen en esos niveles, no hay ningún hueco. Un requirimiento adicional para un árbol binario completo es que para el nivel "n", los nodos deben estar ocupados de izquierda a derecha, no pudiendo haber un hueco a la izquierda de un nodo ocupado.

Un árbol degenerativo es un árbol que, para cada nodo padre, solo hay asociado un nodo hijo. Por lo que se comporta como una lista enlazada.

Comparación de rendimiento

D. A. Heger(2004)[1]​ realiza una comparación entre los diferentes tipos de árboles binarios de búsqueda para encontrar que tipo nos daría el mejor rendimiento para cada caso. Los montículos se encuentran como el tipo de árbol binario de búsqueda que mejor resultado promedio da, mientras que los árboles rojo-negro los que menor rendimiento medio nos aporta.

Buscando el Árbol binario de búsqueda óptimo

Si nosotros no tenemos en mente planificar un árbol binario de búsqueda, y sabemos exactamente como de frecuente serán visitados cada elemento podemos construir un árbol binario de búsqueda óptimo con lo que conseguiremos que la media de gasto generado a la hora de buscar un elemento sea minimizado.

Asumiendo que conocemos los elementos y en qué nivel está cada uno, también conocemos la proporción de futuras búsquedas que se harán para encontrar dicho elemento. Si es así, podemos usar una solución basada en la programación dinámica.

En cambio, a veces solo tenemos la estimación de los costes de búsqueda, como pasa con los sistemas que nos muestra el tiempo que ha necesitado para realizar una búsqueda. Un ejemplo, si tenemos un ABB de palabras usado en un corrector ortográfico, deberíamos balancear el árbol basado en la frecuencia que tiene una palabra en el Corpus lingüístico, desplazando palabras como "de" cerca de la raíz y palabras como "vesánico" cerca de las hojas. Un árbol como tal podría ser comparado con los árboles Huffman que tratan de encontrar elementos que son accedidos frecuentemente cerca de la raíz para producir una densa información; de todas maneras, los árboles Huffman solo puede guardar elementos que contienen datos en las hojas y estos elementos no necesitan ser ordenados.

En cambio, si no sabemos la secuencia en la que los elementos del árbol van a ser accedidos, podemos usar árboles biselados que son tan buenos como cualquier árbol de búsqueda que podemos construir para cualquier secuencia en particular de operaciones de búsqueda.

Árboles alfabéticos son árboles Huffman con una restricción de orden adicional, o lo que es lo mismo, árboles de búsqueda con modificación tal que todos los elementos son almacenados en las hojas.

Véase también

Referencias

  1. Heger, Dominique A. (2004), , European Journal for the Informatics Professional 5 (5), archivado desde el original el 27 de marzo de 2014, consultado el 9 de diciembre de 2012 .

Enlaces externos


  •   Datos: Q623818
  •   Multimedia: Binary search trees

Árbol, binario, búsqueda, árbol, binario, búsqueda, también, llamado, acrónimo, inglés, binary, search, tree, tipo, particular, árbol, binario, presenta, estructura, datos, forma, árbol, usada, informática, Índice, descripción, operaciones, búsqueda, inserción. Un arbol binario de busqueda tambien llamado BST acronimo del ingles Binary Search Tree es un tipo particular de arbol binario que presenta una estructura de datos en forma de arbol usada en informatica Indice 1 Descripcion 2 Operaciones 2 1 Busqueda 2 2 Insercion 2 3 Borrado 2 4 Otras Operaciones 2 5 Recorridos 3 Tipos de arboles binarios de busqueda 4 Comparacion de rendimiento 5 Buscando el Arbol binario de busqueda optimo 6 Vease tambien 7 Referencias 8 Enlaces externosDescripcion EditarVeamos la definicion de arbol binario de busqueda Arbol binario de busqueda Sea A un arbol binario de raiz R e hijos izquierdo y derecho posiblemente nulos HI y HD respectivamente Decimos que A es un arbol binario de busqueda ABB si y solo si se satisfacen las dos condiciones al mismo tiempo HI es vacio displaystyle lor R es mayor que todo elemento de HI displaystyle land HI es un ABB HD es vacio displaystyle lor R es menor que todo elemento de HD displaystyle land HD es un ABB Donde displaystyle land es la conjuncion logica y y displaystyle lor es la disyuncion logica o Un arbol binario de busqueda de tamano 9 y profundidad 3 con raiz 8 y hojas 1 4 7 y 13 Para una facil comprension queda resumido en que es un arbol binario que cumple que el subarbol izquierdo de cualquier nodo si no esta vacio contiene valores menores que el que contiene dicho nodo y el subarbol derecho si no esta vacio contiene valores mayores Para estas definiciones se considera que hay una relacion de orden establecida entre los elementos de los nodos Que cierta relacion este definida o no depende de cada lenguaje de programacion De aqui se deduce que puede haber distintos arboles binarios de busqueda para un mismo conjunto de elementos La altura h en el peor de los casos es siempre el mismo tamano que el numero de elementos disponibles Y en el mejor de los casos viene dada por la expresion h log 2 c 1 displaystyle h lceil log 2 c 1 rceil El interes de los arboles binarios de busqueda ABB radica en que su recorrido en in orden proporciona los elementos ordenados de forma ascendente y en que la busqueda de algun elemento suele ser muy eficiente Dependiendo de las necesidades del usuario que trate con una estructura de este tipo se podra permitir la igualdad estricta en alguno en ninguno o en ambos de los subarboles que penden de la raiz Permitir el uso de la igualdad provoca la aparicion de valores dobles y hace la busqueda mas compleja Un arbol binario de busqueda no deja de ser un caso particular de arbol binario asi usando la siguiente especificacion de arbol binario en maude fmod ARBOL BINARIO X TRIV is sorts ArbolBinNV X ArbolBin X subsort ArbolBinNV X lt ArbolBin X generadores op crear gt ArbolBin X ctor op arbolBin X Elt ArbolBin X ArbolBin X gt ArbolBinNV X ctor endfm podemos hacer la siguiente definicion para un arbol binario de busqueda tambien en maude fmod ARBOL BINARIO BUSQUEDA X ORDEN is protecting ARBOL BINARIO VOrden X sorts ABB X ABBNV X subsort ABBNV X lt ABB X subsort ABB X lt ArbolBin VOrden X subsort ABBNV X lt ArbolBinNV VOrden X generadores op crear gt ArbolBin X ctor op arbolBin X Elt ArbolBin X ArbolBin X gt ArbolBinNV X ctor endfm con la siguiente teoria de orden fth ORDEN is protecting BOOL sort Elt operaciones op lt Elt Elt gt Bool endfth para que un arbol binario pertenezca al tipo arbol binario de busqueda debe cumplir la condicion de ordenacion siguiente que iria junto al modulo ARBOL BINARIO BUSQUEDA var R X Elt vars INV DNV ABBNV X vars I D ABB X mb crear ABB X mb arbolBin R crear crear ABBNV X cmb arbolBin R INV crear ABBNV X if R gt max INV cmb arbolBin R crear DNV ABBNV X if R lt min DNV cmb arbolBin R INV DNV ABBNV X if R gt max INV and R lt min DNV ops min max ABBNV X gt X Elt eq min arbolBin R crear D R eq min arbolBin R INV D min INV eq max arbolBin R I crear R eq max arbolBin R I DNV max DNV class nodo izq der dato None None 0 def init self dato crea un nodo self izq None self der None self dato dato class arbolBinario def init self inicializa la raiz self raiz None def agregarNodo self dato crea un nuevo nodo y lo devuelve return nodo dato def insertar self raiz dato inserta un dato nuevo en el arbol if raiz None si no hay nodos en el arbol lo agrega return self agregarNodo dato else si hay nodos en el arbol lo recorre if dato lt raiz dato si el dato ingresado es menor que el dato guardado va al subarbol izquierdo raiz izq self insertar raiz izq dato else si no procesa el subarbol derecho raiz der self insertar raiz der dato return raizOperaciones EditarTodas las operaciones realizadas sobre arboles binarios de busqueda estan basadas en la comparacion de los elementos o clave de los mismos por lo que es necesaria una subrutina que puede estar predefinida en el lenguaje de programacion que los compare y pueda establecer una relacion de orden entre ellos es decir que dados dos elementos sea capaz de reconocer cual es mayor y cual menor Se habla de clave de un elemento porque en la mayoria de los casos el contenido de los nodos sera otro tipo de estructura y es necesario que la comparacion se haga sobre algun campo al que se denomina clave Busqueda Editar La busqueda en un arbol binario de busqueda consiste en acceder a la raiz del arbol si el elemento a localizar coincide con este la busqueda ha concluido con exito si el elemento es menor se busca en el subarbol izquierdo y si es mayor en el derecho Si se alcanza un nodo hoja y el elemento no ha sido encontrado es que no existe en el arbol Cabe destacar que la busqueda en este tipo de arboles es muy eficiente representa una funcion logaritmica El maximo numero de comparaciones que necesitariamos para saber si un elemento se encuentra en un arbol binario de busqueda estaria entre log2 N 1 y N siendo N el numero de nodos La busqueda de un elemento en un ABB Arbol Binario de Busqueda se puede realizar de dos formas iterativa o recursiva Ejemplo de version iterativa en el lenguaje de programacion C suponiendo que estamos buscando una clave alojada en un nodo donde esta el correspondiente dato que precisamos encontrar data Buscar ABB abb t clave k abb p dato e e NULL p t if estaVacio p while estaVacio p amp amp p gt k k if k lt p gt k p p gt l if p gt k lt k p p gt r if estaVacio p amp amp p gt d NULL e copiaDato p gt d return e Vease ahora la version recursiva en ese mismo lenguaje int buscar tArbol a int elem if a NULL return 0 else if a gt clave lt elem return buscar a gt hDerecho elem else if a gt clave gt elem return buscar a gt hIzquierdo elem else return 1 Otro ejemplo en Python def buscar raiz clave busca el valor clave dentro del arbol if raiz None print No se encuentra else if clave raiz dato print El valor clave se encuentra en el ABB elif clave lt raiz dato lado izquierdo return buscar raiz izq clave else lado derecho return buscar raiz der clave En Pascal Function busqueda T ABR y integer ABR begin if T nil or T raiz y then busqueda T else if T raiz lt y then busqueda busqueda T dch y else busqueda busqueda T izq y end Una especificacion en maude para la operacion de busqueda quedaria de la siguiente forma op esta X Elt ABB X gt Bool var R R1 R2 X Elt vars I D ABB X eq esta R crear false eq esta R1 arbolBin R2 I D if R1 R2 then true else if R1 lt R2 then esta R1 I else esta R1 D fi fi Insercion Editar La insercion es similar a la busqueda y se puede dar una solucion tanto iterativa como recursiva Si tenemos inicialmente como parametro un arbol vacio se crea un nuevo nodo como unico contenido el elemento a insertar Si no lo esta se comprueba si el elemento dado es menor que la raiz del arbol inicial con lo que se inserta en el subarbol izquierdo y si es mayor se inserta en el subarbol derecho Evolucion de la insercion del elemento 5 en un ABB Como en el caso de la busqueda puede haber varias variantes a la hora de implementar la insercion en el TAD Tipo Abstracto de Datos y es la decision a tomar cuando el elemento o clave del elemento a insertar ya se encuentra en el arbol puede que este sea modificado o que sea ignorada la insercion Es obvio que esta operacion modifica el ABB perdiendo la version anterior del mismo A continuacion se muestran las dos versiones del algoritmo en pseudolenguaje iterativa y recursiva respectivamente PROC InsertarABB arbol TABB dato TElemento VARIABLES nuevonodo pav pret TABB clavenueva Tclave ele TElemento INICIO nuevonodo lt NUEVO TNodoABB nuevonodo izq lt NULO nuevonodo der lt NULO nuevonodo elem lt dato SI ABBVacio arbol ENTONCES arbol lt nuevonodo ENOTROCASO clavenueva lt dato clave pav lt arbol Puntero Avanzado pret lt NULO Puntero Retrasado MIENTRAS pav lt NULO HACER pret lt pav ele pav elem SI clavenueva lt ele clave ENTONCES pav lt pav izq EN OTRO CASO pav lt pav dch FINSI FINMIENTRAS ele pret elem SI clavenueva lt ele clave ENTONCES pret izq lt nuevonodo EN OTRO CASO pret dch lt nuevonodo FINSI FINSI FIN PROC InsertarABB arbol TABB dato TElemento VARIABLES ele TElemento INICIO SI ABBVacio arbol ENTONCES arbol lt NUEVO TNodoABB arbol izq lt NULO arbol der lt NULO arbol elem lt dato EN OTRO CASO ele InfoABB arbol SI dato clave lt ele clave ENTONCES InsertarABB arbol izq dato EN OTRO CASO InsertarABB arbol dch dato FINSI FINSI FIN Se ha podido apreciar la simplicidad que ofrece la version recursiva este algoritmo es la traduccion en C El arbol es pasado por referencia para que los nuevos enlaces a los subarboles mantengan la coherencia void insertar tArbol a int elem if a NULL a tArbol malloc sizeof tArbol a gt clave elem a gt hIzquierdo NULL a gt hDerecho NULL else if a gt clave lt elem insertar amp a gt hDerecho elem else if a gt clave gt elem insertar amp a gt hIzquierdo elem En Python el mecanismo de insercion se define por ejemplo dentro de la clase que defina el ABB ver mas arriba Otro ejemplo en Pascal Procedure Insercion var T ABR y integer var ultimo ABR actual ABR nuevo ABR begin ultimo nil actual T while actual lt gt nil do begin ultimo actual if actual raiz lt y then actual actual dch else actual actual izq end new nuevo nuevo raiz y nuevo izq nil nuevo dch nil if ultimo nil then T nuevo else if ultimo raiz lt y then ultimo dch nuevo else ultimo izq nuevo end Vease tambien un ejemplo de algoritmo recursivo de insercion en un ABB en el lenguaje de programacion Maude op insertar X Elt ABB X gt ABBNV X var R R1 R2 X Elt vars I D ABB X eq insertar R crear arbolBin R crear crear eq insertar R1 arbolBin R2 I D if R1 lt R2 then arbolBin R2 insertar R1 I D else arbolBin R2 I insertar R1 D fi La operacion de insercion requiere en el peor de los casos un tiempo proporcional a la altura del arbol Borrado Editar La operacion de borrado no es tan sencilla como las de busqueda e insercion Existen varios casos a tener en consideracion Borrar un nodo sin hijos o nodo hoja simplemente se borra y se establece a nulo el apuntador de su padre Borrar un nodo con un subarbol hijo se borra el nodo y se asigna su subarbol hijo como subarbol de su padre Borrar un nodo con dos subarboles hijo la solucion esta en reemplazar el valor del nodo por el de su predecesor o por el de su sucesor en inorden y posteriormente borrar este nodo Su predecesor en inorden sera el nodo mas a la derecha de su subarbol izquierdo mayor nodo del subarbol izquierdo y su sucesor el nodo mas a la izquierda de su subarbol derecho menor nodo del subarbol derecho En la siguiente figura se muestra como existe la posibilidad de realizar cualquiera de ambos reemplazos El siguiente algoritmo en C realiza el borrado en un ABB El procedimiento reemplazar busca la mayor clave del subarbol izquierdo y la asigna al nodo a eliminar void reemplazar tArbol a tArbol aux Prototipo de la funcion reemplazar void borrar tArbol a int elem tArbol aux if a NULL return if a gt clave lt elem borrar amp a gt hDerecho elem else if a gt clave gt elem borrar amp a gt hIzquierdo elem else if a gt clave elem aux a if a gt hIzquierdo NULL a a gt hDerecho else if a gt hDerecho NULL a a gt hIzquierdo else reemplazar amp a gt hIzquierdo amp aux free aux void reemplazar tArbol a tArbol aux if a gt hDerecho NULL aux gt clave a gt clave aux a a a gt hIzquierdo else reemplazar amp a gt hDerecho aux Otro ejemplo en Pascal Procedure Borrar var T ABR x ABR var aBorrar ABR anterior ABR actual ABR hijo ABR begin if x izq nil or x dch nil then aBorrar x else aBorrar sucesor T x actual T anterior nil while actual lt gt aBorrar do begin anterior actual if actual raiz lt aBorrar raiz then actual actual dch else actual actual izq end if actual izq nil then hijo actual dch else hijo actual izq if anterior nil then T hijo else if anterior raiz lt actual raiz then anterior dch hijo else anterior izq hijo if aBorrar lt gt x then x raiz aBorrar raiz free aBorrar end Vease tambien un ejemplo de algoritmo recursivo de borrado en un ABB en el lenguaje de programacion Maude considerando los generadores crear y arbolBin Esta especificacion hace uso de la componente clave a partir de la cual se ordena el arbol op eliminar X Elt ABB X gt ABB X varS R M X Elt vars I D ABB X vars INV DNV ABBNV X ops max min ArbolBin X gt X Elt eq min arbolBin R crear D R eq max arbolBin R I crear R eq min arbolBin R INV D min INV eq max arbolBin R I DNV max DNV eq eliminar M crear crear ceq eliminar M arbolBin R crear D D if M clave R ceq eliminar M arbolBin R I crear I if M clave R ceq eliminar M arbolBin R INV DNV arbolBin max INV eliminar clave max INV INV DNV if M clave R ceq eliminar M arbolBin R I D arbolBin R eliminar M I D if M lt clave R ceq eliminar M arbolBin R I D arbolBin R I eliminar M D if clave R lt M Otras Operaciones Editar Otra operacion seria por ejemplo comprobar que un arbol binario es un arbol binario de busqueda Su implementacion en maude es la siguiente op esABB ABB X gt Bool var R X Elt vars I D ABB X eq esABB crear true eq esABB arbolbBin R I D Max I lt R and Min D gt R and esABB I and esABB D Recorridos Editar Se puede hacer un recorrido de un arbol en profundidad o en anchura Los recorridos en anchura son por niveles se realiza horizontalmente desde la raiz a todos los hijos antes de pasar a la descendencia de alguno de los hijos El coste de recorrer el ABB es O n ya que se necesitan visitar todos los vertices El recorrido en profundidad lleva al camino desde la raiz hacia el descendiente mas lejano del primer hijo y luego continua con el siguiente hijo Como recorridos en profundidad tenemos inorden preorden y postorden Una propiedad de los ABB es que al hacer un recorrido en profundidad inorden obtenemos los elementos ordenados de forma ascendente Resultado de hacer el recorrido en Inorden 6 9 13 14 15 17 20 26 64 72 Preorden 15 9 6 14 13 20 17 64 26 72 Postorden 6 13 14 9 17 26 72 64 20 15 Recorridos en Visual Basic Net funcion de recorrido en PREORDEN Public Function preorden As String cadenasalida rePreorden raiz Return cadenasalida End Function Private Sub rePreorden ByVal padre As Nodo If IsNothing padre Then Return End If cadenasalida cadenasalida amp amp padre dato rePreorden padre ant rePreorden padre sig End Sub funcion de recorrido en POSTORDEN Public Function postorden As String cadenasalida repostorden raiz Return cadenasalida End Function Private Sub repostorden ByVal padre As Nodo If IsNothing padre Then Return End If repostorden padre ant repostorden padre sig cadenasalida cadenasalida amp amp padre dato End Sub funcion de recorrido en ENORDEN Public Function inorden As String cadenasalida reinorden raiz Return cadenasalida End Function Private Sub reinorden ByVal padre As Nodo If IsNothing padre Then Return End If reinorden padre ant cadenasalida cadenasalida amp amp padre dato reinorden padre sig End Sub Recorridos en C con funciones recursivas struct Nodo char nombre 30 struct Nodo izq struct Nodo der typedef struct Nodo Nodo typedef Nodo Arbol void preOrden Arbol abb if abb printf s n abb gt nombre preOrden abb gt izq preOrden abb gt der void postOrden Arbol abb if abb postOrden abb gt izq postOrden abb gt der printf s n abb gt nombre void inOrden Arbol abb if abb inOrden abb gt izq printf s n abb gt nombre inOrden abb gt der Tipos de arboles binarios de busqueda EditarHay varios tipos de arboles binarios de busqueda Los arboles AVL arbol rojo negro son arboles autobalanceables Los arbol biselado son arboles tambien autobalanceables con la propiedad de que los elementos accedidos recientemente se accedera mas rapido en posteriores accesos En el monticulo como en todos los arboles binarios de busqueda cada nodo padre tiene un valor mayor que sus hijos y ademas es completo esto es cuando todos los niveles estan llenos con excepcion del ultimo que puede no estarlo Por ultimo en lo monticulos con prioridad cada nodo mantiene una prioridad y siempre un nodo padre tendra una prioridad mayor a la de su hijo Otras dos maneras de configurar un arbol binario de busqueda podria ser como un arbol completo o degenerado Un arbol completo es un arbol con n niveles donde cada nivel d lt n 1 el numero de nodos existentes en el nivel d es igual que 2d Esto significa que todos los posibles nodos existen en esos niveles no hay ningun hueco Un requirimiento adicional para un arbol binario completo es que para el nivel n los nodos deben estar ocupados de izquierda a derecha no pudiendo haber un hueco a la izquierda de un nodo ocupado Un arbol degenerativo es un arbol que para cada nodo padre solo hay asociado un nodo hijo Por lo que se comporta como una lista enlazada Comparacion de rendimiento EditarD A Heger 2004 1 realiza una comparacion entre los diferentes tipos de arboles binarios de busqueda para encontrar que tipo nos daria el mejor rendimiento para cada caso Los monticulos se encuentran como el tipo de arbol binario de busqueda que mejor resultado promedio da mientras que los arboles rojo negro los que menor rendimiento medio nos aporta Buscando el Arbol binario de busqueda optimo EditarSi nosotros no tenemos en mente planificar un arbol binario de busqueda y sabemos exactamente como de frecuente seran visitados cada elemento podemos construir un arbol binario de busqueda optimo con lo que conseguiremos que la media de gasto generado a la hora de buscar un elemento sea minimizado Asumiendo que conocemos los elementos y en que nivel esta cada uno tambien conocemos la proporcion de futuras busquedas que se haran para encontrar dicho elemento Si es asi podemos usar una solucion basada en la programacion dinamica En cambio a veces solo tenemos la estimacion de los costes de busqueda como pasa con los sistemas que nos muestra el tiempo que ha necesitado para realizar una busqueda Un ejemplo si tenemos un ABB de palabras usado en un corrector ortografico deberiamos balancear el arbol basado en la frecuencia que tiene una palabra en el Corpus linguistico desplazando palabras como de cerca de la raiz y palabras como vesanico cerca de las hojas Un arbol como tal podria ser comparado con los arboles Huffman que tratan de encontrar elementos que son accedidos frecuentemente cerca de la raiz para producir una densa informacion de todas maneras los arboles Huffman solo puede guardar elementos que contienen datos en las hojas y estos elementos no necesitan ser ordenados En cambio si no sabemos la secuencia en la que los elementos del arbol van a ser accedidos podemos usar arboles biselados que son tan buenos como cualquier arbol de busqueda que podemos construir para cualquier secuencia en particular de operaciones de busqueda Arboles alfabeticos son arboles Huffman con una restriccion de orden adicional o lo que es lo mismo arboles de busqueda con modificacion tal que todos los elementos son almacenados en las hojas Vease tambien EditarArbol programacion Arbol Binario Arbol AVL Arbol 2 3 Arbol B Arbol Rojo Negro Arbol Splay Arbol MultirramaReferencias Editar Heger Dominique A 2004 A Disquisition on The Performance Behavior of Binary Search Tree Data Structures European Journal for the Informatics Professional 5 5 archivado desde el original el 27 de marzo de 2014 consultado el 9 de diciembre de 2012 Enlaces externos EditarArboles binarios de busqueda en Google Aplicacion JAVA de arboles Datos Q623818 Multimedia Binary search trees Obtenido de https es wikipedia org w index php title Arbol binario de busqueda amp oldid 125248579, wikipedia, wiki, leyendo, leer, libro, biblioteca,

español

, española, descargar, gratis, descargar gratis, mp3, video, mp4, 3gp, jpg, jpeg, gif, png, imagen, música, canción, película, libro, juego, juegos