Está en la página 1de 30

ESTRUCTURAS DE DATOS Y ALGORITMOS – 2019/20

Tema 1: EDA’s en Java

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
Cola c (modelo FIFO)

• c.encolar(t) -> lo encola al final


• c.primero() -> obtiene el primer elemento
• c.desencolar() -> quita el primer elemento
Cola de prioridad cp

• cp.insertar(t) -> lo inserta al final


• recuperar() -> devuelve el dato de máxima prioridad
• cp.recuperarMin() -> devuelve el de mínima prioridad
• eliminar() -> elimina el de máxima prioridad

Reservados todos los derechos.


cp.eliminarMin() -> el de mínima prioridad
Pila p (modelo LIFO, Last In First Out)

• tope() -> devuelve la cima de la pila


• desapilar() -> elimina el elemento de la cima
• apilar(t) -> apila el elemento en el tope
ListaConPI

• void insertar(E e) -> antes del PI


• void eliminar() -> el elemento del PI
• E recuperar() -> el elemento del PI
• void inicio() -> sitúa el PI en la 1ª posición
• void siguiente() -> PI a la siguiente posición
• boolean esFin() -> comprueba si el PI está en su fin
• boolean esVacia() -> comprueba si una lista está vacía
• void fin() -> sitúa el PI a su fin (después de la última posición)
• int talla() -> devuelve la talla de una lista
compareTo(x)
public class nombreClase <T extends Comparable<T>> {
public int compareTo(Figura f) {
double areaF = f.area();
double areaThis = this.area();
if (areaThis<areaF) { return -1;}
if (areaThis>areaF) { return 1;}
return 0;
}
}

a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900476
ESTRUCTURAS DE DATOS Y ALGORITMOS – 2019/20
Tema 2: Divide y Vencerás

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
PASOS DIVIDE Y VENCERÁS:
1. Dividir el problema en subproblemas
2. Vencer: resolver los problemas usando recursión (excepto los casos base)
3. Combinar las soluciones
CÁLCULO DE COSTES
x=talla // T(x)=coste del método recursivo
Tvencer(x>xbase) = a * Tvencer(x/c) + Tdividir(x) + Tcombinar(x)
a = Nº de llamadas recursivas

Reservados todos los derechos.


Tvencer(x/c) = Reducción de la talla geométrica
Tdividir(x) + Tcombinar(x) = Sobrecarga en la llamada…
…lineal -> Teorema 4
…constante -> Teorema 3
TEOREMA 1: T(x) = a*T(x-c) +b, con b>=1

• SII a=1, T(x) € Θ(x)


• SII a>1, T(x) € Θ 𝑎 𝑥/𝑐
TEOREMA 2: T(x) = a*T(x-c) + b * x + d, con b>=1 y d>=1

• SII a=1, T(x) € Θ 𝑎2


• SII a>1, T(x) € Θ 𝑎 𝑥/𝑐
TEOREMA 3: T(x) = a*T(x/c) +b, con b>=1

• SII a=1, T(x) € Θ log 𝑐 𝑥


• SII a>1, T(x) € Θ 𝑎log𝑐 𝑎
TEOREMA 4: T(x) = a*T(x/c) + b * x + d, con b>=1 y d>=1

• SII a<c, T(x) € Θ(x)


• SII a = c, T(x) € Θ log 𝑐 𝑥
• SII a>c, T(x) € Θ 𝑎log𝑐 𝑎

MERGESORT (división equilibrada)

1er Método: FUSIÓN PARA COMBINAR 2 ARRAYS


Devuelve un array con la combinación de
2 arrays a y b ordenados

a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900487
public static <T extends Comparable<T>> T[] fusion(T[] a, T[] b){
T[] res = new Comparable[a.length + b.length];
int i = 0, j = 0, k = 0;
while(i<a.length && j<b.length){
if(a[i].compareTo(b[j])<0) { // i<j
res[k++] = a[i++]; // res[k]=a[i]; k++; i++;
} else { res[k++] = b[j++]; } // res[k[=b[j], k++, j++;

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
}
//Puede ser que una de las partes no haya acabado y otra si
for(int r = i; r<a.length;r++) { res[k++] = a[r]; }
for(int r = j; r<b.length;r++) { res[k++] = b[r]; }
return res;
}
2º Método: FUSIONDYV, que es como fusión (lo de arriba) pero con 1 array
y lo ordena

Reservados todos los derechos.


public static <T Extends Comparable<T>> void mergeSort(T[] v) {
mergeSort(v, 0, v.length-1); //método de abajo
}
private static <T extends Comparable <T>> void mergeSort(T[] v,
int i, int j) {
if(i<j){
int m = (i+j)/2; //dividir equilibradamente
mergeSort(v, i, m); //vencer de principio a m
mergeSort(v, m+1, j); //vencer de m+1 a j
fusionDyV(v, i, m+1, j); //combiner
}
}

QUICKSORT (división rápida)


Cojo un pivote (el primero) y lo muevo ordenadamente (así sucesivamente)

¿No te llega para pagar Wuolah Pro? ¿Un año sin anuncios gratis? ¡Clic aquí!
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900487
Ejemplo gráfico:

4 2 8 7 1 5 6 3 El Pivote es el 4, entonces pongo a su


izquierda los <4 y a su derecha los >4
2 1 3 4 8 7 5 6 Ahora el 4 ya está ordenado. 8 y 2 son
los nuevos pivotes y hay que
ordenarlos
1 2 3 4 7 5 6 8 Hemos ordenado 2 y 8 y podemos ver que
la primera parte está la ordenada (1-
2-3-4). 7 es el nuevo pivote y hay que
ordenarlo

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
1 2 3 4 5 6 7 8 Hemos ordenado el 7 y vemos que los
demás están también ordenados

private static<T extends Comparable<T>>void quickSort(T[] v,int i,int d){


if(i<d) {
int indP = particion(v, i, d); //dividir
quickSort(v, i, indP-1);

Reservados todos los derechos.


quicksort(v, indP+1, d);
}
}
public static <T extends Comparable<T>> void quicksort(T[] v) {
quicksort(v, 0, v.length);
}

