Post on 13-Jul-2015
Existe un problema con los arboles
binarios….
• El recorrido con recursivo de los árboles resulta costoso, ya que implica un gasto adicional: Memoria
Tiempo de ejecución
• Esto puede provocar, en el caso de un árbol muy grande, que el stack del sistema se desborde rápidamente.
• Es posible recorrer los árboles de manera iterativa, en lugar de recursiva, pero para esto ocupamos una estructura de tipo PILA.
• En un árbol binario hay más punteros NULL que punteros a nodos.
• Un árbol hilvanado utiliza los punteros nulos para poder conseguir ciertas ventajas.
• A esos punteros nulos, los llamaremos HEBRAS o HILOS, para diferenciarlos de los punteros no nulos.
• Existen varias formas de enhebrado. Veremos el entreorden. (De hecho, la definición de árbol hilvanado que veremos, estará basada en este tipo de recorrido)
Definición
• Es un árbol binario en el que cada hijo izquierdo de valor nulo es sustituido por un enlace al nodo que le antecede en entreorden (excepto el primer nodo) …. Esto es un árbol hilvanado por la izquierda.
• Es un árbol binario en el que cada hijo derecho de valor nulo es sustituido por un enlace al nodo que le sigue en el recorrido en entreorden (excepto el último nodo) …. Esto es un árbol hilvanado por la derecha.
Nodo tipo para árbol hilvanado por la
derecha…
struct nodo {
int info;
struct nodo *left;
struct nodo *right;
int rthread; //1 – Es Hilo, 0 – no Hilo
}
Construcción de los hilos
• Un NULL en un enlace derecho de un nodo p se reemplaza por un puntero al nodo que se visitaría después de p en un recorrido en entreorden. (sucesor)
• Un NULL en un enlace izquierdo de un nodo p se reemplaza por un puntero al nodo que se visitaría antes de p en un recorrido en entreorden. (predecesor)
Recorrer un árbol hilvanado a la
derecha• Iniciamos en el nodo más a la izquierda del árbol, lo
procesamos, y seguimos hacia su hilo derecho.
• Si seguimos hacia el hilo derecho, procesamos el nodo y continuamos hacia el vinculo a su derecha.
• Si seguimos a un vinculo a la derecha, nos movemos hacia el nodo más hacia la izquierda, procesamos el nodo y continuamos con la lógica.
8
75
3
11
13
1
6
9
Seguimos el vinculo a la derecha, nos movemos al nodo más a la izquierda y lo procesamos.
Salida135
Ejemplo
8
75
3
11
13
1
6
9
Salida13567
Ejemplo
Seguimos el vinculo a la derecha, nos movemos al nodo más a la izquierda y lo procesamos.
8
75
3
11
13
1
6
9
Salida1356789
Ejemplo
Seguimos el vinculo a la derecha, nos movemos al nodo más a la izquierda y lo procesamos.
8
75
3
11
13
1
6
9
Salida13567891113
Ejemplo
Seguimos el vinculo a la derecha, nos movemos al nodo más a la izquierda y lo procesamos.
Node leftMost(Node n) {Node ans = n;if (ans == null) {
return null;}while (ans.left != null) {
ans = ans.left;}return ans;
}
void inOrder(Node n) {Node cur = leftmost(n);while (cur != null) {
print(cur);if (cur. rthread == 1){
cur = cur.right;} else {
cur = leftmost(cur.right);}
}}
Que modificación le podemos hacer a
este árbol??
• Todavía estamos desperdiciando punteros, la mitad de nuestros punteros hoja siguen siendo nulos.
• Podemos agregar hilos a los nodos previos en un recorrido entreorden, lo cual nos va a permitir hacer recorridos hacia atras o incluso hacer recorridos en postorden.
Ventajas
• Mejorar el aprovechamiento de la memoria.
• Los hilos evitan el uso de recursividad y de pilas.
• Recorrido entreorden más rápido.
• Determinación del predecesor y sucesor entreorden muy simple y eficiente.
• Mediante otro tipo de hilvanado se pueden conseguir los mismos resultados para otros recorridos.