Está en la página 1de 16

Árboles de Búsqueda Binaria

Agustín J. González
ELO-320: Estructura de Datos y Algoritmos

1
Introducción
 Los árboles de búsqueda son estructuras de datos que soportan
las siguientes operaciones de conjuntos dinámicos:
Search -Búsqueda-, Minimum, Maximum, Predecessor, Successor,
Insert, y Delete.
 Los árboles de búsqueda se pueden utilizar como diccionarios y
como colas de prioridad.
 Estas operaciones toman un tiempo proporcional a la altura del
árbol.
 Para un árbol completo binario esto es (lg n) en el peor caso; sin
embargo, si el árbol es una cadena lineal de n nodos, las mismas
operaciones toman (n) en el peor caso.
 Para árboles creados aleatoriamente, la altura es O(lg n), con lo
cual los tiempos son (lg n).
 Hay varios esquemas para mejorar el peor caso de los árboles de
búsqueda. Dos de ellos son los árboles 2-3 y los árboles rojo-
negro. 2
Propiedad de un árbol búsqueda binaria
 Sea x un nodo en un árbol de x
búsqueda binaria. Si y es un nodo
del sub-árbol izquierdo de x, y z
entonces se cumple: (clave de y)
 (clave de x). Si z es un nodo del y z
sub-árbol dercho de x, entonces la x x
se cumple (clave de x)  (clave de
z). 2
5 3
 Por ejemplo, dos árboles de
búsqueda binaria son:
3 7 7

2 8 5 8
5
 La propiedad de árbol nos permite 5
recorrer o imprimir sus nodos en
el orden de sus claves haciendo
uso de un simple algoritmo
recursivo. 3
Recorrido Inorder de un árbol búsqueda
binaria
 Suponiendo una estructura como la vista antes para árboles binarios, tenemos:
 typedef struct arbol_tag {
struct arbol_tag * p;
struct arbol_tag * left;
struct arbol_tab * right;
elementType element;
} TREE_NODE;
 void Inorder_Tree_Walk( TREE_NODE * x) {
if (x != NULL) {
Inorder_Tree_Walk(x->left);
Print(x->element); /* podría ser procesar elemento*/
Inorder_Tree_Walk(x->right);
}
}
 Este algoritmo toma tiempo (n) porque el procedimiento es llamado exactamente
dos veces por cada nodo.
 Análogamente se definen recorridos preorder y postorder del árbol. El único cambio
es el lugar de la instrucción de procesamiento del nodo. En preorder, el nodo se
procesa primero y en postorder se procesa después.
4
Recorrido Pre y port-order de un árbol
búsqueda binaria
 void Preorder_Tree_Walk( TREE_NODE * x) {
if (x != NULL) {
Print(x->element); /* podría ser procesar elemento*/
Preorder_Tree_Walk(x->left);
Preorder_Tree_Walk(x->right);
}
}
 void Postorder_Tree_Walk( TREE_NODE * x) {
if (x != NULL) {
Postorder_Tree_Walk(x->left);
Postorder_Tree_Walk(x->right);
Print(x->element); /* podría ser procesar elemento*/
}
}
 El recorrido del árbol con los algoritmos previos daría: 5
 Preorder: 5, 3, 2, 5, 7, 8 3 7
 Inorder: 2, 3, 5, 5, 7, 8
 Postorder: 2, 5, 3, 8, 7, 5 2 5 8 5
Otras operaciones en un árbol de
búsqueda binaria
 Búsqueda de una clave determinada:
TREE_NODE * Tree_Search( TREE_NODE * x, elementType k) {
if (x == NULL) return x;
else if (x->element == k ) /* Ojo: esta comparación podría ser
una función*/
return x;
else if (k < x->element)
return Tree_Search( x->left, k);
else
return Tree_Search( x->right, k);
}
 El tiempo de este algoritmo es O(h) donde h es la altura del árbol.
 Este procedimiento se puede “desenrollar” para eliminar el tiempo de
múltiples llamados a la misma función. Ver -->

6
Otras operaciones en un árbol de
búsqueda binaria
 Búsqueda de una clave determinada:

 TREE_NODE * Tree_Search( TREE_NODE * x, elementType k) {


while(x != NULL)
if (x->element == k )
return x;
else if (k < x->element)
x = x->left;
else
x= x->right;
return x;
}

7
Máximo y Mínimo en un árbol de
búsqueda binaria
 TREE_NODE * Tree_Maximum( TREE_NODE * x) {
if (x == NULL) return x;
while (x->right != NULL )
x = x->right;
return x;
}

 TREE_NODE * Tree_Minimum( TREE_NODE * x) {


if (x == NULL) return x;
while (x->left != NULL )
x = x->left;
return x;
}
8
Sucesor y Antecesor en un árbol de
búsqueda binaria
 TREE_NODE * Tree_Successor( TREE_NODE * x) {
TREE_NODE * y;
if (x == NULL) return x;
if (x->right != NULL)
return Tree_Minimum(x->right);
y = x->p;
while ( y != NULL )
if (x == y->right) {
x = y;
y = y->p;
}
else break;
return y;
}