COSTES:
-Selección directa: Θ (k*x)
-mergeSort o quickSort: Θ (x ∗ log 𝑐 𝑥)
SELECCIÓN RÁPIDA: Selecciona dónde debo situar el elemento k empezando a contar desde la posición 0

¿No te llega para pagar Wuolah Pro? ¿Un año sin anuncios gratis? ¡Clic aquí!
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900487
ESTRUCTURAS DE DATOS Y ALGORITMOS – 2019/20
Tema 3: Map y Tabla de Dispersión Hash

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
MODELO MAP: Es un tipo de diccionario con datos pares (Clave c, valor v). En
este diccionario no hay claves repetidas (por ejemplo, puedo utilizar un map
para obtener una lista de palabras DISTINTAS de un texto)
public interface Map <C, V> {

• public V inserter(C c, V v): inserta o actualiza una Entrada(c,


v) en un map y devuelve un valor (V) que estuviera asociado a
su clave
• public V eliminar (C c): elimina el elemento V asociado a la
clave c y lo devuelve
• public V recuperar (C c): devuelve el valor asociado a la clave

Reservados todos los derechos.


c
• public boolean esVacio(): determina si el Map está vacío
• public int talla(): devuelve el número de entradas del Map
• public ListaConPI<C> claves(): devuelve una lista con PI con
las talla de las claves
}

En la Class String, con el método split() podemos


separar las palabras de una frase

TABLA DE DISPERSIÓN (HASH)

Coste promedio de
localizar una clave en
Map

LINEAL LOGARÍTMICO CONSTANTE


Búsqueda secuencial Búsqueda binaria Búsqueda dinámica
Map es una LEG ordenada o no Map es una Tabla Hash
Map es un Array ordenado
(Array especial)
Map es un Array no ordenado

Ejemplo: Tenemos una lista de 188 países (del 1 al 188) ordenados según su PIB
Las entradas del “Diccionario(d)” son: Clave c = nº del país; Valor v = capital
Lisboa (Portugal) está la nº 38 de la lista. Si lo queremos insertar haríamos:
d.insertar(38, “Lisboa (Portugal)”);

a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900490
En resumen: d es un Map ordenado. ¿Esto qué es? Pues es como si fuese un Array
ordenado, pero el Array está compuesto por pares, es decir, elementos que van
de dos en dos, Clave y Valor. El supuesto array sería:
public Entrada<C,V> [] elArray;
¿Qué problema hay? Que para insertar tenemos que añadir/indexar en el Map, y no
se puede hacer tal cual → necesitamos una clave de dispersión adecuada, es
decir, una función de dispersión estándar → hashCode() //el DNI del objeto

MÉTODO hashCode() DE OBJECT

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
Devuelve ints, con lo que si ya está Integer no hace nada
(solo funciona de String a int)
¿Cómo obtengo el valor hash o de dispersión?
Función de dispersión (Convertimos de String a int)
Para que sea efectiva • Un String es como un Array de char (charAt(i))
elArray.length tiene • Un char i lo podemos codificar con n bits
que ser primo
En un bucle for:

Reservados todos los derechos.


valorIntS = s.charAt(0)*base^(s.length()-1)
+ … + s.charAt(s.length()-1)*base^(0);
public hashCode() {
int valorHash = 0;
for(int i = 0; i < this.clave.length(); i++) {
valorHash = 37 * valorHash + this.clave.charAt(i);
// Si no multiplicásemos por 31, por 37 o por 4 (McKenzie)
//sería un mal método
}
return valorHash;
}
RECORDATORIO: equals
Para String (por ejemplo servidor): this.servidor.equals( (x) o).servidor
Para int (por ejemplo puerto): this.puerto == (x) o).puerto

EJEMPLO: VOY A INSERTAR UNA PALABRA PERO SU hashCode() ES MUY GRANDE Y NO CABE
elArray.length-1 = 46795
d.insertar(“dog”, “perro”); //c.hashCode() = 99644 > 46795
Convertimos el valor hash en una posición válida del Array:
int indiceValido = c.hashCode() % elArray.length();

¿No te llega para pagar Wuolah Pro? ¿Un año sin anuncios gratis? ¡Clic aquí!
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900490
¿Y SI SIGUE SIN CABER?
Aplicamos un if(indiceValido<0) {indiceValido += elArray.length;}

COLISIONES
Ocurren cuando inserto una palabra en el Map en una clave en la que ya
había una palabra y la palabra origen y la a insertar tienen distinto
valor:
!c1.equals(c2) && indiceHash(c1) == indiceHash(c2);

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
2 soluciones:

• Direccionamiento abierto: si vamos a insertar una Entrada en una


posición y ésta está ocupada buscamos la primera libre. Hay dos
tipos de búsqueda/exploración:
o Lineal: Busca secuencialmente a partir de indiceHash+1
(agrupación primaria)
o Cuadrática: Busca en indiceHash+1^(2), indiceHash+2^(2), …
(Agrupación secundaria)

Reservados todos los derechos.


Hashing enlazado o encadenamiento separado: almacenamos las Entradas
que colisionan en una Lista de colisiones (cubeta) asociada a esa
posición
Podemos observar que las
posiciones 1, 4 y 9 tienen
una lista de colisiones. En
cambio, las posiciones 0 y 6
están ocupadas, pero no
tienen aún la cubeta con más
posiciones. Y por último,
los elementos 2, 3, 5, 7 y 8
están vacíos.

Para favorecer la Número primo


dispersión,
elArray.lenth
𝑡𝑎𝑙𝑙𝑎
tiene que ser FC<1; FC =
𝑒𝑙𝐴𝑟𝑟𝑎𝑦.𝑙𝑒𝑛𝑔𝑡ℎ

FC= Factor de carga

