Estructuras de Datos Tema 2: Estructuras Jerárquicas Conferencia #3. Árboles binarios, generales y de búsqueda. Contenido de la clase Definición de árbol. Árboles binarios y árboles generales. Recorridos en árboles. Árboles de búsqueda: AVL, rojinegros. Implementación en un lenguaje de programación. Introducción Relaciones entre los datos que denotan relaciones jerárquicas: Estructuras jerárquicas Introducción Ejemplo: Director Subdirector1 J´Dpto1 J´Dpto2 Subdirector2 J´Dpto3 Subdirector3 J´Dpto4 J´Dpto5 Bibliografía Autor(es) Mark Allen Weiss BIBLIOTECA DE CLASES PARA TRABAJO CON ÁRBOLES Título, editorial, año Capítulo 6: epígrafes 6.5 y 6.6 Capítulos 17 y 18 Interfaces: TreeIterator Clases: TreeNode, BinaryTreeNode, Tree, BinaryTree, GenerealTree, PreorederIterator, PosorderIterator, SymetricIterator, InBreadthIterator, InBreadthIteratorWithLevel, InDepthIterator Árboles Un árbol (en inglés: tree) un T.D.A. que representa un conjunto finito T de nodos, tales que: Hay un nodo, especialmente designado, llamado la raíz del árbol T, y Los nodos restantes, excluyendo la raíz, son particionados en m (m 0) conjuntos disjuntos T1, T2, ..., Tm, cada uno de los cuales es, a su vez, un árbol, llamado subárbol del árbol T. Árboles Aclaraciones: Si el conjunto finito T es vacío, entonces el árbol es vacío. Sólo la raíz no tiene predecesor. Todos los demás nodos tienen un único predecesor. Para todo nodo k, distinto de la raíz, existe una única secuencia de la forma: raíz = k0, k1, k2, k3, ..., kn = k con n >= 1, donde ki es el sucesor de ki-1, para 1 <= i <= n, o sea, cada nodo ki de la secuencia es la raíz de otro subárbol. Conceptos básicos Grado de un nodo cantidad de sucesores de un nodo. Grado de un árbol mayor de los grados de todos sus nodos. Nodo hoja nodo sin sucesores. Nodo rama nodo que tiene sucesores, o sea, la raíz de un subárbol. Nivel de un nodo nivel de su padre más uno. Por definición, la raíz del árbol tiene nivel 0. Conceptos básicos Árbol completo de nivel n árbol en el que cada nodo de nivel n es una hoja y cada nodo de nivel menor que n tiene, al menos, un subárbol no vacío. a a c b d e f c b g h Árbol completo de nivel 2 d e Árbol no completo de nivel 2 Conceptos básicos Padre de un nodo nodo raíz del subárbol más pequeño que contiene a dicho nodo y en el cual él no es raíz. Hijo de un nodo nodo raíz de uno de los subárboles. Predecesor de un nodo nodo que le antecede en un recorrido del árbol. Hermano de un nodo a otro nodo hijo de su padre. Conceptos básicos Árbol ordenado árbol para el que se considera el orden relativo de los sucesores o subárboles de cualquier nodo. Ejemplo Mario Marta José Juan Árbol genealógico de una persona Ana Raúl Inés Conceptos básicos Árbol orientado árbol para el cual no interesa el orden relativo de los sucesores o subárboles de cualquier nodo, sólo se tiene en cuenta la orientación de los nodos. Director Subdirector1 J´Dpto1 J´Dpto2 Subdirector2 J´Dpto3 Subdirector3 J´Dpto4 J´Dpto5 Conceptos básicos Una floresta es una colección de dos o más árboles disjuntos. Aclaraciones: Disjuntos significa que no hay nodos comunes entre dos árboles cualesquiera de la misma. De un árbol se obtiene una floresta al quitarle la raíz. De una floresta se obtiene un árbol al añadirle un nodo que sea raíz de todos los árboles que la conforman. Conceptos básicos Un árbol binario (en inglés binary tree) es un árbol ordenado de, a lo sumo, grado 2. Aclaraciones: Cada nodo tiene a lo sumo dos hijos, o sea, dos subárboles. Al ser ordenado, importa el orden de los subárboles, es decir, que será necesario especificar de cada nodo cuál es el hijo izquierdo y cuál el hijo derecho. Recorridos Árboles Binarios: Preorden: raíz, izquierdo, derecho. Simétrico o entreorden: izquierdo, raíz, derecho. Postorden u orden final: izquierdo, derecho, raíz. Árboles Generales: A lo ancho: todos los nodos de un mismo nivel, comenzando por la raíz. En profundidad: la raíz, los subárboles en los que son raíces cada uno de sus hijos. Recorridos en árboles generales A lo ancho: ABCDEFGH En profundidad: ABEFCDGH Búsqueda en árboles Búsquedas utilizando los recorridos tradicionales. Búsquedas que aprovechan implementaciones particulares: lexicográficos, AVL, rojinegros. Árboles de búsqueda Árbol lexicográfico: Un árbol lexicográfico es un árbol binario que, recorrido en orden simétrico, permite obtener la información de los nodos en algún criterio de ordenamiento. Insertar en el orden: Ejemplo 8 8, 10, 12, 16, 20 Insertar en el orden: 12, 10, 8, 16, 20 10 12 8 (N) 16 10 20 12 16 20 Árboles de búsqueda Árbol AVL: Un árbol AVL es un árbol binario de búsqueda con una propiedad adicional de equilibrio, según la cual, las alturas de los hijos derecho e izquierdo solo pueden diferir, a la sumo, en una unidad. (El árbol vacío tiene altura -1) Contraejemplo 12 Ejemplo (log N) 12 8 2 16 10 4 6 8 10 4 20 2 1 16 6 20 Nodos que no cumplen la propiedad de equilibrio Árboles de búsqueda Árbol rojinegro: Un árbol rojinegro es un árbol binario de búsqueda que verifica las propiedades de orden siguientes: Cada nodo está coloreado Ejemplo M rojo o negro. (log N) S H La raíz es negra. Si un nodo es rojo, sus hijos deben ser negros. J P X C Todos los caminos desde un nodo hasta una O R U Z referencia null deben A contener la misma T W cantidad de nodos negros. Implementaciones de árboles Cada nodo contiene la lista de sus hijos. La manipulación de la lista podría hacer engorroso el tratamiento de los hijos Info Lista de referencias a los hijos Implementaciones de árboles Cada nodo contiene enlace a sus hijos Árbol binario: enlace al hijo izquierdo, enlace al hijo derecho. Estructura de un nodo en árbol binario: Hijo izq. Info Hijo der. Árbol general: (transformado a binario) enlace al primer hijo, enlace al siguiente hermano. Estructura de un nodo en árbol general: Info Primer Sgte. hijo Herm. Implementaciones de árboles Árbol general: (transformado a binario) enlace al primer hijo, enlace al siguiente hermano. Árbol General Árbol General (implementado como binario) Implementaciones de árboles Clases TreeNode, BinaryTreeNode abstract public class TreeNode<E> { protected E info; public TreeNode() {…} public TreeNode(E info) {…}} public class BinaryTreeNode<E> extends TreeNode<E> implements Serializable { private static final long serialVersionUID = 1L; protected BinaryTreeNode<E> left; protected BinaryTreeNode<E> right; public BinaryTreeNode() {…} public BinaryTreeNode(E info) {…} public E getInfo() {return info;} public void setInfo(E info) {this.info = info;} public BinaryTreeNode<E> getLeft() {… public void setLeft(BinaryTreeNode<E> left) {…} public BinaryTreeNode<E> getRight() {return right;} Clase Tree abstract public class Tree<E> { protected TreeNode<E> root; public Tree() { root = null; } public Tree(TreeNode<E> root) { this.root = root;} public TreeNode<E> getRoot() { return root;} public void setRoot(TreeNode<E> root) {this.root = root;} public boolean isEmpty() {return root == null;} public abstract int totalNodes(); public abstract List<TreeNode<E>> getLeaves(); public abstract int nodeLevel(TreeNode<E> node); public abstract int treeLevel(); public abstract int treeHeight(); public abstract boolean nodeIsLeaf(TreeNode<E> node); public abstract int nodeDegree(TreeNode<E> node); public abstract E deleteNode(BinaryTreeNode<E> node);} Clase BinaryTree public class BinaryTree<E> extends Tree<E> implements Serializable{ private static final long serialVersionUID = 1L; public BinaryTree() {super();} public BinaryTree(TreeNode<E> root) {super(root);} public BinaryTree(BinaryTreeNode<E> root) {this.root = root;} protected int level(BinaryTreeNode<E> cursor) {…} public int treeLevel() {…} public int nodeLevel(TreeNode<E> node) {…} public E deleteNode(BinaryTreeNode<E> node) {…} private void deleteNotRoot(BinaryTreeNode<E> node, BinaryTreeNode<E> father) {…} public int nodeDegree(TreeNode<E> node) {…} public BinaryTreeNode<E> getFather(BinaryTreeNode<E> node) {.} public List<TreeNode<E>> getLeaves() {…} …. Clase BinaryTree: Iteradores public class BinaryTree<E> extends Tree<E> implements Serializable{ … private void getNodeSubTree(BinaryTreeNode<E> root, BinaryTreeNode<E> node, BinaryTree<E> tree) { …} public List<BinaryTreeNode<E>> getSons(BinaryTreeNode<E> node) {…} public BinaryTree<E> getSubTree(BinaryTreeNode<E> node) {…} private void buildSubTree(BinaryTreeNode<E> srcFather, BinaryTreeNode<E> newFather){…} public boolean insertNode(BinaryTreeNode<E> node, char type, BinaryTreeNode<E> father) {…} public PreorderIterator<E> preOrderIterator(){ return new PreorderIterator<E>(this); } public SymmetricIterator<E> symmetricIterator(){ return new SymmetricIterator<E>(this); } public PosOrderIterator<E> posOrderIterator(){ return new PosOrderIterator<E>(this); } Clase GeneralTree public class GeneralTree<E> extends Tree<E> implements Serializable { private static final long serialVersionUID = 1L; public GeneralTree() {super();} public GeneralTree(BinaryTreeNode<E> root) {super(root);} public int totalNodes() {…} public E deleteNode(BinaryTreeNode<E> node) {…} public BinaryTreeNode<E> getFather(BinaryTreeNode<E> node) {.} public List<TreeNode<E>> getLeaves() {…} public List<BinaryTreeNode<E>> getSons(BinaryTreeNode<E>node) {…} public List<E> getSonsInfo(BinaryTreeNode<E> node) {…} public boolean insertNode(BinaryTreeNode<E> node, BinaryTreeNode<E> father) {…} public boolean insertAsFirstSon(BinaryTreeNode<E> node, BinaryTreeNode<E> father) {…} … Clase GeneralTree: Iteradores public class GeneralTree<E> extends Tree<E> implements Serializable { … public int nodeLevel(TreeNode<E> node) {…} public int treeLevel() { …} public boolean nodeIsLeaf(TreeNode<E> node) {…} public int nodeDegree (TreeNode<E> node) {…} private int rightBrotherCount(BinaryTreeNode<E> node) {…} public InDepthIterator<E> inDepthIterator(){ return new InDepthIterator<E>(this);} public InBreadthIterator<E> inBreadthIterator(){ return new InBreadthIterator<E>(this);} public InBreadthIteratorWithLevels<E> InBreadthIteratorWithLevels(){ return new InBreadthIteratorWithLevels<E>(this); } public int treeHeight() {…} } Conclusiones Árboles y otras definiciones importantes. Árboles binarios y generales. Recorridos. Árboles de búsqueda: lexicográficos, AVL y rojinegros. Implementación de árboles binarios y generales. Motivación próxima clase ¿Cómo almacenar árboles en memoria externa?. Una variante de índice utilizada por los Sistemas de Gestión de Bases de Datos. Estudio Independiente 1. Estudiar las implemntaciones de las clases GeneralTree y BinaryTree. 2. Estudiar las implementaciones de los iteradores para árboles generales: clases InDepthIterator, InBreadthIterator y InBreadthIteratorWithLevels. 3. Estudiar las implementaciones de los iteradores para árboles binarios: clases PreorderIterator, SymmetricIterator y PosorderIterator. 4. Ejercicio resuelto 1.