9
Sucesor y Antecesor en un árbol de
búsqueda binaria
 TREE_NODE * Tree_Predecessor( TREE_NODE * x) {
TREE_NODE * y;
if (x == NULL) return x;
if (x->left != NULL)
return Tree_Maximum(x->left);
y = x->p;
while ( y != NULL )
if (x == y->left) {
x = y;
y = y->p;
}
else break;
return y;
}

10
Inserción en un árbol de búsqueda binaria
 Suponemos inicialmente que z->left = z->right = NULL.
 Void Tree_Insert( TREE_NODE ** T, TREE_NODE * z) {
TREE_NODE *y, *x;
y=NULL;
x = *T;
while (x != NULL) { /* buscamos quien debe ser su padre */
y = x;
if ( z->element < x->element)
x = x->left;
else
x= x->right;
}
z->p = y;
if (y == NULL) /* se trata del primer nodo */
*T = z;
else if (z->element < y->element)
y->left = z;
else
y->right = z;
}
 Como el procedimiento de búsqueda, este algoritmo toma un tiempo O(h), h es la
altura del árbol. 11
Eliminación en un árbol de búsqueda
binaria
 Como entrada disponemos de z,
un puntero al nodo a remover. 1)
 Hay tres casos a considerar: 15 15
 1.- Que *z sea un nodo hoja. 5 16 5 16
En este caso se elimina 3 12 20 3 12 20
fácilmente. 10 13
z
18 23 10 18 23
 2.- Que *z sea un nodo sin 6 6
hijo izquierdo o derecho. En 7 7
este caso, su único sub-árbol 2)
sube para toma el lugar de 15 15
z
*z. 5 16 5 20
3 3
 3.-*z posee dos sub-árboles. 12 20 12 18 23
En este caso, su sucesor no 10 13 18 23 10 13
posee hijo izquierdo, luego 6 6
éste puede ser movido desde 7 7
su posición a la de *z. 12
Eliminación tercer caso
 Caso 3)
z 15 15
z
5 16 5 16
3 12 20 3 12 20
10 13 18 23 10 13 18 23
6 6
7 7

z 15 15
5 16 6 16
3 6 12 20 3 12 20
10 13 18 23 10 13 18 23
7 7

13
Eliminación: Algoritmo
 TREE_NODE * Tree-Delete(TREE_NODE **T, TREE_NODE * z) {
TREE:_NODE * x;
if (z->left == NULL || z->right == NULL)
y = z; /* caso 1 y 2 */
else
y = Tree_Successor(z); /* caso 3 */
/* hasta aquí y es un nodo con menos de dos hijos y debe ser extraído del árbol*/
if (y->left != NULL)
x = y->left;
else
x = y->right;
if (x != NULL) x->p = y->p;
if (y->p == NULL) /* estoy eliminado el último nodo */
*T = x;
else if (y == y->p->left) /* y es hijo izquierdo */
y->p->left = x;
else
y->p->right = x;
if (y !=z) /* caso 3 */
z->element = y->element;
return y;
} 14
Ejercicio:
 Proponga un algoritmo codificado en C o pseudo lenguaje que
reciba como entrada un puntero a la raíz de un árbol binario y
retorne su altura. (Ayuda: observe que la altura de un nodo es uno
más que la altura mayor de sus hijos)
Sea la siguiente estructura para cada nodo del árbol:
typedef struct nodo_arbol {
struct nodo_arbol * p; /* puntero al padre */
struct nodo_arbol * left; /* hijo izquierdo */
struct nodo_arbol * right; /* hijo derecho*/
ELEMENTO elemento;
} NODO_ARBOL;
int Altura (NODO_ARBOL * T) {
int le, ri;
if (T==NULL) return -1; /* en realidad no está definida la
altura en este caso (por observación de Manuel Jander 2003)*/
le = Altura(T->left);
ri = Altura(T->right);
if (le > ri) return(le+1);
else return (ri+1);
15
}
Divertimento
 Antes de que pasara lo que pasara (lo que todos
sabemos que pasó), los hijos de Adán y Eva estaban
muy unidos.
 Si Abel iba a la fiesta, Set también iba. Si Set no iba a
la fiesta, Caín tampoco. Al menos uno de los tres fue a
la fiesta.

 ¿Quién es el que fue?

Gentileza de (Orlando Pinto)

16

También podría gustarte