Está en la página 1de 33

TDA DICCIONARIO

Karim Guevara Puente de la Vega


Índice

 Árbol binario de búsqueda


 TDA Diccionario
 Implementaciones sencillas
 Implementación del TDA Diccionario
Arboles

 Un árbol es una estructura de datos jerárquica


 Se define como una colección de nodos organizados en forma
recursiva.
 Árbol vacío: 0 nodos
 Hojas; nodos sin hijos
Arboles

 Camino de n1 y nk : secuencia de nodos n1, n2, ..., nk tal que ni es padre de ni+1,
para 1 <= i < k.
 largo del camino: número de referencias que componen el camino
 Ancestro: un nodo n es ancestro de un nodo m si existe un camino desde n a m;
 Descendiente: un nodo n es descendiente de un nodo m si existe un camino
desde m a n.
 Profundidad del nodo nk : largo del camino entre la raíz y el nodo nk.
 Profundidad de la raíz es 0.
 Altura de un nodo nk : máximo largo de camino desde nk hasta alguna hoja.
 Altura de toda hoja es 0.
 Altura de un árbol = Altura de la raíz
 Altura de un árbol vacío = -1.
Arboles
 A es la raíz del árbol.
 A es padre de B, C y D.
 E y F son hermanos, puesto que ambos son hijos de B.
 E, J, K, L, C, P, Q, H, N y O son las hojas del árbol.
 El camino desde A a J es único, lo conforman los nodos
A-B-F-J y es de largo 3.
 D es ancestro de P, y por lo tanto P es descendiente de
D.
 L no es descendiente de C, puesto que no existe un
camino desde C a L.
 La profundidad de C es 1, de F es 2 y de Q es 4.
 La altura de C es 0, de F es 1 y de D es 3.
 La altura del árbol es 4 (largo del camino entre la raíz A y
la hoja más profunda, P o Q).
Arboles Binarios

 Un árbol binario es un árbol en donde cada nodo posee 2 referencias


a subárboles (ni más, ni menos).
 Subárbol izquierdo y derecho

class NodoArbolBinario<T> {
T elemento;
NodoArbolBinario<T> izq;
NodoArbolBinario<T> der;
}
Arboles Binarios

 Nodos internos: nodos que conforman un árbol binario


 Nodos externos: referencias que son null
Arboles de expresiones matemáticas

 Es un árbol binario
 Las hojas corresponden a los operandos de la expresión (variables o
constantes),
 Los nodos restantes contienen operadores.
Recorridos del BT

 Existen tres formas principales para recorrer un árbol binario en


forma recursiva.:
 Preorden: raíz - subárbol izquierdo - subárbol derecho.
*+ab-cd
 Inorden: subárbol izquierdo - raíz - subárbol derecho.
a+b*c-d
 Postorden: subárbol izquierdo - subárbol derecho - raíz. (Notación polaca)
ab+cd-*
Árboles de Búsqueda Binaria - BST

 Un árbol de búsqueda binaria es un árbol binario en donde todos


los nodos cumplen la siguiente propiedad si el valor almacenado en
un nodo N es X:
 Los datos almacenados en nodos del subárbol izquierdo de N son menores
que X
 Los datos almacenados en los nodos del subárbol derecho de N son mayores
que X
Coste de la búsqueda: esfuerzo medio de comparación

 P.e.:

eMC = (1 * (1+0) + 2 * (1+1) + 2 * (1+2) + 1 * (1+3) ) / 6

= (1+ 4´+ 6 + 4) / 6 = 2.5

En promedio harán falta 2.5 comparaciones para encontrar un dato en este árbol.
Coste de la búsqueda: esfuerzo de comparación

 Esfuerzo de comparación: número de comparaciones necesarias para encontrar


un dato determinado.

 P.e.:
 Buscar(7)  1 comparación
 Buscar(2)  2 comparación
 Buscar(5)  3 comparación
 Buscar(3)  4 comparación

Esfuerzo de comparación(x) = 1 + nivel(x)


Relación entre el equilibrado y el eMC en un BST

 P.e.: inicializar un BST con las secuencias {7, 2, 9, 1, 5, 3}, {5, 7, 2, 9, 1, 3} y


{1, 2, 3, 5, 7, 9}

 Cuándo más equilibrado esté el BST, menor será su altura, su esfuerzo