¿No te llega para pagar Wuolah Pro? ¿Un año sin anuncios gratis? ¡Clic aquí!
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900490
ANÁLISIS EXPERIMENTAL: TABLA DE DISPERSIÓN
(Para analizar el comportamiento de una tabla Hash de talla X (nº entradas) y
método hashCode())

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
2 métodos

• Calcular y representar el número de colisiones que se producen


conforme aumenta la capacidad de la tabla
70 Una buena función de
60 dispersión sería el
50 gráfico de la
Colisiones

40
30
izquierda, ya que
20 conforme más grande
10 es la capacidad el
0
número de colisiones
2 4 8 16
va bajando
Capacidad

Reservados todos los derechos.


• Calcular y representar el histograma de ocupación junto con la
desviación típica de las cubetas

16 Cuantas más
Nº mínimo de cubetas con

14 cubetas hayan de
12
longitud 0 mejor
10
esa longitud

8
6
4
2
0
8 7 6 5 4 3 2 1 0
Longitud cubeta

REHASHING
(Tenemos que usar rehashing cuando tenemos una mala estimación de la capacidad,
es decir, el FC>1)
¿Qué hace este método?

• Duplica la capacidad de la tabla


• Dispersa las entradas, con lo que reduce el Factor de carga y mejora
la eficiencia
Para hacer el mínimo número de operaciones rehashing determinaremos una
buena capacidad de la tabla (FC~0.75 o <1) y solo haremos rehashing si el
FC de la tabla supera el FC que hemos determinado

a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900490
CÓMO SERÍA EN JAVA
package librerías.estructurasDeDatos.deDispersion;
public class EntradaHash<C,V> {
private C clave;
private V valor;
public entradaHash (C clave, V valor) {
this.clave = clave;

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
this.valor=valor;
}
}
public Class TablaHash <C,V> implements Map<C,V> {
protected ListaConPI<EntradaHash<C,V>>[] elArray;
protected int talla;
protected int indiceHash(C c) {…}

Reservados todos los derechos.



}

¿No te llega para pagar Wuolah Pro? ¿Un año sin anuncios gratis? ¡Clic aquí!
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900490
ESTRUCTURAS DE DATOS Y ALGORITMOS – 2019/20
Tema 4:Map ordenado y Árbol binario de búsqueda

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
MAP ORDENADO
(Es como un Map unido a una lista ordenada)
public interface MapOrdenado<C extends Comparable <C>, V> extends Map<C,V>{
public EntradaMap<C,V> recuperarEntradaMin();
public C recuperarMin();
public EntradaMap<C,V> recuperarEntradaMax();
public C recuperarMax();
public EntradaMap<C,V> sucesorEntrada(C c) ;

Reservados todos los derechos.


public C sucesor(C c);
public EntradaMap<C, V> predecesorEntrada(C c);
public C predecesor(C c);

}
¿CUÁNDO DEBO USAR UN MAP ORDENADO?

• En aplicaciones con restricciones temporales fuertes


• En aplicaciones en las que las claves pertenecen a un conjunto ordenado
Ejemplos de uso:

• Listar entradas de un Map en orden


• Ordenar
• Corrector ortográfico simple
• Suma de subconjuntos
RESUMEN DE LOS COSTES PROMEDIOS
insertar() sucesor() eliminarMin() recuperarMin()
recuperar()
eliminar() predecesor() eliminarMax() recuperarMax()

Θ (1)
LINEAL Θ (x) Θ (x) Θ (x) Θ (x)
Θ (x)
LINEAL
CONTIGUA Θ log 𝑥 Θ (x) Θ log 𝑥 Θ (1) Θ (1)
ORDENADA

TABLA HASH Θ (1) Θ (1) Θ (x) Θ (x) Θ (x)


ÁRBOL
BINARIO DE
Θ log 𝑥 Θ log 𝑥 Θ log 𝑥 Θ log 𝑥 Θ log 𝑥
BÚSQUEDA
EQUILIBRADO

a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900489
ÁRBOL BINARIO DE BÚSQUEDA EQUILIBRADO (ABB)
(Es como un árbol binario normal, pero cumple la propiedad de búsqueda
ordenada)

NODO
RAÍZ

Mayores Menores
que el nodo que el

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
raíz nodo raíz

Ejemplo genérico ABB AB PERO NO ABB

Métodos que podemos usar:

• recuperar(e)
• insertar(e)

Reservados todos los derechos.


eliminar(e)
• recuperarMin()
• recuperarMax()
• eliminarMin()
• eliminarMax()
• sucesor(e)
• predecesor(e)
Operaciones y coste:

• Localizar/buscar un dato (con los métodos de arriba)→O (H)


• Ordenar ascendentemente los datos del ABB→ Θ (H)
• Calcular el tamaño del ABB y de cada nodo→ Θ (1)
• Seleccionar el k-ésimo menor elemento de una colección→O (H)
• Operaciones de rango O (H)
¿CUÁNDO ES UN ABB EQUILIBRADO? →Cuando la diferencia de alturas entre sus
hijos izquierdo y derecho es máximo 1
“Si es completo es equilibrado, pero puede ser equilibrado y no ser completo”
(En los dibujos de la tabla de antes, el ABB no sería equilibrado ya que 3 y 2
están en la altura 3 y 0 en la altura 1, 3-1=2 >1)
Para que sea completo y equilibrado el orden de inserción tiene que ser:

1. Nodo raíz 2. Menores 3. Mayores


*El nodo raíz se obtiene haciendo v[mitad] → v[elArray.length-1/2]

¿No te llega para pagar Wuolah Pro? ¿Un año sin anuncios gratis? ¡Clic aquí!
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900489
EJEMPLO CON 1-2-3-5-7-9
Orden: 5-2-1-3-9-7

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
PASOS PARA CONSTRUIR UN ABB EQUILIBRADO A PARTIR DE UN ARRAY V ORDENADO
ASCENDENTEMENTE:
1. mitad = (elArray.length-1)/2; v[mitad] → nodo raíz
2. Construimos el hijo izquierdo, es decir, de v[0, mitad-1]. ¿Cómo lo
hacemos? Aplicamos a ese subArray v[0, mitad-1] el primer paso

