Descargar la presentación
La descarga está en progreso. Por favor, espere
Publicada porBenito Lara Miranda Modificado hace 7 años
1
Estructuras de Datos ● Introducción y Heaps ● Docentes: ● Eugenia Simich ● Juan Manuel Rabasedas ● Sergio Giro
2
Cómo empezar?
3
● Mi definición: ”Organización sistemática de los datos para permitir una administración eficiente de los mismos usando un conjunto de operaciones”
4
Cómo empezar? ● Mi definición: ”Organización sistemática de los datos para permitir una administración eficiente de los mismos usando un conjunto de operaciones” ● Wikipedia: ”Es una manera particular de guardar y organizar datos en una computadora para que puedan ser usados de manera eficiente”
5
Ejemplos ● (No necesariamente informáticos) ● Agenda (organización sistemática? operaciones? eficientes?) ● Guía telefónica ● Planilla ● Guía turística ● Mapa de la ciudad
6
Arreglos/vectores ● Usos: geometría cartesiana (entre otros) ● Operaciones necesarias: ● Poner el valor para una componente ● Tomar el valor de una componente ● Operaciones derivadas: ● Suma, producto interno...
7
Arreglos/vectores ● Organización sistemática:
8
Arreglos/vectores ● Organización sistemática: ● Organizo las componentes como factores primos de un número ● (4,1,8) → = 18750000 ● Leer la n-sima componente: descomponer el número y obtener la potencia correspondiente al n- simo primo ● Asignar la n-sima componente: dividir por p^{m} y multiplicar por p^{n}. Donde p es el n-simo primo, m es el valor anterior y n es el nuevo valor
9
Arreglos/vectores ● Organización sistemática: ● En un modelo de memoria lineal: ● Reservo espacio para n enteros a partir de la posicion b ● La n-sima componente es el entero en la posicion b+n ● Leer la n-sima componente: buscar el entero en la posicion b+n ● Asignar la n-sima componente: poner el nuevo valor en la posicion b+n
10
Arreglos/vectores ● Operaciones: ● Crear: Int → Arreglo ● Leer: Arreglo x Int → Int ● Asignar: Arreglo x Int x Int→ Arreglo ● Leer(a,i) se anota a[i] ● Asignar(a,i,j) es arreglo a despues de hacer a[i] = j ● Crear(n) en lenguaje C: malloc(n*sizeof(int))
11
Arreglos/vectores ● Operación derivada: producto interno ● prod: Arreglo x Arreglo → Int ● int prod (a,b,n) { ● int res = 0; ● for(int i = 0; i < n; i++) { ● res += a[i]*b[i]; ● } ● return res; ● }
12
(Min) Heaps ● Estructura de datos con las siguientes operaciones ● insertar : Heap x Int → Heap ● borrar_min : Heap → Heap ● obtener_minimo : Heap → Int ● Se utiliza para implementar colas de prioridad (priority queues)
13
(Min) Heaps ● Los heaps son colas de prioridad en las que los datos pueden recorrerse en forma de árbol ● En cada subárbol, la raíz es el elemento mínimo del subárbol 9 2 5 67 1010
14
(Min) Heaps ● Para explicitar la estructura de árbol podemos agregar una operación adicional: ● descomponer: Heap → Heap x Int x Heap 9 2 5 67 1010 5 67 5 67 5 67 2 9 1010
15
Representación ● Podemos representar un árbol (y por lo tanto un heap) utilizando arreglos 9 2 1313 1515 5 67 8 9090 8 9090 8 9090 1010 4040 8 9090 1414 2525 8 9090 2424 2323 0 12 3 46 5 7891011121314 2 5 9 6 7 13 15 8 90 10 40 14 25 24 23 0 01 2 3 4 5 6 7 8 9 10 11 12 13 14 ● Se puede probar por inducción: ● el hijo izquierdo del nodo n está en la posición 2n+1 ● el hijo derecho en la posición 2n+2 ● padre(n) = (n-1) div 2
16
Representación descomponer(h) = descomponer( (a,r,s) ) = ((a,2r+1,s), a[r], (a,2r+2,s)) 9 2 1313 1515 5 67 8 9090 8 9090 8 1010 0 12 3 4 789 0 5 6 ● Para implementar la función descomponer podemos tener, además del arreglo, un entero r indicando la raíz ● Para saber si un nodo tiene hijos, alcanza con guardar la ultima posicion ocupada ● h = (a,r,s)
17
Implementación de las operaciones 9 2 1313 1515 5 67 8 9090 8 9090 8 1010 0 12 3 4 789 0 5 6 ● insertar: puedo poner el nuevo elemento al final del arreglo 3
18
Implementación de insertar 9 2 1313 1515 5 67 8 9090 8 9090 8 1010 0 12 3 4 789 0 5 6 ● insertar: puedo poner el nuevo elemento al final del arreglo ● No cumple la propiedad de heap 3
19
Implementación de insertar 9 2 1313 1515 5 67 8 9090 8 9090 8 1010 0 12 3 4 789 0 5 6 ● insertar: puedo poner el nuevo elemento al final del arreglo ● No cumple la propiedad de heap ● Podemos hacer que el subarbol cumpla la propiedad intercambiando el valor con el nodo superior 3 7 8 1010 4 9 3 7 8 1010 4 9 3 3 8 1010 4 9 7
20
Implementación de insertar 2 5 63 8 9090 8 9090 8 1010 0 1 3 4 789 ● El nuevo árbol tampoco cumple la propiedad de heap 7...
21
Implementación de insertar 2 5 63 8 9090 8 9090 8 1010 0 1 3 4 789 ● El nuevo árbol tampoco cumple la propiedad de heap ● Pero puedo intercambiar nuevamente 7... 3 65 8 9090 8 9090 8 1010 1 3 4 7 7
22
Implementación de insertar 9 2 1313 1515 3 65 8 9090 8 9090 8 1010 0 12 3 4 789 0 5 6 ● Finalmente cumple con la propiedad de heap 7
23
Implementación de insertar 9 2 1313 1515 3 65 8 9090 8 9090 8 1010 0 12 3 4 789 0 5 6 ● insertar ( (a,r,s), n) es un heap (a',r',s') en el que: ● s' = s+1 ● r' = r ● a' es el arreglo luego de ejecutar: a[s+1] = n; flotar(a,s+1); 7 10
24
Implementación de insertar ● void flotar(int a[], int r) { ● while(padre(r) != r ● && a[r] < a[padre(r)]) { ● swap(a,r,padre(r)); ● r = padre(r); ● } ● void swap(int a[], int p, int q) { ● int aux = a[p]; ● a[p] = a[q]; ● a[q] = aux; ● } ● int padre(int i){ if(i ==0) return 0; return (i-1)/2; }
25
Corrección de insertar ● void flotar(int a[], int r) { ● while(padre(r) != r ● && a[r] < a[padre(r)]) { ● swap(a,r,padre(r)); ● r = padre(r); ● } ● Invariante: al finalizar el bucle, vale la propiedad de heap excepto que puede ser a[u] > a[r] si r desciende de u ● Sea c el valor de la variable r al comenzar el bucle, d el valor de r al terminar, sea a' el valor del arreglo al terminar ● Debemos demostrar a'[u] <= a'[t] para todo u, t tal que t es descendiente de u, t != d ● Consideramos diferentes casos para t y u ● Caso t = c Si u = padre(c), dado que entramos al bucle, teníamos a[c] = a'[padre(c)] = a'[u] u c = t ` u ` < >
26
Corrección de insertar ● void flotar(int a[], int r) { ● while(padre(r) != r ● && a[r] < a[padre(r)]) { ● swap(a,r,padre(r)); ● r = padre(r); ● } ● Invariante: al finalizar el bucle, vale la propiedad de heap excepto que puede ser a[u] > a[r] si r desciende de u ● Sea c el valor de la variable r al comenzar el bucle, d el valor de r al terminar, sea a' el valor del arreglo al terminar ● Debemos demostrar a'[u] <= a'[t] para todo u, t tal que t es descendiente de u, t != d ● Consideramos diferentes casos para t y u ● Caso t = c Si u != padre(c), por hipótesis a[u] <= a[d] = a'[c] d c = t ` u ` < > d u <=
27
Corrección de insertar ● void flotar(int a[], int r) { ● while(padre(r) != r ● && a[r] < a[padre(r)]) { ● swap(a,r,padre(r)); ● r = padre(r); ● } ● Invariante: al finalizar el bucle, vale la propiedad de heap excepto que puede ser a[u] > a[r] si r desciende de u ● Sea c el valor de la variable r al comenzar el bucle, d el valor de r al terminar, sea a' el valor del arreglo al terminar ● Debemos demostrar a'[u] <= a'[t] para todo u, t tal que t es descendiente de u, t != d ● Consideramos diferentes casos para t y u ● Caso t = padre(c) En este caso t = d, no debemos demostrar nada d = padre(c) = t c ` c ` < >
28
Corrección de insertar ● void flotar(int a[], int r) { ● while(padre(r) != r ● && a[r] < a[padre(r)]) { ● swap(a,r,padre(r)); ● r = padre(r); ● } ● Invariante: al finalizar el bucle, vale la propiedad de heap excepto que puede ser a[u] > a[r] si r desciende de u ● Sea c el valor de la variable r al comenzar el bucle, d el valor de r al terminar, sea a' el valor del arreglo al terminar ● Debemos demostrar a'[u] <= a'[t] para todo u, t tal que t es descendiente de u, t != d ● Consideramos diferentes casos para t y u ● Caso u = c Como la invariante valía, antes del bucle tenemos a[d] <= a[t]. Después del bucle a'[u] = a'[c] = a[d] <= a[t] = a'[t] c = u t ` d t ` d <=
29
Corrección de insertar ● void flotar(int a[], int r) { ● while(padre(r) != r ● && a[r] < a[padre(r)]) { ● swap(a,r,padre(r)); ● r = padre(r); ● } ● Invariante: al finalizar el bucle, vale la propiedad de heap excepto que puede ser a[u] > a[r] si r desciende de u ● Sea c el valor de la variable r al comenzar el bucle, d el valor de r al terminar, sea a' el valor del arreglo al terminar ● Debemos demostrar a'[u] <= a'[t] para todo u, t tal que t es descendiente de u, t != d ● Consideramos diferentes casos para t y u ● Caso u = c Como la invariante valía, antes del bucle tenemos a[d] <= a[t]. Después del bucle a'[u] = a'[c] = a[d] <= a[t] = a'[t] c = u t ` d t ` d <=
30
Corrección de insertar ● void flotar(int a[], int r) { ● while(padre(r) != r ● && a[r] < a[padre(r)]) { ● swap(a,r,padre(r)); ● r = padre(r); ● } ● Invariante: al finalizar el bucle, vale la propiedad de heap excepto que puede ser a[u] > a[r] si r desciende de u ● Sea c el valor de la variable r al comenzar el bucle, d el valor de r al terminar, sea a' el valor del arreglo al terminar ● Debemos demostrar a'[u] <= a'[t] para todo u, t tal que t es descendiente de u, t != d ● Consideramos diferentes casos para t y u ● Caso u = padre(c) Suponemos t != c (el caso u = padre(c), t = c fue el primero que vimos). En este caso a'[u] = a[c] < a[u] <= a[t] = a'[t] c t ` d = u = padre(c) t ` c d <= ><
31
Corrección de insertar ● void flotar(int a[], int r) { ● while(padre(r) != r ● && a[r] < a[padre(r)]) { ● swap(a,r,padre(r)); ● r = padre(r); ● } ● Invariante: al finalizar el bucle, vale la propiedad de heap excepto que puede ser a[u] > a[r] si r desciende de u ● Sea c el valor de la variable r al comenzar el bucle, d el valor de r al terminar, sea a' el valor del arreglo al terminar ● Debemos demostrar a'[u] <= a'[t] para todo u, t tal que t es descendiente de u, t != d ● En los otros casos la prueba es trivial (los valores de a y a' sólo cambian para c y padre(c) )
32
Corrección de insertar ● void flotar(int a[], int r) { ● while(padre(r) != r ● && a[r] < a[padre(r)]) { ● swap(a,r,padre(r)); ● r = padre(r); ● } ● Invariante: al finalizar el bucle, vale la propiedad de heap excepto que puede ser a[u] > a[r] si r desciende de u ● Una vez que el bucle sale, a[padre(r)] <= a[r]. Además, como vale la invariante, para todos los ancestros u de padre(r) tenemos a[u] <= a[padre(r)]. Por ende, a[u] <= a[r] para todo ancestro u de r. Junto con la invariante, esto asegura a[u] <= a[t] para todo u ancestro de t
33
Implementacion de borrar_min ● Sobreescribo la raíz con el último elemento 9 2 1313 1515 3 65 8 9090 8 9090 8 1010 9 7 1313 1515 3 65 8 9090 8 9090 8 1010 9 2 1313 1515 3 65 8 9090 8 9090 8 1010 7 9 2 1313 1515 3 65 8 9090 8 9090 8 1010 7 ● De nuevo, no cumple con la propiedad de heap ● Puedo intercambiar la raíz con la raíz de un subárbol cuyo valor sea mínimo
34
Implementacion de borrar_min ● Sobreescribo la raíz con el último elemento 9 2 1313 1515 3 65 8 9090 8 9090 8 1010 9 3 1313 1515 7 65 8 9090 8 9090 8 1010 9 2 1313 1515 3 65 8 9090 8 9090 8 1010 9 7 1313 1515 3 65 8 9090 8 9090 8 1010 ● De nuevo, no cumple con la propiedad de heap ● Puedo intercambiar la raíz con la raíz de un subárbol cuyo valor sea mínimo
35
Implementacion de borrar_min ● Sobreescribo la raíz con el último elemento 9 2 1313 1515 3 65 8 9090 8 9090 8 1010 9 3 1313 1515 5 67 8 9090 8 9090 8 1010 9 2 1313 1515 3 65 8 9090 8 9090 8 1010 9 3 1313 1515 7 65 8 9090 8 9090 8 1010 ● De nuevo, no cumple con la propiedad de heap ● Puedo intercambiar la raíz con la raíz de un subárbol cuyo valor sea mínimo (notar que si subía el 6, quedaba el 6 sobre el 5). En este caso el 7 ”se hunde”
36
Implementacion de borrar_min ● borrar(a,r,s) = (a', r', s') ● donde ● s'=s-1 ● r' = r ● a' es el arreglo a después de hacer: a[0] = a[s]; hundir(a,0,s-1); void hundir(int a[], int pos, int size) { int swapPos=pos; if(hijo_izq(pos) <= size && a[hijo_izq(pos)] < a[pos]) { swapPos = hijo_izq(pos); } //swapPos tiene la posición con valor // mínimo entre pos e hijo_izq(pos) if(hijo_der(pos) <= size && a[hijo_der(pos)] < a[swapPos]) { swapPos = hijo_der(pos); } //swapPos tiene la posición con valor // mínimo entre pos, hijo_izq(pos) e // hijo_der(pos) if (pos != swapPos) { swap(a, pos, swapPos); hundir(a, swapPos); } }
Presentaciones similares
© 2024 SlidePlayer.es Inc.
All rights reserved.