Skip to content

Commit

Permalink
Add Lecture 19 (+Code)
Browse files Browse the repository at this point in the history
  • Loading branch information
jpconsuegra committed Jun 30, 2024
1 parent c5283a0 commit e350f65
Show file tree
Hide file tree
Showing 4 changed files with 383 additions and 0 deletions.
141 changes: 141 additions & 0 deletions conferences/2024/19-more-trees/code/ArbolBinario.cs
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
}
}
78 changes: 78 additions & 0 deletions conferences/2024/19-more-trees/code/Program.cs
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));
}
}

}
}
10 changes: 10 additions & 0 deletions conferences/2024/19-more-trees/code/Program.csproj
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>
154 changes: 154 additions & 0 deletions conferences/2024/19-more-trees/lecture-19.md
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.

0 comments on commit e350f65

Please sign in to comment.