Reservados todos los derechos.


recursivamente
3. Construimos el hijo derecho como el izquierdo, pero son el subArray
v[mitad+1, v.length-1]

¿No te llega para pagar Wuolah Pro? ¿Un año sin anuncios gratis? ¡Clic aquí!
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900489
Resumen-Tema-5-EDA-ESTRUCTURAS-D...

Anónimo

Estructuras de Datos y Algoritmos

2º Grado en Ingeniería Informática

Escuela Técnica Superior de Ingeniería Informática


Universidad Politécnica de Valencia

Reservados todos los derechos.


No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
ESTRUCTURAS DE DATOS Y ALGORITMOS – 2019/20
Tema 5: Cola de prioridad y montículo binario

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
Usaremos:
import librerías.estructurasDeDatos.modelos.ColaPrioridad;
import librerías.estructurasDeDatos.jerarquicos.MonticuloBinario;
COLA DE PRIORIDAD
public interface ColaPrioridad<E extends Comparable<E>>

• ColaPrioridad usa FIFO → First In First Out


• E extends Comparable<E> porque hay que comparar para ver cuál
tenemos que atender antes
• Métodos que hay:

Reservados todos los derechos.


o public void insertar(E e)
o public void eliminarMin()
o public void recuperarMin()
o public boolean esVacia()
MONTÍCULO BINARIO

• El nodo raíz es <= que los hijos


• Si el último nivel no está completo, los nodos estarán situados de
izquierda a derecha
MÉTODO EYTZINGER → Recorro el
montículo por niveles de
izquierda a derecha y los pongo
en un Array.
El nodo raíz va en la casilla 1
elArray =
5 9 11 14 18 19 21 33 17 27

0 1 2 3 4 5 6 7 8 9 10

En el ejemplo podemos observar varias cosas:


• Nodo raíz  elArray[1]
• Hijo izquierdo  elArray[2i]
• Hijo derecho  elArray[2i+1]
• padre (excepto el nodo raíz)  array[i/2]
• Se cumple (menos en i=1 o en i=talla) →
1<i<=talla : elArray[i/2]<=elArray[i]
public Class MonticuloBinario<E extends Comparable<E>> implements
ColaPrioridad<E> {
protected static final int C_P_D = 100; //Aplicar tamaño por defecto
protected E[] elArray;

a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900486
protected int talla;
public MonticuloBinario (int n) {
elArray= (E[]) new Comparable(n);
talla=0;
}
public boolean esVacia() { return talla==0;}
public E recuperarMin() { return elArray[1];}
public E recuperarMax() {

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
int pos = (talla/2) +1;
E max = elArray[pos]; //cogemos la última posición
while(pos <= talla) {
if(elArray[pos].compareTo(max) >0) {
max = elArray[pos];
}
pos++;

Reservados todos los derechos.


}
return max;
}
public int contarHojas(){
return talla – (talla/2);
}

MÉTODO INSERTAR:
1. Calcular la posición de inserción de e y verificar que el dato a insertar
(e) es mayor que su nuevo padre. La posición será talla+1 a no ser que no
cumpla ser mayor que el padre. ¿Qué pasa si no es mayor? Lo cambio por el
padre y en bucle hacemos REFLOTADO de e hasta que todos los nodos padres
sean menores que sus hijos.
2. Insertamos e
public void insertar(E e){
if (talla == elArray.length-1) { //Si no caben más
duplicarArray();
}
int posIns = talla++;
posIns = reflotar(e, posIns); //Propiedad de orden
elArray[posIns] = e; //inserto
}

¿No te llega para pagar Wuolah Pro? ¿Un año sin anuncios gratis? ¡Clic aquí!
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900486
protected int reflotar(E e, int pos) {
while(pos>1 && e.compareTo(elArray[pos/2])<0) { //pos/2=padre
elArray[pos] = elArray[pos/2]; //el hijo será el padre
pos = pos/2; //el antiguo padre es ahora el hijo
}
return pos;
}
MÉTODO ELIMINARMIN

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
1. Borramos el mínimo, o sea, el nodo raíz y ponemos el nodo talla en la
raíz y hacemos talla—
2. Hundimos → Es justo lo contrario que reflotar (de arriba a abajo)
3. Insertamos el dato hundido
public E eliminarMin() {
E elMinimo = elArray[1];
elArray[1] = elArray[talla--]; //elArray[1]=elArray[talla] y talla--
hundir(1);
return elMinimo;

Reservados todos los derechos.


}
protected void hundir(int pos) {
int posActual = pos, hijo = posActual*2; //obtengo el hijo izquierdo
E aHundir = elArray[posActual];
boolean esHeap = false;
while(hijo<=talla && !esHeap) { //hijo no sobrepase talla y false
//Si no está en la última posición && hijo derecho<izquierdo
if(hijo<talla && elArray[hijo+1].compareTo(elArray[hijo])<0){
hijo++;
}
if(elArray[hijo].compareTo(aHundir)<0) { //actual hijo< aHundir
elArray[posActual] = elArray[hijo]; //invierto posiciones
posActual = hijo;
hijo = posActual*2; //obtengo el nuevo hijo de posActual
} else { //si mi Actual hijo > posición a hundir, ya está
esHeap = true; //acabaría el bucle porque no entraría
}
}
elArray[posActual] = aHundir; //Actualizo elArray
}

¿No te llega para pagar Wuolah Pro? ¿Un año sin anuncios gratis? ¡Clic aquí!
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900486
ESTRUCTURAS DE DATOS Y ALGORITMOS – 2019/20
Tema 6: Grafos y estructuras de partición

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
Grafo ponderado → Con peso
Grafo dirigido → Con flechas
MATRIZ DE ADYACENCIA

• Vértices: int
• Aristas: pares de int

Reservados todos los derechos.


LA CLASE GRAFO
public abstract Class Grafo { //todos los métodos deben ser abstractos
public String toString(){ //este no es abstract
String res = “”;
for(int i = 0; i < numVertices(); i++) {
res += “Vertice: ” + i;
ListaConPI<Adyacente> l = adyacentesDe(i);
if(l.esVacia()) { res += “ sin adyacentes.”;}
else { res += “ con adyacentes: ”}
for(l.inicio(); !l.esFin(); l.siguiente()){
res += l.recuperar() + “”;
}
res += “\n”;
}
return res;
}
public abstract int gradoEntrada(int i){ //DIRIGIDO
int grado = 0;
for(int j = 0; j<numVertices(); j++) {
if(existeArista(j, i)) { grado++;}
}
return grado;
}

a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900488
public abstract int gradoEntrada(int i){ //NO DIRIGIDO
return gradoSalida(i);
}
public abstract int gradoSalida(int i) { //DIRIGIDO Y NO DIRIGIDO
return elArray[i].talla();
}
public abstract int numVertices(); // Θ (V)

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
public abstract int numAristas(); // Θ (V)
public abstract Boolean existeArista(int i, int j); //O (|V|)
public abstract void insertaArista(int i, int j); //O (|V|)
public abstract double pesoArista(int i, int j); //O (|V|)
public abstract void insertarArista(int i, int j, double p);
public abstract ListaConPI<Adyacente> adyadencesDe(int i);
}

Reservados todos los derechos.


CLASE ADYACENTE
public class Adyacente {
protected int destino;
protected double peso;
public Adyacente(int v, double p){
destino = v;
peso = p;
}
public int getDestino() { return destino;}
public int getPeso() { return peso;}
public String toString(){
return destino + “(“ + peso + “)”;
}
}
ALCANZABILIDAD → Ver qué vértices de G (Grafo) puedo alcanzar desde v(vértice)
2 posibles estrategias:

• DFS→ Búsqueda en profundidad. Exploración en Pre-Orden de un árbol


• BFS→ Búsqueda en anchura/amplitud. Exploración por niveles de un
árbol

¿No te llega para pagar Wuolah Pro? ¿Un año sin anuncios gratis? ¡Clic aquí!
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900488
TIPOS DE “CAMINOS”

Camino simple: <1,2,5,4>, longitud=3


que es el nº de aristas

Camino no simple: <2,5,4,5>,


longitud=3

Ciclo: <1,2,5,4,1>, longitud = 4

Bucle: <4,5,4,5>, longitud = 3

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
DFS: EXPLORACIÓN EN PROFUNDIDAD
En la clase Grafo:
protected int[] visitados;
protected int ordenVisita;
public void preOrden(Arbol t) { preOrden(raizT);}
public void preOrden(Nodo n) {visitar(n);} //para todos los hijos de n
hacemos preOrden(hijo)
public void dFS(Grafo g) { //Para todos los vértices de V dFS(v)
visitados = new int[numVertices()];
if(visitados[v]==0) {dFS(v);}

Reservados todos los derechos.


}
public void dFS(Vertice v) { //Para todos los adyacentes de v dFS(w)
visitar(v);
//Para todos los adyacentes de v
if(visitados[adyacentes] == 0) {dFS(adyacentes);}
}
//DFS PRE-ORDEN (POST-ORDEN EN LA PÁGINA 22)
public int toArrayDFS(){
int[] res = new int[numVertices()];
ordenVisita = 0;
visitados = new int[numVertices()];
for(int v = 0; v<numVertices(); v++){
if(visitados[v]==0) { //si no se ha visitado
toArrayDFS(v, res);
}
}
return res;
}
protected void toArrayDFS(int v, int[] res) {
res[ordenVisita] = v;
ordenVisita++;
visitados[v] = 1;
ListaConPI<Adyacente> l = adyacentesDe(v);
for(l.inicio(); !l.esFin(); l.siguiente()){
int w = l.recuperar().getDestino();
if(visitados[w] == 0) { toArrayDFS(w, res);}
}
}

¿No te llega para pagar Wuolah Pro? ¿Un año sin anuncios gratis? ¡Clic aquí!
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900488
BFS: BÚSQUEDA EN ANCHURA
En la clase Grafo: (Lo sombreado cambia con respecto al DFS)
protected int[] visitados;
protected int ordenVisita;
protected Cola<Integer> q;
public void porNiveles(Arbol t) { porNiveles(raizT);}
public void porNiveles(Nodo n) {
Cola<Nodo> q = new ArrayCola<Nodo>();
q.encolar();

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
while(!q.esVacia()) {
Nodo n = q.desencolar();
visitar(n);
}
}
public void bFS(Grafo g) {
Cola<Vertice> q = new Arraycola<Vertice>();
if(visitados[0]==0) { bFS(v);}
}
public void bFS(Vertice v) {

Reservados todos los derechos.


q.encolar();
visitar(v);
visitados = 1;
while(!q.esVacia()) {
Vertice w = q.desencolar();
if(visitados[v] == 0) {
visitar(w);
visitados[w]=1;
q.encolar(w);
}
}
}
public int[] toArrayBFS(){
int[] res = new int[numVertices()];
ordenVisita = 0;
visitados = new int[numVertices()];
q = new ArrayCola<Integer>();
for(int v = 0; v<numVertices(); v++){
if(visitados[v]==0) { //si no se ha visitado
toArrayBFS(v, res);
}
}
return res;
}

¿No te llega para pagar Wuolah Pro? ¿Un año sin anuncios gratis? ¡Clic aquí!
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900488
protected void toArrayBFS(int v, int[] res) {
res[ordenVisita] = v;
ordenVisita++;

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
q.encolar(v);
while(!q.esVacia()) {
int n = q.desencolar();
ListaConPI<Adyacente> l = adyacentesDe(v);
for(l.inicio(); !l.esFin(); l.siguiente()){
int w = l.recuperar().getDestino();
if(visitados[w] == 0) {
visitados[w] = 1;
res[ordenVisita++]=w;
q.encolar(w);
}
}

Reservados todos los derechos.


}
}

ENCONTRAR EL CAMINO MÁS CORTO SIN PESOS (desde un vértice al resto)


En la clase Grafo
//Atributos Auxiliares
protected Cola<Integer> q;
protected double[] distanciaMin;
protected int[] caminoMin;
protected static final double INFINITO = Double.POSITIVE_INFINITY;
public void caminosMinimosSinPesos(int v){
caminoMin = new int[numVertices()];
for(int i=0; i<numVertices();i++){ distanciaMin[i]=-1; }
distanciaMin[v]=0;
q=new ArrayCola<Integer>();
caminosBFS(v);
}
protected void caminosBFS(int v){
q.encolar(v);
while(!q.esVacia()){
int n = q.desencolar();
ListaConPI<Adyacente> l = adyacentesDe(n);
for(l.inicio(); !l.esFin(); l.siguiente()){
int w = l.recuperar().getDestino();
if(distanciaMin[w] == INFINITO) {
distanciaMin[w] = distanciaMin[v]+1;
caminoMin[w]=n; q.encolar(w);
}
}
}
}

a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900488
EL CAMINO MÁS CORTO SIN PESOS (entre dos vértices)

public ListaConPI<Integer> caminoMinimoSinPesos (int v, int w) {


caminosMinimosSinPesos(v); //El 1er método de arriba
return decodificarCaminoHasta(w);
}
protected ListaConPI<Integer> decodificarCaminoHasta(w) {
ListaConPI<Integer> res = new LEGListaConPI<Integer> ();
if(distanciaMin[w] != INFINITO) {
res.insertar(w);

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
for(int v = caminoMin[w]; v!=-1;v=caminoMin[v]) {
res.inicio();
res.insertar(v);
}
}
return res;
}

CAMINO MÁS CORTO CON PESOS

Reservados todos los derechos.


public ListaConPI<Integer> caminoMinimo(int v, int w) {
dijkstra(v);
return decodificarCaminoHasta(v);
}

Para implementar Dijkstra necesitamos una subclase VerticeCoste

class VerticeCoste implements Comparable<VerticeCoste> {


//Declaramos los atributos
protected int codigo;
protected double coste;

public VerticeCoste (int cod, double cost) {


codigo = cod;
coste = cost;
}
public int compareTo(VerticeCoste v){
return (coste<v.coste) ? -1 : ((coste>v.coste)? 1 : 0;
//si coste<v.coste → -1, si coste>v.coste → 1, sino → 0
}
}
Ahora podemos implementarlo (siguiente página)
Resumen algoritmo de Dijkstra: Dado un vértice origen (en nuestro caso le
llamaremos u), determina el camino más corto hacia cada destino, es
decir, compara los diversos caminos existentes desde los que se puede
llegar desde el origen al destino y se queda con el más corto (así con
todos los destinos)

¿No te llega para pagar Wuolah Pro? ¿Un año sin anuncios gratis? ¡Clic aquí!
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900488
public void dijkstra(int u) {
distanciaMin = new double[numVertices()];
caminoMin = new int[numVertices()];
for(int i=0; i<numVertices(); i++) {
// “inicializamos” distanciaMin y caminoMin
distanciaMin[i] = INFINITO;
caminoMin[i] = -1;
}
distanciaMin[u] = 0;
visitados = new int[numVertices()];

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
ColaPrioridad<VerticeCoste> qP;
qP = new MonticuloBinario<VerticeCoste> ();
qP.insertar(new VerticeCoste(u, 0)); //código = u, coste = 0
while(!qP.esVacia()){ //mientras que la cola no esté vacía
int v = qP.eliminarMin().codigo; //obtengo el código del mínimo
if(visitados[v]==0) { //si no hemos visitado el mínimo
visitados[v] = 1; //lo visitamos
//Nos creamos una lista con los adyacentes
ListaConPI<Adyacente> l = adyacentesDe(v);
for(l.inicio(); !l.esFin(); l.siguiente) {

Reservados todos los derechos.


//la recorremos para ver cual es la mínima
int w = l.recuperar().destino();
double costeW = l.recuperar().peso; //obtengo peso
//SII la distancia mínima que había > nueva+costeW
if(distanciaMin[w]>distanciaMin[v]+costeW) {
//Actualizamos nueva distanciaMin y camino
distanciaMin[w] = distanciaMin[v] + costeW;
caminoMin[w] = v;
//insertamos en la cola
qP.insertar(new VerticeCoste(w, distanciaMin[w]));
}
}
}
}
}

GRAFO DIRIGIDO Y ACÍCLICO (DAG en inglés)


• Orden Topológico (OT): Orden que podrían seguir los datos
(digamos que es un orden “lógico”)
El DFS post-orden (no siguiento las
flechitas) es:

{SO2,SO,DBD,BDA,EDA,PRG,MDA,ECT,FCO}

El Orden Topológico (siguiengo la


lógica de las flechas) es:

{FCO,ETC,MDA,PRG,EDA,BDA,DBD,SO,SO2}

¿No te llega para pagar Wuolah Pro? ¿Un año sin anuncios gratis? ¡Clic aquí!
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900488
DFS POST-ORDEN (más arriba está el pre-orden)
public int[] finDelDFS(){
int[] res = new int[numVertices()];
ordenVisita = 0;
visitados = new int[numVertices()];
for(int v = 0; v<numVertices(); v++){
if(visitados[v]==0) { finDelDFS(v, res);}
}
return res;
}

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
protected void finDelDFS(int v, int[] res) {
visitados[v] = 1;
ListaConPI<Adyacente> l = adyacentesDe(v);
for(l.inicio(); !l.esFin(); l.siguiente()){
int w = l.recuperar().getDestino();
if(visitados[w]==0) { finDelDFS(w, res);}
}
visitados[v] = 2;
res[ordenVisita] = v;
ordenVisita++;

Reservados todos los derechos.


}
ORDEN TOPOLÓGICO (Lo subrayado es lo que cambia con respecto a Post-Orden)
public int[] ordenTopologicoDFS(){
int[] res = new int[numVertices()];
ordenVisita = 0;
visitados = new int[numVertices()];
for(int v = 0; v<numVertices(); v++){
if(visitados[v]==0) { ordenTopologicoDFS(v, res);}
}
return res;
}
protected void ordenTopologicoDFS(int v, int[] res) {
visitados[v] = 1;
ListaConPI<Adyacente> l = adyacentesDe(v);
for(l.inicio(); !l.esFin(); l.siguiente()){
int w = l.recuperar().getDestino();
if(visitados[w]==0) { ordenTopologicoDFS(w, res);}
}
visitados[v] = 2;
res[numVertices()-1-ordenVisita] = v;
ordenVisita++;
}

TEST DE ACICLICIDAD →Grafo Acíclico (Sin ciclos, obvio)


Arista hacia atrás→ arista que cierra un ciclo, por lo que lo confirma
(w, v) → v precede a w en orden topológico

¿No te llega para pagar Wuolah Pro? ¿Un año sin anuncios gratis? ¡Clic aquí!
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900488
//SII el grafo es un DIGRAFO (grafo dirigido)
//Lo subrayado son las diferencias con toArrayDFS()
public boolean hayCicloDFS(){

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
boolean ciclo = false;
visitados = new int[numVertices()];
for(int v = 0; v<numVertices() && !ciclo; v++){
if(visitados[v] == 0) {ciclo = hayAristaHDFS(v);}
}
return ciclo;
}
protected boolean hayAristaHDFS(int v) {
boolean aristaHA = false;
visitados[v] = 1;
ListaConPI<Adyacente> l = adyacentesDe(v);
for(l.inicio(); !l.esFin() && !aristaHA; l.siguiente()){

Reservados todos los derechos.


int w = l.recuperar().getDestino();
if(visitados[w] == 0) {aristaHA = hayAristaHDFS(w);}
else if (visitados[w]==1) { aristaHA = true;}
}
visitados[v] = 2;
return aristaHA;
}
UNIÓN DE TEST DE ACICLICIDAD + ORDEN TOPOLÓGICO (en dos métodos)
public int[] ordenTopologicoDFS(){
int[] res = new int[numVertices()];
ordenVisita = 0;
visitados = new int[numVertices()];
boolean ciclo = false;
for(int v = 0; v<numVertices() && !ciclo; v++){
if(visitados[v]==0) { ciclo =ordenTopologicoDFS(v, res);}
}
if(!ciclo) {return res;}
return null;
}
protected boolean ordenTopologicoDFS(int v, int[] res) {
boolean aristaHA = false;
visitados[v] = 1;
ListaConPI<Adyacente> l = adyacentesDe(v);
for(l.inicio(); !l.esFin() && !aristaHA; l.siguiente()){
int w = l.recuperar().getDestino();
if(visitados[w]==0) {aristaHA =ordenTopologicoDFS(w, res);}
else if(visitados[w] == 1) {aristaHA = true;}
}
visitados[v] = 2;
res[numVertices()-1-ordenVisita] = v; ordenVisita++;
return aristaHA;
}

a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900488
• Subgrafo de un grafo G → sus vértices y aristas son subconjuntos de
los de G
• Árbol → Grafo conexo, acíclico y no dirigido
• Bosque → Grafo acíclico y no dirigido
• Árbol de recubrimiento → Subgrafo de G que contiene a todos los
vértices de G y un árbol
• Árbol de recubrimiento mínimo → Se obtiene con el algoritmo de Prim
1. Seleccionaremos un vértice como raíz del árbol
▪ E’=0 (aún no hay aristas añadidas)
▪ V’ = {vértice seleccionado

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
2. Seleccionamos su adyacente mínimo, es decir, el adyacente que
tenga el mínimo peso
3. Añadimos el nuevo vértice a V’ y la nueva arista a E’
4. Bucle hasta que |E’| = |V|-1 (el bucle vuelve al 2.)
ALGORITMO DE PRIM
public Arista[] prim() {
visitados = new int[numVertices()];
q = new ArrayCola<Integer>();
Arista[] sTree = new Arista[numVertices() - 1];
ColaPrioridad<Arista> aristasFactibles = new

Reservados todos los derechos.


MonticuloBinario<Arista>();
int i = 0;
// Raíz del árbol T es un vértice cualquiera, por ejemplo, V’ = {0}
q.encolar(0);
visitados[0] = 1;
// para todo vértice u ϵ V’, seleccionar adyacente w ϵ V’
// tal que el peso de la arista (v, w) sea mínimo
while (!q.esVacia() && i < numVertices() - 1 ) {
int u = q.desencolar();
ListaConPI<Adyacente> l = adyacentesDe(u);
for (l.inicio(); !l.esFin(); l.siguiente()) {
int w = l.recuperar().getDestino();
double p = l.recuperar().getPeso();
// si w ∉ V’ entonces insertar arista factible
if (visitados[w] == 0){
aristasFactibles.insertar(new Arista(u, w, p));}
}
// seleccionar arista de peso mínimo, w = min(verticesFactibles)
Arista e = aristasFactibles.eliminarMin();
sTree[i++] = e; // E’ = E’ U (v, w)
// V’ = V’ U w
q.encolar(e.destino);
visitados[e.destino] = 1;
}
if (i == numVertices() - 1) { return sTree; }
else { return null; }
}

¿No te llega para pagar Wuolah Pro? ¿Un año sin anuncios gratis? ¡Clic aquí!
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900488
UF-SET: Dividir un conjunto de N elementos en tantos subconjuntos disjuntos
como establezca en él la Relación “a está conectado con b”
• PORBLEMA de la conectividad o equivalencias dinámicas
Dados los N elementos de un conjunto C, establecer y
representar las clases que determina la relación de
equivalencia (B) (2 tipos)
▪ MODELO DE GESTIÓN DE DATOS: para obtener la partición de
C realizamos
a) find(a) → obtiene la clase de equivalencia del
elemento

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
b) unión(claseA, clase) → une las 2 clases si cumplen
la relación de equivalencia
▪ ALGORITMO DE PARTICIÓN (construcción UF-SET)
a) Inicialización: Crear una partición de C en la que
cada elemento esté en una clase de equivalencia
distinta
b) Paso i: Si dos elementos de C pertenecen a la misma
clase, su unión es innecesaria (para comprobarlo
aplicaríamos un if)
c) Terminación: para cualquier elemento de C, su clase