Medio de Comparación y el coste de sus operaciones.
Costo medio de las operaciones

 Cuándo el BST no está equilibrado (caso peor) los costes son lineales
Implementación: clase NodeBST

class NodeBST<E> {
private E data;
private NodeBST<E> left;
private NodeBST<E> right;

// Constructores
NodeBST(E data, NodeBST<E> left, NodeBST<E> right){
this.data = data;
this.left = left;
this.right = right;
}
NodeBST(E data){
this(data,null, null);
}
// getters, setters
}
Operaciones que nos interesan en la clase BST
Operaciones de búsqueda: Consultores:
 E recover(E x) throws ItemNotFound  int height()
 E minRecover()  boolean isEmpty()
Operaciones de inserción:  double eMC()
 void insertDuplicates(E x)
 void insert(E x) throws ItemDuplicated Operaciones de recorrido:
 void update(E x, E nuevo)  String preOrder()
Operaciones de eliminación:  String postOrder()
 void remove(E x) throws ItemNotFound  String inOrder()
 void minRemove()  String toLevels()
Implementación: clase BST

public class BST <E extends Comparable<E>> {


// Atributos
protected NodeBST<E> root; nodo raíz del árbol

// Constructores de un ABB vacio


public BST(){
root = null;
}
}
Implementación: operaciones de búsqueda

public E recover(E x) throws ItemNotFound {


NodeBST<E> res = recover(x, root);
if(res == null)
throw new ItemNotFound ("El dato "+ x + "no esta");
return res.data;
}
protected NodeBST<E> recover(E x, NodeBST<E> n){
if (n == null) return null;
else {
int resC = n.data.compareTo(x);
if (resC < 0) return recover(x, n.right);
else if (resC > 0) return recover(x, n.left);
else return n;
}
}
Traza del método recover
 Llamada inicial (buscamos el dato x=5)
res = recover(x, root);

recover(5, 7 );
resC > 0
return recover(5, 7 .left)
5
recover(5, 2 );
resC < 0
return recover(5, 2 .right)
5

recover(5, 5 );
resC == 0
return 5
5

return 5 .dato;
Implementación: operaciones de inserción
public void insert(E x) throws ItemDuplicated {
root = insert(x, root);
}
protected NodeBST<E> insert(E x, NodeBST<E> actual)
throws ItemDuplicated {
NodeBST<E> res = actual;
if (actual == null) { res = new NodeBST<E>(x); }
else { //buscamos el lugar para inserción
int resC = actual.data.compareTo(x);
if (resC == 0 ) throw new ItemDuplicated(x + "esta duplcado");
if (resC < 0) res.right = insert(x, actual.right);
else
res.left = insert(x, actual.left);
}
return res;
}
Traza del método insert
Llamada inicial (insertamos el dato x=6)
root = insert(x, root),

insert(6, 7 );
resC > 0
7 .left = insert(6, 7 .left)
return 7
7 insert(6, 2 );
resC < 0
2 .right = insert(6, 2 .right)
return 2
2 insert(6, 5 );
resC < 0
5 .right = insert(6, 5 .right)
return 5
5 insert(6,NULL);
return 6
6
Implementación: operaciones de eliminación
//SII !isEmpty(): método para eliminar el minimo
public E minRemove() {
E min = minRecover();
this.root = minRemove(this.root);
return min;
}

protected NodeBST<E> minRemove(NodeBST<E> actual) {


if (actual.left != null) { //buscamos el minimo
actual.left = minRemove(actual.left);
}
else { //eliminamos el minimo
actual = actual.right;
}
return actual;
}
Traza del método minRemove
Llamada inicial
root = minRemove(root),

minRemove( 7 );
7 .left = minRemove( 7 .left)
7 return 7
minRemove( 4 );
4 .left = minRemove( 4 .left)
4 return 4
minRemove( 1 );
1 .left == null
return 1 .right
3
Implementación: operaciones de eliminación
public void remove(E x) throws ItemNotFound {
this.root = remove(x, this.root);
}
protected NodeBST<E> remove(E x, NodeBST<E> actual) throws ItemNotFound {
NodeBST<E> res = actual;
if (actual == null) throw new ItemNotFound(x + "no esta");
int resC = actual.data.compareTo(x);
if (resC < 0) res.right = remove(x, actual.right);
else if (resC > 0) res.left = remove(x, actual.left);
else if(actual.left != null && actual.right != null){//dos hijos
res.data = minRecover(actuall.right).data;
res.right = minRemove(actual.right);
} else { //1 hijo o ninguno
res = (actual.left != null) ? actual.left : actual.right;
}
return res;
}
Traza de remove (nodo con un hijo)
Llamada inicial (eliminamos el dato x=5)
root = remove(x, root);

