-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c5283a0
commit e350f65
Showing
4 changed files
with
383 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
|
||
namespace WEBOO.Programacion | ||
{ | ||
public class ArbolBinario<T> | ||
{ | ||
|
||
public ArbolBinario( | ||
T valor, | ||
ArbolBinario<T> hijoIzquierdo, | ||
ArbolBinario<T> hijoDerecho) | ||
{ | ||
this.Valor = valor; | ||
this.HijoIzquierdo = hijoIzquierdo; | ||
this.HijoDerecho = hijoDerecho; | ||
} | ||
|
||
public ArbolBinario(T valor) : this(valor, null, null) { } | ||
|
||
public T Valor { get; private set; } | ||
|
||
public ArbolBinario<T> HijoIzquierdo { get; protected set; } | ||
|
||
public ArbolBinario<T> HijoDerecho { get; protected set; } | ||
|
||
public IEnumerable<T> EntreOrden() | ||
{ | ||
if (this.HijoIzquierdo != null) | ||
foreach (var x in this.HijoIzquierdo.EntreOrden()) | ||
yield return x; | ||
|
||
yield return this.Valor; | ||
|
||
if (this.HijoDerecho != null) | ||
foreach (var x in this.HijoDerecho.EntreOrden()) | ||
yield return x; | ||
} | ||
|
||
public IEnumerable<T> PostOrden() | ||
{ | ||
if (this.HijoIzquierdo != null) | ||
foreach (var x in this.HijoIzquierdo.PostOrden()) | ||
yield return x; | ||
|
||
if (this.HijoDerecho != null) | ||
foreach (var x in this.HijoDerecho.PostOrden()) | ||
yield return x; | ||
|
||
yield return this.Valor; | ||
} | ||
|
||
public virtual bool Contiene(T x) | ||
{ | ||
if (this.Valor.Equals(x)) | ||
return true; | ||
if (this.HijoIzquierdo != null && this.HijoIzquierdo.Contiene(x)) | ||
return true; | ||
if (this.HijoDerecho != null && this.HijoDerecho.Contiene(x)) | ||
return true; | ||
|
||
return false; | ||
} | ||
|
||
#region EJERCICIOS | ||
//Programar los recorridos PreOrden y PostOrden | ||
//Determinar si un árbol binario es espejo | ||
//Programar un método que reciba un árbol correspondiente a una expresión (con operadores y valores enteros) y evalue la expresion | ||
#endregion | ||
} | ||
|
||
public class ArbolBinarioOrdenado<T> : ArbolBinario<T> where T : IComparable<T> | ||
{ | ||
public ArbolBinarioOrdenado(T valor, | ||
ArbolBinarioOrdenado<T> hijoIzquierdo, | ||
ArbolBinarioOrdenado<T> hijoDerecho) : base(valor, hijoIzquierdo, hijoDerecho) | ||
{ | ||
if ((hijoIzquierdo != null && hijoIzquierdo.Max.CompareTo(valor) > 0) || | ||
(hijoDerecho != null && hijoDerecho.Min.CompareTo(valor) < 0)) | ||
throw new ArgumentException(); | ||
} | ||
|
||
public ArbolBinarioOrdenado(T valor) : this(valor, null, null) { } | ||
|
||
public new ArbolBinarioOrdenado<T> HijoDerecho | ||
{ | ||
get { return base.HijoDerecho as ArbolBinarioOrdenado<T>; } | ||
protected set { base.HijoDerecho = value; } | ||
} | ||
|
||
public new ArbolBinarioOrdenado<T> HijoIzquierdo | ||
{ | ||
get { return base.HijoIzquierdo as ArbolBinarioOrdenado<T>; } | ||
protected set { base.HijoIzquierdo = value; } | ||
} | ||
|
||
public T Max | ||
{ | ||
get | ||
{ | ||
return HijoDerecho == null ? this.Valor : HijoDerecho.Max; | ||
} | ||
} | ||
|
||
public T Min | ||
{ | ||
get | ||
{ | ||
return HijoIzquierdo == null ? this.Valor : HijoIzquierdo.Min; | ||
} | ||
} | ||
|
||
public override bool Contiene(T x) | ||
{ | ||
int comparacion = x.CompareTo(this.Valor); | ||
|
||
if (comparacion < 0) | ||
if (HijoIzquierdo != null) | ||
return HijoIzquierdo.Contiene(x); | ||
else | ||
return false; | ||
|
||
if (comparacion > 0) | ||
if (HijoDerecho != null) | ||
return HijoDerecho.Contiene(x); | ||
else | ||
return false; | ||
|
||
return true; | ||
} | ||
|
||
#region EJERCICIOS | ||
//Determinar si un árbol binario está ordenado | ||
//Dado un árbol binario devolver un árbol binario ordenado | ||
//Determinar si un árbol binario está balanceado | ||
//Crear un árbol binario balanceado y ordenado a partir de uno ordenado | ||
#endregion | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
|
||
namespace WEBOO.Programacion | ||
{ | ||
class Program | ||
{ | ||
static void Main(string[] args) | ||
{ | ||
#region Ejemplo de recorrido EntreOrden | ||
ArbolBinario<string> expresion = new ArbolBinario<string>("*", | ||
new ArbolBinario<string>("+", new ArbolBinario<string>("a"), new ArbolBinario<string>("b")), | ||
new ArbolBinario<string>("-", new ArbolBinario<string>("c"), new ArbolBinario<string>("d"))); | ||
|
||
Console.WriteLine("\nRecorriendo en EntreOrden un árbol..."); | ||
foreach (var s in expresion.EntreOrden()) | ||
Console.Write("{0} ", s); | ||
Console.WriteLine(); | ||
#endregion | ||
|
||
#region Ejemplo de recorrido en postorden para evaluar un árbol de expresion | ||
ArbolBinario<object> expr = new ArbolBinario<object>('*', | ||
new ArbolBinario<object>('+', new ArbolBinario<object>(4), new ArbolBinario<object>(2)), | ||
new ArbolBinario<object>('-', new ArbolBinario<object>(5), new ArbolBinario<object>(3))); | ||
//Evaluar | ||
Stack<object> pila = new Stack<object>(); | ||
int op1, op2; | ||
Console.WriteLine("\nRecorriendo un árbol de expresión en postorden para evaluar la expresión..."); | ||
foreach (var x in expr.PostOrden()) | ||
{ | ||
Console.Write("{0} ", x); | ||
if (x is int) pila.Push(x); | ||
else if (x is char) | ||
{ | ||
if (pila.Count > 0) op2 = (int)(pila.Pop()); | ||
else throw new Exception("Arbol no corresponde a una expresión"); | ||
if (pila.Count > 0) op1 = (int)(pila.Pop()); | ||
else throw new Exception("Arbol no corresponde a una expresión"); | ||
switch ((char)x) | ||
{ | ||
case '+': pila.Push(op1 + op2); break; | ||
case '-': pila.Push(op1 - op2); break; | ||
case '*': pila.Push(op1 * op2); break; | ||
case '/': pila.Push(op1 / op2); break; | ||
case '%': pila.Push(op1 % op2); break; | ||
default: throw new Exception("Operador inválido"); | ||
} | ||
} | ||
else throw new Exception("No es operando entero ni operador"); | ||
} | ||
if (pila.Count == 1) | ||
Console.WriteLine("\nResultado de evaluar la expresión es {0}", pila.Pop()); | ||
else throw new Exception("Arbol no corresponde a una expresión"); | ||
#endregion | ||
|
||
ArbolBinarioOrdenado<int> arbol = new ArbolBinarioOrdenado<int>(20, | ||
new ArbolBinarioOrdenado<int>(15, new ArbolBinarioOrdenado<int>(10), new ArbolBinarioOrdenado<int>(18)), | ||
new ArbolBinarioOrdenado<int>(40, new ArbolBinarioOrdenado<int>(33), new ArbolBinarioOrdenado<int>(52))); | ||
|
||
Console.WriteLine("\nRecorriendo en EntreOrden árbol ordenado..."); | ||
foreach (var x in arbol.EntreOrden()) | ||
Console.Write("{0} ", x); | ||
Console.WriteLine(); | ||
|
||
while (true) | ||
{ | ||
Console.Write("\nEntre numero a buscar "); | ||
string s = Console.ReadLine(); | ||
if (s.Length == 0) break; | ||
int k = Int32.Parse(s); | ||
Console.WriteLine("Arbol contiene a {0} es {1}", k, arbol.Contiene(k)); | ||
} | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net7.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
# Profundizando sobre Árboles | ||
|
||
Recordemos que un _árbol_ es una estructura de datos jerárquica que consiste en nodos conectados por aristas. Cada nodo contiene un valor o dato y puede tener nodos hijos. El nodo superior se llama raíz y cada nodo tiene cero o más nodos hijos. Los nodos sin hijos se llaman hojas. | ||
|
||
Algunas definiciones: | ||
|
||
- **Raíz**: el nodo superior del árbol. | ||
- **Nodo interno**: nodo con al menos un hijo. | ||
- **Hoja**: nodo sin hijos. | ||
- **Altura**: la longitud del camino más largo desde la raíz hasta una hoja. | ||
|
||
## Árbol Binario | ||
|
||
Un árbol binario es un tipo de árbol en el cual cada nodo tiene como máximo dos hijos, denominados hijo izquierdo e hijo derecho. | ||
|
||
### Ejemplo en C# | ||
|
||
```csharp | ||
public class NodoBinario<T> { | ||
public T Valor; | ||
public NodoBinario<T> Izquierdo; | ||
public NodoBinario<T> Derecho; | ||
|
||
public NodoBinario(int valor) { | ||
this.Valor = valor; | ||
Izquierdo = null; | ||
Derecho = null; | ||
} | ||
} | ||
``` | ||
|
||
Para implementar un árbol binario, se crean nodos y se establecen referencias para los hijos izquierdo y derecho. Los métodos comunes incluyen inserción, eliminación y búsqueda. | ||
|
||
## Árbol Binario Ordenado (BST) | ||
|
||
Un árbol binario ordenado es un árbol binario en el que para cada nodo, todos los valores en el subárbol izquierdo son menores que el valor del nodo, y todos los valores en el subárbol derecho son mayores. | ||
|
||
### Consideraciones | ||
|
||
- Facilita operaciones eficientes de búsqueda, inserción y eliminación. | ||
- Mantiene sus propiedades a través de rotaciones y rebalanceos en árboles más avanzados como AVL o Red-Black. | ||
> Los estudiarán en EDA `;-)` | ||
### Ejemplo en C# | ||
|
||
```csharp | ||
public class BST<T> { | ||
public NodoBinario<T> raiz; | ||
|
||
public void Insertar(int valor) { | ||
raiz = InsertarRecursivo(raiz, valor); | ||
} | ||
|
||
private NodoBinario<T> InsertarRecursivo(NodoBinario<T> raiz, T valor) { | ||
if (raiz == null) { | ||
raiz = new NodoBinario(valor); | ||
return raiz; | ||
} | ||
if (valor < raiz.Valor) | ||
raiz.Izquierdo = InsertarRecursivo(raiz.Izquierdo, valor); | ||
else if (valor > raiz.Valor) | ||
raiz.Derecho = InsertarRecursivo(raiz.Derecho, valor); | ||
|
||
return raiz; | ||
} | ||
} | ||
``` | ||
|
||
La inserción y búsqueda en un BST pueden ser implementadas de forma recursiva. La complejidad promedio es O(log n), pero en el peor caso puede ser O(n). Para que las operaciones sean eficientes, el árbol debe estár **balanceado** _(que tenga altura logarítmica respecto a la cantidad de nodos que almacena)_. | ||
|
||
## Recorridos en Árboles | ||
|
||
Existen varios métodos para recorrer un árbol. Los más comunes son los recorridos en profundidad (DFS) y en amplitud (BFS). Dentro del DFS, se incluyen los recorridos en pre-orden, post-orden y en-orden. | ||
|
||
### Recorrido en Profundidad (DFS) | ||
|
||
#### Recorrido en Pre-orden | ||
|
||
En el recorrido en pre-orden, se visita primero el nodo actual, luego se recorre el subárbol izquierdo y finalmente el subárbol derecho. | ||
|
||
```csharp | ||
public void PreOrden<T>(Nodo<T> nodo) { | ||
Console.Write(nodo.Valor + " "); | ||
foreach (var hijo in nodo.Hijos) { | ||
PreOrden(hijo); | ||
} | ||
} | ||
``` | ||
|
||
#### Recorrido en Post-orden | ||
|
||
En el recorrido en post-orden, se recorre primero el subárbol izquierdo, luego el subárbol derecho y finalmente se visita el nodo actual. | ||
|
||
```csharp | ||
public void PostOrden<T>(Nodo<T> nodo) { | ||
foreach (var hijo in nodo.Hijos) { | ||
PostOrden(hijo); | ||
} | ||
Console.Write(nodo.Valor + " "); | ||
} | ||
``` | ||
|
||
#### Recorrido en In-orden (para Árbol Binario) | ||
|
||
En el recorrido en in-orden, se recorre primero el subárbol izquierdo, luego se visita el nodo actual y finalmente se recorre el subárbol derecho. Este recorrido es especialmente útil en árboles binarios de búsqueda, ya que produce los valores en orden ascendente. | ||
|
||
```csharp | ||
public void InOrden<T>(NodoBinario<T> nodo) { | ||
if (nodo == null) return; | ||
InOrden(nodo.Izquierdo); | ||
Console.Write(nodo.Valor + " "); | ||
InOrden(nodo.Derecho); | ||
} | ||
``` | ||
|
||
### Recorrido en Amplitud (BFS) | ||
|
||
En el recorrido en amplitud, se visita cada nivel del árbol de izquierda a derecha, empezando por la raíz y avanzando hacia abajo nivel por nivel. | ||
|
||
```csharp | ||
public void BFS<T>(Nodo<T> raiz) { | ||
if (raiz == null) return; | ||
Queue<Nodo<T>> cola = new Queue<Nodo<T>>(); | ||
cola.Enqueue(raiz); | ||
while (cola.Count > 0) { | ||
Nodo<T> nodo = cola.Dequeue(); | ||
Console.Write(nodo.Valor + " "); | ||
foreach (var hijo in nodo.Hijos) { | ||
cola.Enqueue(hijo); | ||
} | ||
} | ||
} | ||
``` | ||
|
||
## Otros Tipos de Árboles | ||
|
||
- **Quadtree:** Un quadtree es una estructura de datos en la que cada nodo tiene exactamente cuatro hijos. Se utiliza principalmente para dividir un espacio bidimensional en regiones más pequeñas. | ||
|
||
- Utilizado en gráficos computacionales y procesamiento de imágenes. | ||
- Eficiente para operaciones de colisión y búsquedas espaciales. | ||
|
||
|
||
- **Árbol de Prefijos (Trie):** Un árbol de prefijos o trie es un árbol de búsqueda en el que cada nodo representa un prefijo común de un conjunto de cadenas. | ||
|
||
- Utilizado para búsqueda eficiente de cadenas, autocompletado y corrección ortográfica. | ||
- Cada camino desde la raíz hasta una hoja representa una palabra. | ||
|
||
## Notas Generales | ||
|
||
- Los árboles son estructuras de datos fundamentales en la computación, usados en diversas aplicaciones como bases de datos, gráficos, inteligencia artificial, y más. | ||
- La elección del tipo de árbol depende del caso de uso específico, considerando las operaciones principales y su eficiencia. | ||
- Los árboles avanzados como AVL, Red-Black, y B-trees proporcionan mejor rendimiento garantizado en operaciones comunes, a costa de una mayor complejidad de implementación. | ||
|
||
Con un entendimiento sólido de las estructuras de árbol y sus recorridos, se pueden abordar problemas complejos de manera más eficiente y efectiva. |