Reservados todos los derechos.


de equivalencia contiene todos los elementos
relacionados con él
• INTERFAZ UF-SET (solo tiene 2 métodos)
public interface UFSet {
int find (int i);
void unión(int claseI, int claseJ);
}
• Coste amortizado (coste total de todas las operaciones) → Tendremos
que contar que tendremos, en general, más operaciones find que unión
• Tenemos 2 IMPLEMENTACIONES EN UF-SET → Fast-find y Fast-union

FAST-FIND (Es la más sencilla pero también la más costosa)


• Los N elementos se representan en un array de int
• elArray[i] es la clase de equivalencia o subconjunto al que
pertenece el dato i
• Inicialización: Cada elemento del conjunto está en una clase de
equivalencia
¿Por qué es más costosa?
▪ Como máximo se pueden realizar N-1 operaciones de unión en Θ 𝑁 2
▪ Solo será bueno el rendimiento si el nº de operaciones find es mayor
que 𝑁 2 . Si esto pasa, union y find serán constantes
find(i) → Θ (1), es coste constante. P.ej.
EJEMPLO
find(2) = elArray[2] = 2
union(x,y) → Θ (N), tendríamos que rerorrer
elArray. P.Ej. union(0,1)

¿No te llega para pagar Wuolah Pro? ¿Un año sin anuncios gratis? ¡Clic aquí!
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900488
FAST-UNION (Representación jerárquica en bosque, es decir, cada clase de
equivalencia la representamos con un árbol)
• El dato del nodo raíz es el representante de la clase
• Cada nodo tiene un dato de la clase y una referencia a su padre
Costes:
▪ find(i) → O (H=N)
▪ union(x, y) → Θ (1) (constante)
EJEMPLO FAST UNION

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
elArray = 6 3 9 3 3 3 8 3 8 8

