Programación III, Guía8 Facultad : Ingeniería Escuela : Computación Asignatura: Programación III Tema: “ARBOLES ROJO NEGRO”. Objetivo Implementar la estructura de árboles B y árboles Rojo Negro, utilizando C#. Introducción Un árbol rojo negro es un tipo abstracto de datos, concretamente es un árbol binario de búsqueda equilibrado, una estructura de datos utilizada en informática y ciencias de la computación. Puede buscar, insertar y borrar en un tiempo O(log n), donde n es el número de elementos del árbol. En los árboles rojo-negro las hojas no son relevantes y no contienen datos. A la hora de implementarlo en un lenguaje de programación, para ahorrar memoria, un único nodo (nodo-centinela) hace de nodo hoja para todas las ramas. Así, todas las referencias de los nodos internos a las hojas van a parar al nodo centinela. En los árboles rojo-negros, como en todos los árboles binarios de búsqueda, es posible moverse ordenadamente a través de los elementos de forma eficiente si hay forma de localizar el padre de cualquier nodo. El tiempo de desplazarse desde la raíz hasta una hoja a través de un árbol equilibrado que tiene la mínima altura posible es de O(log n). Propiedades: Un árbol rojo-negro es un árbol binario de búsqueda en el que cada nodo tiene un atributo de color cuyo valor es o bien rojo o bien negro. Además de los requisitos impuestos a los árboles binarios de búsqueda convencionales, se deben satisfacer los siguientes para tener un árbol rojo-negro válido: 1. Todo nodo es o bien rojo o bien negro. 2. La raíz es negra. 3. Todas las hojas son negras (las hojas son los hijos nulos). 1 Programación III, Guía 8 2 4. Los hijos de todo nodo rojo son negros (también llamada "Propiedad del rojo"). 5. Cada camino simple desde un nodo a una hoja descendiente contiene el mismo número de nodos negros, ya sea contando siempre los nodos negros nulos, o bien no contándolos nunca (el resultado es equivalente). También es llamada "Propiedad del camino", y al número de nodos negros de cada camino, que es constante para todos los caminos, se le denomina "Altura negra del árbol", y por tanto el camino no puede tener dos rojos seguidos. 6. El camino más largo desde la raíz hasta una hoja no es más largo que 2 veces el camino más corto desde la raíz del árbol a una hoja en dicho árbol. El resultado es que dicho árbol está aproximadamente equilibrado. Materiales y equipo Guía de Laboratorio Nº 8. Computadora con programa: o Visual Studio 2012. C# Dispositivo de Almacenamiento (USB). Procedimiento 1. Cree un proyecto modo consola en Visual C# y nómbrelo como BinarySearchTree.cs using System; using System.Collections.Generic; using System.Text; namespace BinaryTree { public class Node { Programación III, Guía 8 public String data; public Object key; public Node left, right; public Node(Object key, String data) { this.data = data; this.key = key; left = null; right = null; } } public class BinarySearchTree { private Node root; private int count = 0; public BinarySearchTree() { root = null; count = 0; } public int Count { get { return this.count; } set { this.count = value; } } public Node Root { get { return this.root; } } private void CreateNode(Node node, ref Node tree) { if (tree == null) tree = node; else { int result = String.Compare(node.key.ToString(), tree.key.ToString()); if (result == 0) throw new Exception("Clave duplicada..."); else if (result < 0) CreateNode(node, ref tree.left); else CreateNode(node, ref tree.right); } } public Node Insert(Object key, String data) { Node node = new Node(key, data); try { 3 Programación III, Guía 8 4 if (root == null) root = node; else CreateNode(node, ref root); this.Count++; return node; } catch { return null; } } public Node Search(Node node, Object key) { if (node == null) return null; else { int result = String.Compare(key.ToString(), node.key.ToString()); if (result < 0) return Search(node.left, key); else if (result > 0) return Search(node.right, key); else return node; } } } } 2. Ahora cree otro archivo con el nombre Program.cs using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Text; namespace Trees { public enum Color { Red = 0, Black = 1 } public enum Direction { Left, Right } public class Node { public IComparable data; public Node left; public Node right; public Color color = Color.Black; public Node(IComparable data) : this(data, null, null) { } public Node(IComparable data, Node left, Node right) Programación III, Guía 8 { this.data = data; this.left = left; this.right = right; } } public class Tree { protected Node root; protected Node freshNode; protected Node currentNode; protected Tree() { freshNode = new Node(null); freshNode.left = freshNode.right = freshNode; root = new Node(null); root.left = freshNode; root.right = freshNode; } protected int Compare(IComparable item, Node node) { if (node != root) return item.CompareTo(node.data); else return 1; } public IComparable Search(IComparable data) { freshNode.data = data; currentNode = root.right; while (true) { if (Compare(data, currentNode) < 0) currentNode = currentNode.left; else if (Compare(data, currentNode) > 0) currentNode = currentNode.right; else if (currentNode != freshNode) return currentNode.data; else return null; } } protected void Display() { this.Display(root.right); } protected void Display(Node temp) { if (temp != freshNode) Display(temp.left); Console.WriteLine(temp.data); Display(temp.right); } } } public sealed class RedBlackTree : Tree { 5 Programación III, Guía 8 6 private Color Black = Color.Black; private Color Red = Color.Red; private Node parentNode; private Node grandParentNode; private Node tempNode; public RedBlackTree() { } public void Insert(IComparable item) { currentNode = parentNode = grandParentNode = root; freshNode.data = item; int returnedValue = 0; while (Compare(item, currentNode) != 0) { tempNode = grandParentNode; grandParentNode = parentNode; parentNode = currentNode; returnedValue = Compare(item, currentNode); if (returnedValue < 0) currentNode = currentNode.left; else currentNode = currentNode.right; if (currentNode.left.color == Color.Red && currentNode.right.color == Color.Red) ReArrange(item); } if (currentNode == freshNode) { currentNode = new Node(item, freshNode, freshNode); if (Compare(item, parentNode) < 0) parentNode.left = currentNode; else parentNode.right = currentNode; ReArrange(item); } } private void ReArrange(IComparable item) { currentNode.color = Red; currentNode.left.color = Color.Black; currentNode.right.color = Color.Black; if (parentNode.color == Color.Red) { grandParentNode.color = Color.Red; bool compareWithGrandParentNode = (Compare(item, grandParentNode) < 0); bool compareWithParentNode = (Compare(item, parentNode) < 0); if (compareWithGrandParentNode != compareWithParentNode) parentNode = Rotate(item, grandParentNode); currentNode = Rotate(item, tempNode); currentNode.color = Black; } root.right.color = Color.Black; } private Node Rotate(IComparable item, Node parentNode) Programación III, Guía 8 { int value; if (Compare(item, parentNode) < 0) { value = Compare(item, parentNode.left); if (value < 0) parentNode.left = this.Rotate(parentNode.left, Direction.Left); else parentNode.left = this.Rotate(parentNode.left, Direction.Right); return parentNode.left; } else { value = Compare(item, parentNode.right); if (value < 0) parentNode.right = this.Rotate(parentNode.right, Direction.Left); else parentNode.right = this.Rotate(parentNode.right, Direction.Right); return parentNode.right; } } private Node Rotate(Node node, Direction direction) { Node tempNode; if (direction == Direction.Left) { tempNode = node.left; node.left = tempNode.right; tempNode.right = node; return tempNode; } else { tempNode = node.right; node.right = tempNode.left; tempNode.left = node; return tempNode; } } private int RandomNumber(int min, int max) { Random random = new Random(); return random.Next(min, max); } public static void Main(String[] args) { RedBlackTree redBlackTree = new RedBlackTree(); BinaryTree.BinarySearchTree binarySearchTree = new BinaryTree.BinarySearchTree(); Console.WriteLine("ARBOL ROJO-NEGRO"); Console.WriteLine("ingreso de datos en arbol Rojo Negro"); for (int i = 0; i < 9000000; i++) 7 Programación III, Guía 8 8 { redBlackTree.Insert(i); } Console.WriteLine("ingreso de datos en arbol de busqueda"); for (int p = 0; p < 9000000; p++) { binarySearchTree.Insert(p, p.ToString()); } DateTime startTime = DateTime.Now; Console.WriteLine("Buscando dato 4596126 dentro del arbol rojo negro"); redBlackTree.Search(4596126); DateTime endTime = DateTime.Now; TimeSpan timeElasped = (TimeSpan)(endTime - startTime); Console.WriteLine("Arbol Rojo Negro tiempo de busqueda: " + timeElasped.Milliseconds.ToString() + " milisegundos."); startTime = DateTime.Now; Console.WriteLine("Buscando dato 4596126 dentro arbol de busqueda"); binarySearchTree.Search(binarySearchTree.Root, "4596126"); endTime = DateTime.Now; timeElasped = (TimeSpan)(endTime - startTime); Console.WriteLine("Arbol binario tiempo de busqueda: " + timeElasped.Milliseconds.ToString() + "milisegundos."); Console.Read(); } } Análisis de resultados Analice el código proporcionado en Program.cs y explique su funcionamiento. Hacer un menú que permita insertar n valores (automático o manual) y que además me permita realizar búsquedas mediante el árbol rojo negro o mediante el árbol de búsqueda y que imprima el tiempo de ejecución. Programación III, Guía 8 9 Investigación complementaria. Investigue el funcionamiento de los arboles B (B- Trees). Qué diferencias y similitudes tienen con los otros árboles desarrollados Bibliografía. DEITEL, HARVEY M. / DEITEL, PAUL J. Cómo programar en C#. Editorial Pearson Prentice Hall, México 2004 JOYANES AGUILAR, LUIS. Programación en C# - Algoritmos, estructuras de datos y objetos. Editorial McGraw Hill, España 2006. Programación III, Guía 8 10 Hoja de cotejo: 8 Guía 8: Arboles Rojo Negro. Alumno: Máquina No: Docente: GL: Fecha: EVALUACION % CONOCIMIENTO 40 APLICACIÓN DEL CONOCIMIENTO 40 ACTITUD 20 TOTAL 100% 1-4 5-7 8-10 Nota