PDF de programación - Capítulo 3 - Diseño de algoritmos iterativos

Imágen de pdf Capítulo 3 - Diseño de algoritmos iterativos

Capítulo 3 - Diseño de algoritmos iterativosgráfica de visualizaciones

Publicado el 24 de Septiembre del 2019
965 visualizaciones desde el 24 de Septiembre del 2019
454,6 KB
24 paginas
Creado hace 8a (09/10/2015)
Diseño de algoritmos iterativos1

Capítulo 3

Cada cosa tiene su belleza, pero no todos pueden
verla.

Confucio

Resumen: En este tema se introducen los conceptos de verificación y derivación de
algoritmos como métodos que nos permiten razonar sobre la corrección de un algoritmo
y su correcta construcción respectivamente.

1.

Introducción

En el capítulo anterior se ha visto la posibilidad de utilizar predicados para definir
conjuntos de estados y cómo es posible especificar un algoritmo mediante dos predicados
llamados precondición y postcondición. El primero describe el conjunto de estados válidos
al comienzo del algoritmo y el segundo el conjunto de estados alcanzables con la ejecución
del algoritmo.

En este capítulo representaremos los estados intermedios de un algoritmo mientras se
ejecuta utilizando predicados, generalmente denominados aserciones o asertos. Escribiendo
asertos entre cada dos instrucciones tenemos un modo de razonar sobre la corrección de
un programa imperativo.

2. Reglas prácticas para el cálculo de la eficiencia

1. Las instrucciones de asignación, de entrada-salida, los accesos a elementos de un
vector y las expresiones aritméticas y lógicas (siempre que no involucren variables
cuyos tamaños dependan del tamaño del problema) tendrán un coste constante, Θ(1).
No se cuentan los return.

2. Para calcular el coste de una composición secuencial de instrucciones, S1; S2 se suman
los costes de S1 y S2. Si el coste de S1 está en Θ(f1(n)) y el de S2 está en Θ(f2(n)),
entonces: Θ(f1(n) + f2(n)) = Θ(máx(f1(n), f2(n))).

3. Para calcular el coste de una instrucción condiciónal:

1Ramón González del Campo es el autor principal de este tema.

25

26

Capítulo 3. Diseño de algoritmos iterativos

if (B) {S1} else {S2}

Si el coste de S1 está en O(f1(n)), el de S2 está en O(f2(n)) y el de B en O(fB(n)),
podemos señalar dos casos para el condiciónal:

Caso peor: O(máx(fB(n), f1(n), f2(n)).
Caso promedio: O(máx(fB(n), f (n)) donde f (n) es el promedio de f1(n) y f2(n).

Se pueden encontrar expresiones análogas a éstas para la clase Omega.

4. Bucles con la forma:

while (B)

{
S
}

Para calcular el coste de tal bucle hay que calcular primero el coste de cada pasada
y después sumar los costes de todas las pasadas que se hagan en el bucle. El número
de iteraciones dependerá de lo que tarde en hacerse falso B, teniendo en cuenta los
datos concretos sobre los que se ejecute el programa y lo grandes que sean.

2.1. Ejemplos de cálculo de complejidad de algoritmos iterativos

De manera práctica, se analizará el código de los algoritmos presentados de arriba hacia

abajo y de dentro hacia fuera.

Búsqueda secuencial

1 bool buscaSec( int v[], int num, int x ) {

int j;
bool encontrado;

j = 0;
encontrado = false;
while ( (j < num) && ! encontrado ) {

encontrado = ( v[j] == x );
j++;

}
return encontrado;

2

3

4

5

6

7

8

9

10

11

12 }

• Caso peor: el elemento buscado x condiciónno está en el vector
◦ Cuerpo del bucle while: 4 (3 en la línea 8 y 1 en la línea 9)
◦ Bucle while:
= 7n + 3
◦ Total: 7n + 3 + 2(inicializaciones) = 7n + 5

∗ ( 4
|{z}

|{z}

j=0..n−1

|{z}

condición

condición

3

|{z}

cuerpo

n

+ 3

) +

• Caso mejor: el elemento buscado x está en la primera posición del vector; solo

se entra una vez en el bucle while
◦ Cuerpo del bucle while: 4
◦ Bucle while: (4 + 3) + 3 = 10

Estructura de Datos y Algoritmos

2. Reglas prácticas para el cálculo de la eficiencia

27

◦ Total: 10 + 2 = 12

Búsqueda binaria

1 int buscaBin( int v[], int num, int x ) {

int izq, der, centro;

izq = -1;
der = num;
while ( der != izq+1 ) {

centro = (izq+der) / 2;
if ( v[centro] <= x )

izq = centro;

else

der = centro;

}
return izq;

2

3

4

5

6

7

8

9

10

11

12

13

14 }

• En esta ocasión no hay caso mejor ni peor, el bucle se ejecuta el mismo número
de veces independientemente de la posición de x en el vector o incluso si x no
aparece en el vector. Aunque el elemento buscado esté en el centro, el bucle
sigue ejecutándose hasta acotar un subvector de longitud 1.
◦ Cuerpo del bucle while:
◦ Bucle while:
|{z}
◦ Total: (8 log(n) + 2) + 2(inicializaciones) = 8 log(n) + 4

|{z}
∗ ( 6
|{z}

= 8 log(n) + 2

| {z }

|{z}if

|{z}

vueltas while

+ 2

log(n)

condición

condición

3

+ 3

= 6

línea 7

) +

2

cuerpo

En caso de que el elemento buscado estuviese repetido, ¿qué posición se devolvería?

Ordenación por inserción

1 void ordenaIns ( int v[], int num ) {

int i, j, x;

for ( i = 1; i < num; i++ ) {

x = v[i];
j = i-1;
while ( (j >= 0 ) && (v[j] > x) ){

v[j+1] = v[j];
j = j-1;

}
v[j+1] = x;

}

2

3

4

5

6

7

8

9

10

11

12

13 }

• Caso peor: el vector está ordenado a la inversa; la segunda parte de la condición

del while se cumple siempre
◦ Cuerpo del bucle while: 6 (4 de la línea 8 y 2 de la línea 9)
◦ Bucle while:
= 10i + 4

+ 4

) +

4

i

j=0..i−1

|{z}

∗ ( 6
|{z}

cuerpo

condición

|{z}

condición

|{z}
Facultad de Informática - UCM

28

Capítulo 3. Diseño de algoritmos iterativos

+ 2

|{z}l5

+ 2

|{z}l6

+ 3

|{z}l11

+ 1

|{z}

i++

= 10i + 12

◦ Cuerpo del bucle for: (10i + 4)
}
◦ Bucle for:
X

((10i + 12)

+ 1

{z

while

n−1

|

n−1

X

) +

1

+ 1

=

(10i + 13) + 2 =

i=1

cuerpo

|

= 10

i=1

}

n−1

n−1

condición

condición

|{z}

|{z}
X

|{z}ini
n(n − 1)

{z
X
= 5n2 − 5n + 13n − 13 + 2 = 5n2 + 8n − 11

13 + 2 = 10

i +

i=1

i=1

2

+ 13(n − 1) + 2 =

• Caso mejor: el vector está ordenado; la segunda parte de la condición del while

no se cumple nunca
◦ Bucle while: 4(condición)
◦ Cuerpo del bucle for: 4 + 2 + 2 + 3 + 1 = 12
◦ Bucle for:
X

(12 + 1) + 1 + 1 =

X

n−1

n−1

i=1

i=1

13 + 2 = 13(n − 1) + 2 = 13n − 11

Ordenación por selección

1 void ordenaSel ( int v[], int num ) {

int i, j, menor, aux;

for ( i = 0; i < num; i++ ) {

menor = i;
for ( j = i+1; j < num; j++ )

if ( v[j] < v[menor] )

menor = j;

if ( i != menor ) {

aux = v[i];
v[i] = v[menor];
v[menor] = aux;

}

}

2

3

4

5

6

7

8

9

10

11

12

13

14

15 }

+ 1

• Caso peor: vector desordenado
◦ Cuerpo del for interno: 3
|{z}if
|{z}l8
|{z}
◦ Bucle for interno: (n − i − 1)
|{z}
|{z}
}
{z
◦ Cuerpo del for externo: 1
+ (6n − 6i − 3)
|{z}l5
|
}

j++
+ 1

j=i+1..n−1

+ 1

{z

( 5

cuerpo

|

f or

= 5

)+ 1

+ 2

= 6n−6i−3

condición

condición

|{z}

+ 1

+ 2

|{z}if

|{z}l10

+ 3

|{z}ini
|{z}l11

+ 2

|{z}l12

+ 1

|{z}

i++

= 6n − 6i + 7

◦ Bucle for externo:
X

n−1

((6n − 6i + 7)
}
|
Estructura de Datos y Algoritmos

{z

cuerpo

i=0

+ 1

)+ 1

condición

condición

|{z}

|{z}

n−1

X

i=0

n−6

= 6

+ 1

|{z}ini

n−1

X

i=0

i+

n−1

X

i=0

8+2 =

2. Reglas prácticas para el cálculo de la eficiencia

29

n(n − 1)

= 6n2 − 6

n + 8n + 2 = 3n2 + 11n + 2
• Caso mejor: vector ordenado; la condición del if más interno no se cumple

+ 8n + 2 = 6n2 −

n2 +

2

6
2

6
2

nunca, y como consecuencia la del más externo tampoco:
◦ Cuerpo del for interno: 4
◦ Bucle for interno: (n − i − 1)(4 + 1) + 1 + 2 = 5n − 5i − 2
◦ Cuerpo del for externo: 1 + (5n − 5i − 2) + 1 + 1 = 5n − 5i + 1
◦ Bucle for externo:

n−1

X

i=0

((5n − 5i + 1) + 1) + 1 + 1 = 5

n − 5

n−1

X

i=0

n−1

X

i=0

n−1

X

i=0

i +

2 + 2 =

= 5n2 − 5

+ 2n + 2 = 5n2 −
¿Qué sucede si el vector está ordenado al revés?

2

n(n − 1)

5
2

n2 +

5
2

n + 2n + 2 =

n2 +

5
2

9
2

n + 2

Ordenación por el método de la burbuja modificado

1 void ordenaBur ( int v[], int num ) {

int i, j, aux;
bool modificado;

i = 0;
modificado = true;
while ( (i < num-1) && modificado ) {

modificado = false;
for ( j = num-1; j > i; j-- )

if ( v[j] < v[j-1] ) {

aux = v[j];
v[j] = v[j-1];
v[j-1] = aux;
modificado = true;

}

i++;

}

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18 }

• Caso peor: El vector está ordenado al revés; se entra siempre en el if :
= 15

+ 2

+ 4

+ 3

+ 1

+ 1

|

cuerpo

{z

j=i+1..n−1

◦ Cuerpo del bucle for: 4
|{z}if
◦ Bucle for: (n − i − 1)
( 15
|{z}
}
◦ Cuerpo del bucle while: 1
|{z}l8
◦ Bucle while:
X

+ 3

((16n − 16i − 11)
|
}

cuerpo

n−2

i=0

condición

|{z}
{z
= 16n(n − 1) − 16

+ 1

1

) +

condición

|{z}l11

|{z}l12

|{z}l13
|{z}
|{z}
+ 16n − 16i − 13
}
|

{z

f or

condición

+ 1

|{z}

i++

|{z}l14

+ 2

j−−

|{z}
= 16n − 16i − 13

|{z}ini
= 16n − 16i − 11

= 16

n−2

X

i=0

n−16

n−2

X

i=0

i−

n−2

X

i=0

8+3 =

)+ 3

condición

|{z}

(n − 2)(n − 1)

2

− 8(n − 1) + 3 =

= 16n2 − 16n − 8n2 + 24n − 16 − 8n + 8 + 3 = 8n2 − 5

Facultad de Informática - UCM

30

Capítulo 3. Diseño de algoritmos iterativos

◦ Total: 8n2 − 5
| {z }

while

+ 2

|{z}ini

= 8n2 − 3

• Caso mejor: El vector está ordenado; nunca se entra en el if y solo se da una

vuelta al while:
◦ Cuerpo del bucle for: 4 + 1 = 5
◦ Bucle for: (n − 1)(5 + 1) + 1 + 2 = 6n − 3
◦ Cuerpo del bucle while: 1 + (6n − 3) + 1 = 6n − 1
◦ Bucle while:

((6n − 1) + 3) + 3 = 6n + 5

◦ Total: 6n + 5 + 2 = 6n + 7

3. Verificación

3.1. Semántica de un lenguaje imperativo

Especificar un algoritmo: encontrar dos predicados P y Q tales que: {P}A{Q}.
Verificar: introducir predicados intermedios entre cada par de instrucciones elemen-
tales:

{P ≡ R0}A1{R1}; ...;{Rn−1}An{Rn ≡ Q}

Si se satisface {Rk−1}Ak{Rk} ∀k entonces se satisface {P}A{Q}.
Buscaremos reglas para determinar si se satisface {Rk−1}Ak{Rk} (reglas de verifica-
ción).

Conocer dichas reglas para cada instrucción del lenguaje es equivalente a conocer la
semántica de éste.

Todas las instrucciones que se definen más adelante cumplen las siguientes reglas generales:

Si se cumple {P}A{Q} podemos conocer otras especificaciones de A. Si P ′ ⇒ P
entonces se cumple {P ′}A{Q}:

P ′ ⇒ P {P}A{Q}

{P ′}A{Q}

(fortalecimiento de la precondición)

Si Q ⇒ Q′ entonces se cumple {P}A{Q′}:

{P}A{Q} Q ⇒ Q′

{P}A{Q′}

Conjunción en la postcondición:

(debilitamiento de la postcondición)

{P}A{Q1} {P}A{Q2}

{P}A{Q1 ∧ Q2}

Disyunción en la precondición:

Estructura de Datos y Algoritmos

3. Verificación

31

{P1}A{Q}

{P2}A{Q}

{P1 ∨ P2}A{Q}

Acabamos de ver que la precondición de una especificación correcta se pue
  • Links de descarga
http://lwp-l.com/pdf16606

Comentarios de: Capítulo 3 - Diseño de algoritmos iterativos (0)


No hay comentarios
 

Comentar...

Nombre
Correo (no se visualiza en la web)
Valoración
Comentarios...
CerrarCerrar
CerrarCerrar
Cerrar

Tienes que ser un usuario registrado para poder insertar imágenes, archivos y/o videos.

Puedes registrarte o validarte desde aquí.

Codigo
Negrita
Subrayado
Tachado
Cursiva
Insertar enlace
Imagen externa
Emoticon
Tabular
Centrar
Titulo
Linea
Disminuir
Aumentar
Vista preliminar
sonreir
dientes
lengua
guiño
enfadado
confundido
llorar
avergonzado
sorprendido
triste
sol
estrella
jarra
camara
taza de cafe
email
beso
bombilla
amor
mal
bien
Es necesario revisar y aceptar las políticas de privacidad