Reservados todos los derechos.


0 1 2 3 4 5 6 7 8 9

3 y 8 están en su posición elArray[3] y elArray[8]

Los hijos de 3 son 1, 7, 4 y 5 → en elArray[hijox] ponemos 3

Los hijos de 8 son 6 y 9 → en elArray[hijoy] ponemos 8

El hijo de 6 es 0 → elArray[0] = 6

El hijo de 9 es 2 → elArray[2] = 9

ESTRATEGIAS PARA MEJORAR LA EFICIENCIA


(Se pretende que el coste de m operaciones find sea O(m), para ello
tenemos que reducir/equilibrar la altura de los árboles) 2 tipos
• Combinar por la altura → En union() el árbol de menor altura
pasa a ser hijo de la raíz del de mayor altura, así evita que
el árbol unión “crezca”. Solo cuando 2 árboles tienen la misma
altura, la altura del árbol unión crece.
• Compresión de caminos → En find(i) todo nodo en el camino de i
a la raíz cambia su padre por la raíz
PROBLEMÓN: No son 2 mejoras compatibles porque la 1ª puede cambiar
la altura de los árboles a unir y calcular la nueva altura puede
suponer un esfuerzo computacional muy grande
SOLUCIÓN: Aplicar otra estrategia → Combinar por rango (el valor
almacenado en el nodo raíz de un árbol ya no es su altura, sino una
estimación (cota superior))

