Logo Studenta

Teórica09

¡Este material tiene más páginas!

Vista previa del material en texto

Algoritmos de ordenamiento sobre secuencias
Algoritmos y Estructuras de Datos I
1
Motivación
4 5 1 2 3 6 7
↓
1 2 3 4 5 6 7
2
Ordenamiento de secuencias
I proc ordenar(inout s : seq〈Z〉){
Pre {s = S0}
Post {mismos(s, S0) ∧ ordenado(s)}
}
I pred mismos(s, t : seq〈Z〉){
(∀e : Z)(#apariciones(s, e) = #apariciones(t, e))
}
I aux #apariciones(s : seq〈T 〉, e : T ) : Z =∑|s|−1
i=0 (if s[i ] = e then 1 else 0 fi)
I pred ordenado(s : seq〈Z〉){
(∀i : Z)(0 ≤ i < |s| − 1→L s[i ] ≤ s[i + 1])
}
3
Ordenamiento de secuencias
I Modificamos la secuencia solamente a través de intercambios
de elementos.
proc swap(inout s : seq〈Z〉, in i , j : Z){
Pre {0 ≤ i , j < |s| ∧ s = S0}
Post {s[i ] = S0[j ] ∧ s[j ] = S0[i ] ∧
(∀k : Z)(0 ≤ k < |s| ∧ i 6= k ∧ j 6= k →L s[k] = S0[k])}
}
I Propiedad 1:
s = S0 → mismos(s, S0)
I Propiedad 2:
{mismos(s, S0)}
swap(s,i,j)
{mismos(s, S0)}
I De esta forma, nos aseguramos que mismos(s,S0) a lo largo
de la ejecución del algoritmo.
4
Ordenamiento por selección (Selection Sort)
I Idea: Seleccionar el ḿınimo elemento e intercambiarlo con la
primera posición de la secuencia. Repetir con el segundo, etc.
4 5 1 2 3 6 7
5
Ordenamiento por selección (Selection Sort)
I Idea: Seleccionar el ḿınimo elemento e intercambiarlo con la
primera posición de la secuencia. Repetir con el segundo, etc.
void selectionSort(vector<int> &s) {
for(int i=0; i<s.size(); i++) {
// indice del minimo elemento de s entre i y s.size()
int minPos = ...
swap(s, i, minPos);
}
}
6
Ordenamiento por selección (Selection Sort)
I Podemos refinar un poco el código:
void selectionSort(vector<int> &s) {
for(int i=0; i<s.size()-1; i++) {
int minPos= findMinPosition(s, i, s.size());
swap(s, i, minPos);
}
}
I Entonces surge la necesidad de especificar el problema auxiliar
de buscar el ḿınimo entre i y s.size():
proc findMinPosition(in s : seq〈Z〉, in d , h : Z, out min : Z){
Pre {0 ≤ d < h ≤ |s|}
Post {d ≤ min < h
∧L (∀i : Z)(d ≤ i < h→L s[min] ≤ s[i ])}
}
7
Buscar el Ḿınimo Elemento
dmin min h
↓ ↓ ↓
4 5 1 2 3 6 7
↑ ↑ ↑ ↑ ↑ ↑
i i i i i i
I ¿Qué invariante de ciclo podemos proponer?
d ≤ min < i ≤ h ∧L
(∀j : Z)(d ≤ j < i →L s[min] ≤ s[j ])
I ¿Qué función variante podemos usar?
fv = h − i
8
Buscar el Ḿınimo Elemento
I Invariante:
d ≤ min < i ≤ h ∧L (∀j : Z)(d ≤ j < i →L s[min] ≤ s[j ])
I Función variante
fv = h − i
I ¿Cómo lo implementamos?
int findMinPosition(vector<int> &s, int d, int h) {
int min = d;
for(int i = d + 1; i < h; i++) {
if (s[i] < s[min]) {
min = i;
}
}
return min;
}
9
Recap: Teorema de corrección de un ciclo
I Teorema. Sean un predicado I y una función fv : V→ Z
(donde V es el producto cartesiano de los dominios de las
variables del programa), y supongamos que I ⇒ def(B). Si
1. PC ⇒ I ,
2. {I ∧ B} S {I},
3. I ∧ ¬B ⇒ QC ,
4. {I ∧ B ∧ V0 = fv} S {fv < V0},
5. I ∧ fv ≤ 0⇒ ¬B,
... entonces la siguiente tripla de Hoare es válida:
{PC} while B do S endwhile {QC}
10
Buscar el Ḿınimo Elemento
I PC ≡ 0 ≤ d < h ≤ |s| ∧min = d ∧ i = d + 1
I QC ≡ d ≤ min < h
∧L(∀i : Z)(d ≤ i < h→L s[min] ≤ s[i ])
I B ≡ i < h
I I ≡ d ≤ min < i ≤ h
∧L (∀j : Z)(d ≤ j < i →L s[min] ≤ s[j ])
I fv = h − i
int findMinPosition(vector<int> &s, int d, int h) {
int min = d;
for(int i=d+1; i<h; i++) {
if (s[i] < s[min]) {
min = i;
}
}
return min;
}
11
Corrección: Buscar el Ḿınimo Elemento
I PC ≡ 0 ≤ d < h ≤ |s| ∧min = d ∧ i = d + 1
I QC ≡ d ≤ min < h
∧L(∀i : Z)(d ≤ i < h→L s[min] ≤ s[i ])
I B ≡ i < h
I I ≡ d ≤ min < i ≤ h
∧L (∀j : Z)(d ≤ j < i →L s[min] ≤ s[j ])
I fv = h − i
I ¿I es se cumple al principio del ciclo (punto 1.)? X
I ¿Se cumple la postcondición del ciclo a la salida del ciclo
(punto 3.)? X
I ¿Si la función variante alcanza la cota inferior la guarda se
deja de cumplir (punto 5.)? X
12
Corrección: Buscar el Ḿınimo Elemento
I I ≡ d ≤ min < i ≤ h
∧L (∀j : Z)(d ≤ j < i →L s[min] ≤ s[j ])
I fv = h − i
int findMinPosition(vector<int> &s, int d, int h) {
int min = d;
for(int i=d+1; i<h; i++) {
if (s[i] < s[min]) {
min = i;
}
}
return min;
}
I ¿I se preserva en cada iteración (punto 2.)? X
I ¿La función variante es estrictamente decreciente (punto
4.)?X
13
Ordenamiento por selección (Selection Sort)
I Volvamos ahora al programa de ordenamiento por selección:
void selectionSort(vector<int> &s) {
for(int i=0; i<s.size(); i++) {
int minPos = findMinPosition(s, i, s.size());
swap(s, i, minPos);
}
}
I PC ≡ i = 0 ∧ s = S0
I QC ≡ mismos(s, S0) ∧ ordenado(s)
I B ≡ i < |s|
I I ≡ ?
I ¡Luego de la i-ésima iteración, subseq(s, 0, i) contiene los i
primeros elementos ordenados! ¿Tenemos entonces el
invariante del ciclo?
I I ≡ mismos(s,S0)∧ ((0 ≤ i ≤ |s|)∧L ordenado(subseq(s, 0, i)))
I fv = |s| − i
14
Ordenamiento por selección (Selection Sort)
I I ≡ mismos(s, S0)∧((0 ≤ i ≤ |s|)∧Lordenado(subseq(s, 0, i)))
I fv = |s| − i
void selectionSort(vector<int> &s) {
for(int i=0; i<s.size(); i++) {
int minPos = findMinPosition(s, i, s.size());
swap(s, i, minPos);
}
}
I ¿I se preserva en cada iteración (punto 2.)? 7
I Contraejemplo:
I Si arrancamos la iteración con i = 1 y s = 〈100, 2, 1〉
I Terminamos con i = 2 y s = 〈100, 1, 2〉 que no satisface I
Debemos reforzar el invariante para probar la corrección:
I ≡ mismos(s, S0) ∧ ((0 ≤ i ≤ |s|) ∧L
(
ordenado(subseq(s, 0, i)))∧
(∀j , k : Z)((0 ≤ j < i ∧ i ≤ k < |s|)→L s[j ] ≤ s[k]))
15
Corrección: Ordenamiento por selección (Selection Sort)
I ≡ mismos(s,S0) ∧ ((0 ≤ i ≤ |s|) ∧L
(
ordenado(subseq(s, 0, i))) ∧
(∀j , k : Z)((0 ≤ j < i ∧ i ≤ k < |s|)→L s[j ] ≤ s[k]))
Gráficamente:
x ∈ subseq(s, 0, i) y ∈ subseq(s, i + 1, |s|)
≤ y ≥ x
ordenado ?
16
Corrección: Ordenamiento por selección (Selection Sort)
I PC ≡ i = 0 ∧ s = S0
I QC ≡ mismos(s, S0) ∧ ordenado(s)
I B ≡ i < |s|
I I ≡ mismos(s, S0) ∧ ((0 ≤ i ≤ |s|)∧L
(ordenado(subseq(s, 0, i))) ∧ (∀j , k : Z)((0 ≤ j < i ∧ i ≤ k <
|s|)→L s[j ] ≤ s[k]))
I fv = |s| − i
I ¿I es se cumple al principio del ciclo (punto 1.)? X
I ¿Se cumple la postcondición del ciclo a la salida del ciclo
(punto 3.)?X
I ¿Si la función variante alcanza la cota inferior la guarda se
deja de cumplir (punto 5.)?X
17
Corrección: Ordenamiento por selección (Selection Sort)
I I ≡ mismos(s, S0) ∧ ((0 ≤ i ≤ |s|)∧L
(ordenado(subseq(s, 0, i))) ∧ (∀j , k : Z)((0 ≤ j < i ∧ i ≤ k <
|s|)→L s[j ] ≤ s[k]))
I fv = |s| − i
void selectionSort(vector<int> &s) {
for(int i=0; i<s.size(); i++) {
int minPos = findMinPosition(s, i, s.size());
swap(s, i, minPos);
}
}
I ¿I se preserva en cada iteración (punto 2.)? X
I ¿La función variante es estrictamente decreciente (punto
4.)?X
18
Ordenamiento por selección (Selection Sort)
int findMinPosition(vector<int> &s, int d, int h) {
int min = d;
for(int i=d+1; i<h; i++) {
if (s[i] < s[min]) {
min = i;
}
}
return min;
}
void selectionSort(vector<int> &s) {
for(int i=0; i<s.size(); i++) {
int minPos = findMinPosition(s,i,s.size());
swap(s, i, minPos);
}
}
I ¿Cómo se comporta este algoritmo?
I Veámoslo en https://visualgo.net/es/sorting.
19
https://visualgo.net/es/sorting
Tiempo de ejecución de peor caso
findMinPosition
I Sea n = |s| ¿cuál es el tiempo de ejecución de peor caso de
findMinPosition?
int min = d; c1 1
for(int i=d+1; i<h; i++) { c2 n
if (s[i] < s[min]) { c3 n − 1
min = i; c4 n − 1
}
}
return min; c5 1
I TfindMinPosition(n) = 1∗c1+n∗c2+(n−1)∗c3+(n−1)∗c4+1∗c5
I TfindMinPosition(n) ∈ O(n)
I Decimos que findMinPosition tiene un tiempo de ejecución
de peor caso lineal en función de la longitud de la secuencia.
20
Tiempo de ejecución de peor caso
selectionSort
I Sea n = |s| ¿cuál es el tiempo de ejecución de peor caso para
el programa selectionSort?
for(int i=0; i<s.size(); i++) { c ′1 n + 1
int minPos=findMinPosition(s,i,s.size()); c ′2 ∗ n n
swap(s, i, minPos); c ′3 n
}
I TselectionSort(n) = (n + 1) ∗ c ′1 + n ∗ n ∗ c ′2 + n ∗ c ′3
I TselectionSort(n) ∈ O((n + 1) ∗ n) = O(n2 + n) = O(n2)
I Decimos que selectionSorttiene un tiempo de ejecución de
peor caso cuadrático en función de la longitud de la secuencia.
21
Ordenamiento por selección (Selection Sort)
I Variantes del algoritmo básico:
1. Cocktail sort: consiste en buscar en cada iteración el máximo y
el ḿınimo del vector por ordenar, intercambiando el ḿınimo
con i y el máximo con |s| − i − 1.
2. Bingo sort: consiste en ubicar todas las apariciones del valor
ḿınimo en el vector por ordenar, y mover todos los valores
ḿınimos al mismo tiempo (efectivo si hay muchos valores
repetidos).
I El tiempo de ejecución de peor caso de ambas variantes en
función de n = |s| es:
I TcocktailSort(n) ∈ O(n2)
I TbingoSort(n) ∈ O(n2)
I Por lo tanto, ambas variantes de selectionSort tienen el
“mismo” tiempo de ejecución de peor caso (cuadrático)
22
Ordenamiento por inserción (Insertion Sort)
I Veamos otro algoritmo de ordenamiento, pero donde el
invariante (a diferencia de selectionSort) es:
I ≡ mismos(s, S0)∧(0 ≤ i ≤ |s| ∧L ordenado(subseq(s, 0, i)))
I Esto implica que en cada iteración los primeros i elementos
están ordenados, sin ser necesariamente los i elementos más
pequeños del vector.
I La función variante de este algoritmo de ordenamiento (al
igual que selectionSort) es:
fv = |s| − i
23
Ordenamiento por inserción (Insertion Sort)
I ≡ mismos(s,S0) ∧ (0 ≤ i ≤ |s| ∧L ordenado(subseq(s, 0, i)))
void insertionSort(vector<int> &s) {
for(int i=0; i<s.size(); i++) {
// Tenemos que preservar el invariante...
}
}
I ¿I es se cumple al principio del ciclo (punto 1.)? X
I ¿Se cumple la postcondición del ciclo a la salida del ciclo
(punto 3.)? X
I ¿I se preserva en cada iteración (punto 2.)?
I Sabiendo que los primeros i elementos están ordenados,
tenemos que hacer que los primeros i + 1 elementos pasen a
estar ordenados!
I ¿Cómo lo podemos hacer?
24
Ordenamiento por inserción (Insertion Sort)
Necesitamos desplazar s[i ] hasta una posición donde subseq(s,0,i)
esté ordenada de vuelta. Ejemplo, ya están ordenadas las primeras
3 posiciones.
1 4 5 2 3 6 7
↑
i
1 4 5 2 3 6 7
↑
i , j
1 4 2 5 3 6 7
↑ ↑
j i
1 2 4 5 3 6 7
↑ ↑
j i
25
Ordenamiento por inserción (Insertion Sort)
I Antes de comenzar el desplazamiento, tenemos que:
ordenada
?
subseq(s, 0, i) subseq(s, i , |s|)
I Durante el desplazamiento, se cumple que que:
ordenada ordenada
x > x ?
subseq(s, 0, j) s[j ] subseq(s, j + 1, i + 1) subseq(s, i + 1, |s|)
I Al finalizar el desplazamiento, nuevamente tenemos que:
ordenada
?
subseq(s, 0, i + 1) subseq(s, i + 1, |s|)
26
Ordenamiento por inserción (Insertion Sort)
I Llamemos insert a la función auxiliar que desplaza el
elemento s[i] ¿cuál es el invariante para esta función?
I ≡ 0 ≤ j ≤ i
∧ mismos(subseq(s, 0, i + 1), subseq(S0, 0, i + 1))
∧ subseq(s, i + 1, |s|) = subseq(S0, i + 1, |s|)
∧ ordenado(subseq(s, 0, j)) ∧ ordenado(subseq(s, j , i + 1))
∧ (∀k : Z)(j < k ≤ i →L s[j ] < s[k])
I ¿Cuál es la función variante de insert?
fv = j
27
Ordenamiento por inserción (Insertion Sort)
I ¿Cuál es una posible implementación de insert?
void insert(vector<int> &s, int i) {
for(int j=i; j>0 && s[j] < s[j-1]; j--) {
swap(s, j, j-1);
}
}
I ¿Cuál es una posible implementación de insertSort?
void insertionSort(vector<int> &s) {
for(int i=0; i<s.size(); i++) {
insert(s,i);
}
}
I ¿Cómo se comporta este algoritmo de ordenamiento?
I Veámoslo en https://visualgo.net/es/sorting.
28
https://visualgo.net/es/sorting
Tiempo de ejecución de peor caso
insert
I Sea n = |s| ¿cuál es el tiempo de ejecución de peor caso de
insert?
for(int j=i; j>0 && s[j] < s[j-1]; j--) { c ′′1 n + 1
swap(s, j, j-1); c ′′2 n
}
I Tinsert(n) = c ′′1 ∗ (n + 1) + c ′′2 ∗ n
I Tinsert(n) ∈ O(n)
I insert tiene tiempo de ejecución de peor caso lineal.
29
Tiempo de ejecución de peor caso
insertSort
I Sea n = |s| ¿cuál es el tiempo de ejecución de peor caso de
insertSort?
for(int i=0; i<s.size(); i++) { c ′′′1 n + 1
insert(s, i); c ′′′2 ∗ n n
}
I TinsertSort(n) = c ′′′1 ∗ (n + 1) + c ′′′2 ∗ n ∗ n
I TinsertSort(n) ∈ O(n2)
I insertSort tiene tiempo de ejecución de peor caso
cuadrático (igual que selectionSort)
30
El problema de la bandera holandesa
Dado una secuencia que contiene colores (rojo, blanco y azul)
ordenarlos de modo que respeten el orden de la bandera holandesa
(primero rojo, luego blanco y luego azul)
Por ejemplo, si la secuencia es:
〈White,Red ,Blue,Blue,Red〉
El programa debe modificar la secuencia para que quede:
〈Red ,Red ,White,Blue,Blue〉
31
El problema de la bandera holandesa
I Si Red=1,White=2 y Blue=3, ¿Cuál seŕıa la especificación del
problema?
I proc banderaHolandesa(inout s : seq〈Z〉){
Pre {s = S0 ∧ (∀e : Z)(e ∈ s ↔ (e = 1 ∨ e = 2 ∨ e = 3))}
Post {mismos(s, S0) ∧ ordenado(s)}
}
I ¿Cómo podemos implementar una solución a este problema?
I ¿Podemos usar algún algoritmo de ordenamiento que
conozcamos? Rta: podemos usar insertionSort o
selectionSort.
I ¿Cuál es tiempo de ejecución de peor caso? Rta:
TbanderaHolandesa(n) ∈ O(|s|2)
I ¿Podemos buscar otra solución que tenga un tiempo de
ejecución de peor caso lineal?
32
Idea de solución
2 2 1 2 3 1 2
#1 = 2,#2 = 4,#3 = 1
↓
1 1 2 2 2 2 3
33
Eficiencia de los Algoritmos de ordenamiento
I Tanto selection sort como insertion sort son algoritmos
cuadráticos (iteran una cantidad cuadrática de veces)
I ¿Hay algoritmos con comportamiento más eficiente en peor
caso?
I Quicksort y BubbleSort: Peor caso: O(n2)
I Mergesort y Heapsort: Peor caso: O(n ∗ log(n))
I Counting sort (para secuencias de enteros acotados). Peor
caso: O(n)
I Radix sort (para secuencias de enteros). Peor caso:
O(232) = O(1)
O(1) < O(n) < O(n × log(n)) < O(n2)
34
Órden de los órdenes
O(1) < O(n) < O(n × log(n)) < O(n2)
n
O(n²)
O(n.log n)
O(n)
O(1)
35
Bibliograf́ıa
I Vickers et al. - Reasoned Programming
I 6.5 - Insertion Sort
I NIST- Dictionary of Algorithms and Data Structures
I Selection Sort - https://xlinux.nist.gov/dads/HTML/selectionSort.html
I Bingo Sort - https://xlinux.nist.gov/dads/HTML/bingosort.html
I Cocktail Sort - https://xlinux.nist.gov/dads/HTML/bidirectionalBubbleSort.html
I Cormen et al. - Introduction to Algorithms
I Chapter 2.1 - Insertion Sort
36

Otros materiales