remove(5, 7 );
resC > 0
7 .left = remove(5, 7 .left)
7 return 7
remove(5, 2 );
resC < 0
2 .right = remove(5, 2 .right)

2
return 2
remove(5, 5 );
resC == 0
return 5 .left)
3
Traza de remove (nodo con dos hijos)
Llamada inicial (eliminamos el dato x=7)
root = remove(x, root),

remove(7, 7 );
resC == 0
7 .data = minRecover( 7 .right).data

8 .right = minRemove( 8 .right) minRecover( 9 );


8
return 8 8 return 8
minRemove( 9 );
9 .left = minRemove( 9 .left)
9 return 9

minRemove( 8 );
8 .left == null

null
return 8 .right
Implementación: consultores y de recorrido

public boolean isEmpty(){


return this.root == null;
}

public String postOrder(){


if (this.root != null) return postOrden(this.root);
else return "*";
}

protected String postOrder(NodeBST<E> actual){


String res = "";
if (actual.left != null) res += postOrder(actual.left);
if (actual.right != null) res += postOrder(actual.right);
return res + actual.data.toString() + "\n";
}
TDA Diccionario

 Un TDA Diccionario está diseñado para favorecer la búsqueda de un


dato en una colección (no se permite, en general, datos repetidos)
 Los datos que se almacenan en un TDA Diccionario son pares (clave,
valor), donde:

 La búsqueda se realiza en función de la clave:

 El valor es la información que se desea recuperar


TDA Diccionario

 Dado un conjunto de elementos {X1, X2, ..., XN} de un diccionario,


todos distintos entre sí, se desea almacenarlos en una estructura de
datos que permita la implementación eficiente de las operaciones:

 búsqueda(X): dado un elemento X, conocido como llave de búsqueda,


encontrarlo dentro del conjunto o decir que no está.
 inserción(X): agregar un nuevo elemento X al conjunto.
 eliminación(X): eliminar el elemento X del conjunto.

 Estas operaciones describen al TDA diccionario.


Implementaciones sencillas

 Utilizando una lista:


 búsqueda: O(n) (búsqueda secuencial).
 inserción: O(1) (insertando siempre al comienzo de la lista).
 eliminación: O(n) (búsqueda + O(1)).

 Por medio de un arreglo ordenado:


 inserción y eliminación son ineficientes: O(n)
 Es posible realizar la búsqueda binaria: O(log n)
Implementación del TDA Diccionario

 El modelo Diccionario permite realizar búsquedas por clave para


obtener el valor de dicha entrada del Diccionario.
 Una entrada es un par (clave, valor)
 No se permiten elementos repetidos, es decir, dos entradas con la
misma clave
public interface Dictionary <C, V> {
 Para implementar el void insert(C key, V val);
void remove(C key) throws ItemNotFound;
interfaz Dictionary
V recover(C key) throws ItemNotFound;
necesitamos definir la clase boolean isEmpty();
EntryDic }
Implementación: clase EntryDic

class EntryDic<C extends Comparable<C>,V>


implements Comparable<EntryDic<C,V>> {
private C key;
private V value;
public EntryDic(C key, V val) { this.key = key; this.value = val;}
public EntryDic(C key) { this(key, null); }
public boolean equals(Object x) {
return ((EntryDic<C,V>)x).key.equals(this.key);
}
public int compareTo(EntryDic<C,V> x) {
return this.key.compareTo(x.key);
}
public String toString() {
return this.key + “ => ” + this.value;
}
}
Implementación: clase BSTDiccionary
class BSTDictionary<C extends Comparable<C>,V>
implements Dictionary<C,V> {
private BST<EntryDic<C,V>> bst;
public BSTDictionary() {
bst = new BST<EntryDic<C,V>>();
}
public void insert(C key, V value) {
bst.insert(new EntryDic<C,V>(key,value));
}
public void remove(C key) throws ItemNotFound {
bst.remove(new EntryDic<C,V>(key));
}
public V recover(C key) throws ItemNotFound {
return bst.recover(new EntryDic<C,V>(key)).valor;
}
public boolean isEmpty() { return bst.isEmpty(); }
}