SII combinamos Compresión de caminos + Combinar por rango → O(m)

¿No te llega para pagar Wuolah Pro? ¿Un año sin anuncios gratis? ¡Clic aquí!
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900488
COMBINAR POR RANGO
1º Tenemos que disponer del rango de cada árbol, que se guarda
en su nodo raíz en negativo y su valor es el número de nodos

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
del camino más profundo del árbol

SII elArray[y]<0 → i = raíz del árbol


|elArray[i]|-1 es su rango
EJEMPLO

elArray de los
grafos

Grafo 2
Grafo 1
Nuevp elArray

Reservados todos los derechos.


Unión grafo 1 y 2

(fast-union)

podemos ver que no


cambia la altura. Si
el grafo 2 hubiera
tenido una altura
más si que habría
incrementado en 1
EJEMPLO COMPRESIÓN DE CAMINOS

Queremos buscar el 7, que esta a la derecha abajo del todo,


con lo que sus nodos de arriba(9 y 2) pasan a tener como
padre el nodo raíz. LOS DEMÁS NO SE TOCAN

JAVA FOREST UF-SET


public class ForestUFSet implements UFSet {
protected int[] elArray;
public ForestUFSet(int n) {
elArray = new int[n];
for(int i = 0; i<elArray.length; i++) {
elArray[i] = -1;
}
}

a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900488
public int find(int i) {
if(elArray[i]<0) {return i;}
return elArray[i] = find(elArray[i]);
//para la compresión de caminos
}
public void union(int claseI, int claseJ){
//si son iguales (mismo rango)
if(elArray[claseI] == elArray[claseJ]) {
elArray[claseI] = claseJ; //Colgar claseI de claseJ
// “Incrementar” rango de claseJ para tener nº negativo

No se permite la explotación económica ni la transformación de esta obra. Queda permitida la impresión en su totalidad.
elArray[claseJ]--;
} else {//distinto rango → no se incrementa
//si no son iguales hay que comprobar cuál es menor
if(elArray[claseI]<elArray[claseJ]) { //Negativos
elArray[claseJ] = claseI; //Colgar J de I
else {
elArray[claseI] = claseJ; //Colgar I de J
}
}
}

Reservados todos los derechos.


} //fin clase

¿No te llega para pagar Wuolah Pro? ¿Un año sin anuncios gratis? ¡Clic aquí!
a64b0469ff35958ef4ab887a898bd50bdfbbe91a-2900488

También podría gustarte