Вы находитесь на странице: 1из 32

Tema 1: Preliminares

Estructuras de Datos

Grado en Ingeniería de Computadores Universidad Rey Juan Carlos

José Miguel Buenaposada Biencinto

Agradecimientos: a Ana Pradera y Juan Manuel Serrano por el planteamiento del curso, a Antonio Sanz y a algunos otros profesores del DCC por muchas (o algunas transparencias) según el caso .

¿Qué debemos saber sobre Pascal?

Algún entorno de TurboPascal:

“Borland Turbo Pascal” o bien

“Eclipse Gavab 2.0” (http://www.gavab.es/wiki/eclipsegavab/)

Instrucciones de control

Subprogramas

Arrays

Registros

Ficheros

URJC-ED-Introducción

3

Índice

1.1 Conceptos previos

1.2 Punteros

1.3 Complejidad

URJC-ED-Introducción

22

Ciclo de vida del software

Planificación (estimación de recursos, coste, tiempo y viabilidad)

Análisis: Qué se hace

Diseño: Cómo se hace

Codificación: Se hace

Pruebas: se prueba y se corrige

Documentación

Uso y mantenimiento: se mejora y amplía

URJC-ED-Introducción

4

¡Diseñar la solución antes de programar!

Fase de análisis

Fase de diseño

Problema
Problema
Algoritmo
Algoritmo

Algoritmo

Programa

Atajo tentador
Atajo
tentador

Fase de implementación

URJC-ED-Introducción

5

Normas de estilo (cont.)

Identificadores: descriptivos y minúsculas

Palabras separadas, unidas por _ o utilizando primer carácter de la palabra sufija mayúscula o ambos

nombre_archivo, nombreArchivo, nombre_Archivo

Constantes: MAYUSCULAS

IVA, PI, NUMERO_E,

Procedimientos: Empezando por letra MAYUS.

BusquedaBinaria, Apilar, PilaVacia,

Tipos: Empezando por “Tipo” o “T”

TipoPila, TPila

URJC-ED-Introducción

7

Normas de estilo

Evitar varias instrucciones en una misma línea

Tabular adecuadamente el anidamiento de sentencias. Evitar escribir:

IF precio>MAXIMO THEN WriteLn(‘Precio abusivo’);

Dar nombres nemotécnicos a los identificadores que describan lo mejor posible su cometido o lo que representan (subprogramas y variables).

Palabras reservadas: MAYUSCULAS

WHILE, FOR, RECORD,

URJC-ED-Introducción

6

Normas de estilo (cont.)

Módulos y Ficheros:

Los nombres de programas y módulos (unidades):

Deben coincidir con los nombres de los ficheros que los contienen, y

Deben empezar por MAYUSCULAS y resto minúsculas

URJC-ED-Introducción

8

Normas de estilo (cont.)

Módulos y Ficheros:

Deben contener una cabecera de identificación como esta:

{*************************************************************************************************

*

*

*

Módulo:

Nombre

*

*

Fichero:

( ) Programa ( ) Espec. TAD

( ) Impl. TAD

( ) Otros

*

*

Autor(es):Nombre(s)

 

*

*

Fecha:

Fecha de actualización

*

*

*

*

Descripción:

*

*

Breve descripción del módulo (párrafo corto)

 

*

*

*

*************************************************************************************************}

URJC-ED-Introducción

9

Conceptos aprendidos: Arrays

Un tipo de dato ARRAY se define en la sección de declaración de tipos TYPE

TYPE

Tipo1

= ARRAY [1

3]

OF integer;

 

TipoVector

= ARRAY [1

3]

OF real;

TipoMatriz

= ARRAY [1

3,

1

7]

OF char;

 

TipoViviendas = ARRAY [1 VAR var1: Tipo1;

3,

1

3,

’A’

’E’]

OF boolean;

URJC-ED-Introducción

11

Normas de estilo (cont.)

Se recomienda emplear subprogramas para tareas bien identificadas (abstracción procedimental).

Emplear sentencias de repetición (especialmente bucles FOR y WHILE) cuando sea posible.

Evitar variables globales en subprogramas.

Uso adecuado de funciones (devuelven un valor).

URJC-ED-Introducción

10

Conceptos aprendidos: Arrays (cont.)

Son estructuras de datos:

– De acceso directo: permiten almacenar y recuperar directamente los datos especificando su posición dentro de la estructura.

– Homogéneas: sus elementos son TODOS del MISMO TIPO.

– Estáticas: su tamaño se establece de forma FIJA cuando se declara variable de este tipo y no puede cambiar su tamaño durante la ejecución del programa.

URJC-ED-Introducción

12

Conceptos aprendidos: Registros

Son estructuras de datos:

– Heterogéneas: sus elementos pueden ser de DISTINTOS tipos.

– Estáticas: su tamaño se establece de forma FIJA cuando se declara variable de este tipo.

TYPE TNombreReg = RECORD idCampo1 : idTipo1; idCampo2 : idTipo2;

idCampon : idTipon END; {Fin de TNombreReg}

URJC-ED-Introducción

13

Conceptos aprendidos: Registros (cont.)

VAR profesor : TFicha;

BEGIN writeln(profesor.nombre, profesor.edad, profesor.sueldo);

C

t

i

on sen enc a

WITH

:

VAR profesor : TFicha;

BEGIN WITH profesor DO writeln(nombre,edad,sueldo);

URJC-ED-Introducción

15

Conceptos aprendidos: Registros (cont.)

Las funciones no pueden devolver un registro.

Para acceder a un campo se usa el operador punto (.):

nombreVariableRegistro.nombreCampo

También podemos acceder a los campos de un registro “abriendo” el registro con la sentencia WITH:

WITH nombreVariableRegistro DO Instrucción que con una expresión con nombreCampo

URJC-ED-Introducción

Índice

1.1 Conceptos previos

1.2 Punteros

1.3 Complejidad

URJC-ED-Introducción

14

1616

Memoria dinámica y punteros

Las estructuras de datos que conocemos (ARRAY, RECORD, integer, …) son de memoria estática.

Cuando no se sabe cuánta memoria se va a necesitar para una estructura de datos en ejecución, el programa pedirá (y devolverá) al sistema memoria dinámicamente (cuando sea necesario).

La gestión de memoria dinámica en muchos lenguajes de programación se realiza a través de punteros.

 

URJC-ED-Introducción

17

 

Declaración de enteros en Pascal

Recordemos como declarar una variable entera x:

VAR

 

x: integer;

{ reserva memoria para un dato entero }

El compilador de Pascal reservará 2 bytes en una posición de memoria (podría ser un registro de la CPU) a la que llamará x.

 
 

URJC-ED-Introducción

19

Punteros

Una variable puntero sirve para albergar la dirección de memoria de otra variable (es decir, apunta a otra variable).

Utilizando punteros podremos:

Pedir (reservar) nueva memoria dinámica al sistema.

Liberar la memoria a la que se apunta.

Acceder al valor del dato al que se apunta.

Pascal (como C, C++, y otros lenguajes) posee mecanismos para manejar memoria dinámica a través de punteros.

URJC-ED-Introducción

18

Declaración de punteros en Pascal

Declaración de un tipo y una variable p puntero a un entero:

TYPE TipoPuntero = ^integer;

{tipo puntero a entero}

VAR p: TipoPuntero; { reserva una celda de memoria que pueda contener la dirección de memoria de una variable entera }

El compilador de Pascal reservará N bytes (los necesarios para almacenar una dirección de memoria) en una posición de memoria (podría ser un registro de la CPU) a la que llamará p.

URJC-ED-Introducción

20

El puntero a “ninguna parte”

NIL, es una constante de tipo puntero que indica que no apunta a ninguna celda de memoria.

TYPE TipoPuntero = ^integer;

VAR p: TipoPuntero; { no está inicializada, contiene un valor indeterminado que no es NIL }

BEGIN p := NIL; { p no apunta a ninguna dirección }

{tipo puntero a entero}

Gráficamente:

p

dirección } {tipo puntero a entero} Gráficamente: p distinto de dir. no asignada: URJC-ED-Introducción p ?

distinto de dir. no asignada:

URJC-ED-Introducción

p

?
?

21

Ejemplo de operaciones con punteros

Operaciones con punteros

Comparación ( = y <> ) y asignación ( := ) de punteros.

Dirección de una variable v: @v

Se obtiene la dirección de memoria de una variable para asignarla a un puntero a ese tipo de variable.

Contenido de un puntero p: p^

Se accede a la variable apuntada por el puntero (a su contenido).

URJC-ED-Introducción

22

Ejemplo de operaciones con punteros

TYPE TipoPuntero = ^integer; VAR

   

TYPE TipoPuntero = ^integer; VAR

 

i:

integer;

 

i:

integer;

 

p:

TipoPuntero;

 

p:

TipoPuntero;

 

BEGIN

BEGIN BEGIN

BEGIN

p

:= NIL;

 

p

:= NIL;

 

i

p

:= 7;

:

= @i

;

{ Asi nar la dirección de la variable i a

g

p

}

i

p

:= 7;

:

= @i

;

{ Asi nar la dirección de la variable i a

g

p

}

p^

:= 3;

{ Cambiar el contenido de lo apuntado por p }

p^

:= 3;

{ Cambiar el contenido de lo apuntado por p }

write(i); {escribe el valor 3}

 

write(i); {escribe el valor 3}

 

URJC-ED-Introducción

23

Dir. Memoria:

90

38

? p ? i URJC-ED-Introducción
?
p
?
i
URJC-ED-Introducción

24

Ejemplo de operaciones con punteros

Ejemplo de operaciones con punteros

 

TYPE

 

TYPE

TipoPuntero = ^integer; VAR

 

TipoPuntero = ^integer; VAR

 

i:

integer;

 

i:

integer;

 

p:

TipoPuntero;

 

p:

TipoPuntero;

 
BEGIN p   BEGIN

BEGIN

p

 

BEGIN

:= NIL;

 
:= NIL;   p i p := NIL;  

p

i

p

:= NIL;

 
 

i

p

:= 7;

:

= @i

;

{ Asi nar la dirección de la variable i a

g

p

}

:= 7;

:

@i

=

;

{ Asi nar la dirección de la variable i a

g

p

}

p^

:= 3;

{ Cambiar el contenido de lo apuntado por p }

 

p^

:= 3;

{ Cambiar el contenido de lo apuntado por p }

write(i); {escribe el valor 3}

 

write(i); {escribe el valor 3}

 

Dir. Memoria:

90

38

? p ? i URJC-ED-Introducción
?
p
?
i
URJC-ED-Introducción

25

Ejemplo de operaciones con punteros

Dir. Memoria:

90

38

7 p ? ? i URJC-ED-Introducción
7
p
? ?
i
URJC-ED-Introducción

26

Ejemplo de operaciones con punteros

 

TYPE TipoPuntero = ^integer; VAR

   

TYPE TipoPuntero = ^integer; VAR

 

i:

integer;

 

i:

integer;

 

p:

TipoPuntero;

 

p:

TipoPuntero;

 

BEGIN

BEGIN

p

:= NIL;

 

p

:= NIL;

 
i p := 7; := @i ; { Asi nar la dirección de la variable

i

p

:= 7;

:= @i

;

{ Asi nar la dirección de la variable i a

g

p

}

i

p

:= 7;

:

@i

=

;

{ Asi nar la dirección de la variable i a

g

p

}

p^

:= 3;

{ Cambiar el contenido de lo apuntado por p }

p^ := 3; { Cambiar el contenido de lo apuntado por p } p^ := 3;

p^

:= 3;

{ Cambiar el contenido de lo apuntado por p }

write(i); {escribe el valor 3}

 

write(i); {escribe el valor 3}

 
Dir. Memoria: 90 38 p 38 i 7 Se dice que “p apunta a i”
Dir. Memoria:
90
38
p
38
i 7
Se dice que “p apunta a i”

URJC-ED-Introducción

27

Dir. Memoria: 90 38 p 38 i 3 Se dice que “p apunta a i”
Dir. Memoria:
90
38
p
38
i 3
Se dice que “p apunta a i”

URJC-ED-Introducción

28

Ejemplo de “operación ilegal”

TYPE

TipoPuntero = ^integer;

VAR i: integer; p: TipoPuntero; BEGIN

p

:= NIL;

 

p

:= @i; { Asignar la dirección de la variable i a p }

p

:

^ =

3

;

p

{ almacena el valor 3 en la celda de memoria apuntada por p }

:= 3; { operación ilegal: 3 es integer mientras que p es TipoPuntero y sólo puede contener una dirección de memoria de una variable integer}

 

URJC-ED-Introducción

29

Operador “contenido” ^: RECORD

Para un puntero a una variable registro:

TYPE TipoRegistro = RECORD dato: integer;

 

indice: integer END; TipoPuntero = ^TipoRegistro; VAR r: TipoRegistro; p: TipoPuntero; BEGIN

 

p

:= @r;

p^.dato := 5;

 
 

URJC-ED-Introducción

31

Operador “contenido” ^: ARRAY

Para un puntero a una variable ARRAY:

TYPE

TipoArray

TipoPuntero = ^TipoArray;

= ARRAY [1

2]

VAR

a:

TipoArray;

p:

TipoPuntero;

BEGIN

p

:= @a;

p^[1] := 5;

p^[2] := 3;

OF integer;

URJC-ED-Introducción

Ejercicio 1

30

¿Qué valores escribe el programa?

PROGRAM Ejer1; VAR a, b: integer; pb: ^integer; BEGIN a := 10; pb := @a;
PROGRAM Ejer1;
VAR
a, b: integer;
pb: ^integer;
BEGIN
a
:= 10;
pb
:= @a;
b
:= pb^;
writeln(a,’ ’, b);
END.

URJC-ED-Introducción

32

Ejercicio 2

Petición de nueva memoria dinámica

¿Qué valores escribe el programa?

PROGRAM Ejer2;

VAR

a:

string;

pa, pb: ^string;

BEGIN

a := ‘Hola’;

pa := @a;

pb := pa;

writeln(a); pb^ := ‘Adios’; writeln(a);

END.

URJC-ED-Introducción

33

Semántica del procedimiento new

TYPE TipoPuntero = ^integer; VAR p: TipoPuntero; BEGIN new(p);

= ^integer; VAR p: TipoPuntero; BEGIN new(p); Dir. Memoria: 90 p ? URJC-ED-Introducción 3 5 •

Dir. Memoria:

90

p ? URJC-ED-Introducción
p
?
URJC-ED-Introducción

35

new, procedimiento que reserva una nueva celda de memoria dinámica e inicializa la variable puntero tal que apunte a esta nueva celda.

TYPE Ti oPuntero = ^inte er VAR p: TipoPuntero; BEGIN new(p);

p

g

;

Si p es un puntero a integer reserva espacio para contener un integer. Si p es un puntero a char reserva espacio para albergar una valor de tipo char.

URJC-ED-Introducción

34

Semántica del procedimiento new

TYPE TipoPuntero = ^integer; VAR p: TipoPuntero; BEGIN new(p);

= ^integer; VAR p: TipoPuntero; BEGIN new(p); Dir. Memoria: p 90 54 54 ? Memoria dinámica

Dir. Memoria:

p

90 54 54 ?
90
54
54 ?

Memoria dinámica (del heap o montón)

Se dice que “p apunta a un entero”

URJC-ED-Introducción

36

Liberación de memoria dinámica

dispose, procedimiento que libera el espacio de memoria indicado por la variable puntero que se pasa como parámetro.

TYPE Ti oPuntero = ^inte er VAR p: TipoPuntero; BEGIN new(p); dispose(p);

p

g

;

{

Una referencia posterior a p^ puede ser desastrosa, pues p apuntará a una celda que ya no está reservada. Conviene asignarle NIL }

p

= NIL;

URJC-ED-Introducción

37

Semántica del procedimiento dispose

TYPE TipoPuntero = ^integer; VAR p: TipoPuntero; BEGIN new(p); dispose(p); p := NIL;

VAR p: TipoPuntero; BEGIN new(p); dispose(p); p := NIL; Dir. Memoria: p 90 54 54 ?

Dir. Memoria:

p

90 54 54 ?
90
54
54 ?

Memoria dinámica (del heap o montón)

Se dice que “p apunta a un entero”

URJC-ED-Introducción

39

Semántica del procedimiento dispose

TYPE TipoPuntero = ^integer; VAR p: TipoPuntero; BEGIN new(p); dispose(p);

p := NIL;

VAR p: TipoPuntero; BEGIN new(p); dispose(p); p := NIL; Dir. Memoria: 90 p ? URJC-ED-Introducción 3
Dir. Memoria: 90 p ? URJC-ED-Introducción
Dir. Memoria:
90
p
?
URJC-ED-Introducción

38

Semántica del procedimiento dispose

TYPE

TipoPuntero = ^integer; VAR p: TipoPuntero; BEGIN new(p); dispose(p);

p := NIL;

p: TipoPuntero; BEGIN new(p); dispose(p); p := NIL; Dir. Memoria: p 90 54 54 ? Memoria

Dir. Memoria:

p

90 54 54 ?
90
54
54 ?

Memoria dinámica (del heap o montón) marcada como libre

Se dice que “p apunta a un entero”

URJC-ED-Introducción

40

Semántica del procedimiento dispose

TYPE TipoPuntero = ^integer; VAR p: TipoPuntero; BEGIN new(p); dispose(p); p := NIL;

TYPE TipoPuntero = ^integer; VAR p: TipoPuntero; BEGIN new(p); dispose(p); p := NIL;

Dir. Memoria:

p

90

BEGIN new(p); dispose(p); p := NIL; Dir. Memoria: p 90   URJC-ED-Introducción 4 1 Ejercicio 3
 

URJC-ED-Introducción

41

Ejercicio 3

¿Qué hace el programa?

 
 

PROGRAM Ejer3; VAR pa, pb: ^string;

 

BEGIN

new(pa); pa^ := ‘Hola’;

 

pb

:= pa;

writeln(pa^); pb^ := ‘Adios’; writeln(pa^);

 

dispose(pb);

END.

 

URJC-ED-Introducción

43

Al trabajar con punteros hay que …

Declarar una variable de tipo puntero.

Si es necesario reservar memoria en tiempo de ejecución llamar a new.

Después de llamar a new el valor del contenido del puntero es indefinido (es necesario asignarle un valor).

Variable_puntero es diferente de: Variable_puntero^

Es necesario liberar el espacio de memoria (dispose) cuando no se vaya a utilizar más el dato apuntado.

URJC-ED-Introducción

42

Perdida de memoria (memory leak)

La memoria disponible en el heap es limitada y cada vez que se llama a new una parte de esa memoria se marca como ocupada.

Cada vez que se llama a dispose, la memoria ocupada se marca como libre.

Cuando se pide memoria con new(p) y se asigna otra dirección a p antes de hacer un dispose(p) se produce una pérdida de memoria (la memoria apuntada por p queda ocupada e inaccesible).

URJC-ED-Introducción

44

Error de acceso

Cada vez que se llama a dispose(p), la memoria ocupada se marca como libre pero p mantiene la dirección anterior al dispose.

Inmediantamente después de dispose(p)un acceso al contenido de p, p^, producirá un error de ejecución.

URJC-ED-Introducción

45

Punteros en llamadas a subprogramas

Pueden ser parámetros por valor y por referencia de los subprogramas:

FUNCTION F1 (VAR p1: ^integer; p2: ^integer): integer;

PROCEDURE F2 (VAR p1: ^integer; p2: ^integer);

Se pueden devolver como resultado de una función:

FUNCTION F2 (a: integer): ^integer;

VAR p: ^integer; BEGIN p := F2(4);

URJC-ED-Introducción

47

Ejercicio 4

¿Qué hace el programa?

PROGRAM Ejer4; VAR pa, pb: ^string;

BEGIN

new(pa); pa^ := ‘Hola’; new(pb);

:= pa;

pb

writeln(pa^); pb^ := ‘Adios’; writeln(pa^); dispose(pb); dispose(pa); END.

URJC-ED-Introducción

46

Punteros en llamadas a subprogramas (cont.)

El paso de punteros por valor equivale al paso por referencia de la variable que apuntan.

El subprograma recibe una copia del puntero y apunta a la misma información que el original,

Un cambio en esa información es un cambio en la apuntada por el puntero original.

PROCEDURE Ej3 (p1: ^integer); BEGIN

END;

VAR p: ^integer; i: integer; BEGIN i := 2; p := @i;

Ej3(p);

URJC-ED-Introducción

Dir. Memoria: 129 23 p 23 i 2 “p1 es copia de p” p1 23
Dir. Memoria:
129
23
p 23
i 2
“p1 es copia de p”
p1
23

48

Ejercicio 5

¿Qué valores escribe el programa?

PROGRAM Ejer5; TYPE TPuntEnt = ^integer;

VAR

a,

b, c: integer;

BEGIN

{ Ejer5 }

PROCEDURE X( x: TPuntEnt; y: integer; VAR z: integer );

BEGIN

a := 2;

b := 3;

c := 4;

X(@a, b, c); writeln(a,’ ’,b,’ ’, c);

x^

:= x^ * x^;

END. { Ejer 5 }

y

:= y * y;

z

:= z * z;

END;

URJC-ED-Introducción

49

Definición de la complejidad

La complejidad o eficiencia de un algoritmo se define como el orden de magnitud de los recursos informáticos que requiere el algoritmo para ser ejecutado.

El estudio de la complejidad de los algoritmos permite evaluar su coste, y así:

Comparar algoritmos entre sí.

Averiguar si un algoritmo es factible.

URJC-ED-Introducción

51

Índice

1.1 Conceptos previos

1.2 Punteros

1.3 Complejidad

URJC-ED-Introducción

5050

Motivación en Estructuras de Datos

Una estructura de datos:

Una especificación única (lo veremos).

– Múltiples posibles implementaciones (lo veremos)

¿Cómo elegir entre las posibles implementaciones?

¡Evaluando su complejidad!

URJC-ED-Introducción

52

Aspectos que intervienen en el cálculo de complejidades

Cuáles son los recursos informáticos que hay que estimar.

En qué casos (para qué tipo de entradas) hay que estimar la complejidad.

Qué significa calcular el orden de magnitud.

Qué reglas prácticas existen para calcular complejidades.

URJC-ED-Introducción

53

¿Cómo estimar los recursos?

• Método empírico:

Programar el algoritmo y ejecutarlo en un ordenador.

– Inconveninente: el resultado depende del programador, el lenguaje elegido y la CPU.

• Método teórico:

Calcular el número de “operaciones básicas” que realiza el algoritmo.

– Ventajas: el resultado no depende ni del programador, ni del lenguaje, ni de la CPU.

URJC-ED-Introducción

55

Recursos informáticos

Los recursos informáticos a evaluar son el tiempo (de ejecución) y/o el espacio (de memoria) requeridos por los algoritmos.

Ambos dependen del tamaño de la entrada. Se trata de calcular las funciones T A y E A :

T A (n) = tiempo requerido para la ejecución del algoritmo A con una entrada de tamaño n.

E A (n) = espacio de memoria requerido para la ejecución del algoritmo A con una entrada de tamaño n.

URJC-ED-Introducción

54

¿Cómo estimar los recursos (tiempo)?

T A (n) = número de operaciones básicas que realiza el algoritmo A con una entrada de tamaño n

Una operación básica es aquella cu o tiempo de

y

ejecución se puede acotar superiormente por una constante, independientemente del tamaño de la entrada, la CPU, el lenguaje de programación, el

compilador, etc.

URJC-ED-Introducción

56

Casos para el estudio de la complejidad

Las funciones T A y E A no sólo dependen del tamaño de la entrada, sino también de su contenido:

¡ no se tarda lo mismo en ordenar 10 números ya ordenados que en ordenar 10 números totalmente desordenados !

Habrá diferentes tipos de entradas unas “más difíciles” y otras “más fáciles” para un algoritmo determinado.

URJC-ED-Introducción

57

Casos para el estudio de la complejidad

• El caso medio o caso probabilístico, que representa una situación intermedia (su evaluación suele requerir técnicas estadísticas).

fin

:= FALSO;

k

:= 1;

MIENTRAS (k<=N) Y (NO fin) HACER SI (V[k] == buscado) fin := true;

k := k + 1;

URJC-ED-Introducción

¿Número promedio de iteraciones suponiendo igual probabilidad de encontrar buscado en

cualquier posición de V (de tamaño N)?

59

Casos para el estudio de la complejidad

fin

:= FALSO;

 

k

:= 1;

MIENTRAS (k<=N) Y (NO fin) HACER SI (V[k] == buscado)

 

fin := true;

k

:= k + 1;

iteraciones?

¿Cómo es el array V (de tamaño N) que produce el menor número de

URJC-ED-Introducción

58

Casos para el estudio de la complejidad

• El peor caso, caso extremo en el que el número de operaciones a ejecutar (o el espacio requerido) es el mayor posible

fin

:= FALSO;

k

:= 1;

MIENTRAS (k<=N) Y (NO fin) HACER SI (V[k] == buscado) fin := true;

k := k + 1;

URJC-ED-Introducción

¿Cómo es el array V (de tamaño N) que produce el mayor número de

iteraciones?

60

Casos para el estudio de la complejidad

• El peor caso, caso extremo en el que el número de operaciones a ejecutar (o el espacio requerido) es el mayor posible

El cálculo en el peor caso asegura que los recursos reales consumidos, sea cual sea el contenido de la entrada, ¡nunca rebasarán el valor calculado!

URJC-ED-Introducción

61

Medidas asintóticas de complejidad

Existen varias medidas para estudiar el comportamiento asintótico de una función:

Notación “O grande”: O(f(n)) (cota superior: la más usada)

Notación “Omega”: (f(n)) (cota inferior)

Notación

“Theta”: (f(n)) (cota media)

URJC-ED-Introducción

63

Medidas asintóticas de complejidad

Si hay que ordenar un conjunto de 5 elementos, la eficiencia del algoritmo no importa demasiado (en cualquier caso el tiempo de ejecución será pequeño).

Para analizar las funciones T A y E A bastará con estudiar su comportamiento asintótico (cómo se comportan cuando el tamaño de la entrada, n, es grande).

URJC-ED-Introducción

62

Notación asintótica O()

Dada una función f, queremos estudiar aquellas funciones g que a lo sumo crecen tan deprisa como f.

Al conjunto de tales funciones se le llama cota superior de f y lo denominamos O(f).

• Al conjunto de tales funciones se le llama cota superior de f y lo denominamos

URJC-ED-Introducción

64

Definición notación asintótica O()

Se dice que f es del orden de g, f(n)

O(g(n)), si y sólo

si existen dos constantes positivas C y k tales que f(n) g(n) para todo n k.

URJC-ED-Introducción
URJC-ED-Introducción

65

Conjuntos O(f) más importantes y su ordenación

O(1)

complejidad constante

 

O(log n)

complejidad logarítmica

 

O(n)

complejidad lineal

 

O(n p )

complejidad polinómica (p=2: cuadrática, p=3: cúbica)

O(2 n )

complejidad exponencial

 

O(n!)

complejidad factorial

 

O(1)

O(log n)

 

O(n)

O(n log n)

O(n p )

O(2 n ) O(n!)

URJC-ED-Introducción

67

Algunas propiedades útiles …

O(log b n) = O(log c n)

g(n) = a m n m + a m-1 n m-1 +

+ a 1 n + a 0

O(n m )

si a m 0

g(n) =

g(n) =

g(n) =

n

i=1

c

= cn

O(n)

n

(primero

+

último)nº térm

2

i =

i

1

n

=

2

3

i

=

1

i

2

=

6

O(n )

n(n

+

1)(2n

+

1)

=

2

O(n )

(1

+

n)n

URJC-ED-Introducción

66

Conjuntos O(f) más importantes y su ordenación (cont.)

(1 + n)n URJC-ED-Introducción 6 6 Conjuntos O( f ) más importantes y su ordenación (cont.)

URJC-ED-Introducción

68

El tamaño de la entrada importa …

¿Es mejor un algoritmo de O(n) que otro de O(n 2 )?

Depende del tamaño de las entradas, n, que se espera procesar.

Algoritmo 1: T 1 (n) = 5n 2 Algoritmo 2: T 2 (n) = 400n

5n 2 /400n = n/80

¿entradas n>80?

¿entradas n=80?

¿entradas n<80?

URJC-ED-Introducción

69

Reglas prácticas para el cálculo de la complejidad

Todo algoritmo está compuesto por una secuencia de instrucciones.

Existen unas reglas prácticas para calcular el coste de cada uno de los posibles tipos de instrucciones.

La complejidad de un algoritmo se basa en el coste de las instrucciones que lo componen pero el cálculo depende de si el algoritmo es o no recursivo.

Las reglas que se dan a continuación permiten calcular la complejidad en el peor caso de los distintos tipos de instrucciones.

URJC-ED-Introducción

71

En resumen …

Para calcular la complejidad de un algoritmo A:

Estudiar el comportamiento asintótico de las funciones T A /E A (dependientes del tamaño n de la entrada al algoritmo) en el peor caso o en un caso medio.

Encontrar una función f tal que en el peor caso/caso medio se

tenga T A /E A

O(f ).

Los conjuntos O(f ) proporcionan cotas superiores. Se tratará de encontrar la menor de todas las funciones f tal que T A /E A O(f ).

URJC-ED-Introducción

70

Regla 1: Instrucciones elementales

Se llama instrucción elemental a las operaciones de entrada/salida, asignaciones y expresiones aritméticas en las que no está involucrada ninguna variable que dependa del tamaño de la entrada del algoritmo

[I

instrucción

elemental]

T

I

O(1)

URJC-ED-Introducción

72

Regla 2: Secuencias de instrucciones

Regla 3: Instrucciones de selección

 

I

SI

B

ENTONCES

T

B

O

(

f

B

)

I SI

1

NO

I

2

T

I

 

O máx f

(

(

B

,

f

1

,

f

2

))

I

I

1

;

I

2

T I f

T

f

O

(

1

O

(

2

1

I

2

)

)

T

I

1

O

(

f

1

)

T I

O máx f

(

(

1

,

f

2

))

T

I

2

O

(

f

2

)

I

CASO

E

EN

caso

1:

I

1

caso

k

:

I

k

     
 

T

I

i

T

E

(

O f

i

(

O f

E

)

),

i

{1,

,

k

}

T

I

O máx f

(

(

E

,

f

1

,

 

,

f

k

))

URJC-ED-Introducción

73

Regla 4: Instrucciones de repetición

I ∫ MIENTRAS B HACER J f iter ∫ núm . iteraciones ( peor caso
I
∫ MIENTRAS
B
HACER
J
f iter
∫ núm
.
iteraciones
(
peor
caso
)
T
O
(
f
)
f iter
I
i
i = 1
T
O
(
f
),
en
la
iteración
i
B J
;
i

La complejidad de un bucle

PARA i DESDE a 1 HASTA a 2 HACER J

se calcula igual que la de un bucle MIENTRAS salvo que en el caso PARA el coste de la condición B se puede ignorar puesto que es siempre constante.

URJC-ED-Introducción

75

URJC-ED-Introducción

Ejemplos

74

PARA i DESDE 1 HASTA n HACER

{1}

 

x

:= x + 1

PARA i DESDE 1 HASTA n HACER

{2}

 

PARA j DESDE 1 HASTA n HACER

x

:= x + 1

PARA i DESDE 1 HASTA n HACER PARA j DESDE 1 HASTA i HACER

{3}

 

x

:= x + 1

i

:= 1

 

{4}

MIENTRAS i <= n HACER

 

x := x + 1

 

i :=

i

+ 2

URJC-ED-Introducción

76

Ejemplos (cont.)

x := 1 MIENTRAS x <= n HACER

{5}

x

:= x*2

PARA i DESDE 1 HASTA n-1 HACER PARA j DESDE i+1 HASTA n HACER

{6}

x

:= x + 1

URJC-ED-Introducción

77

Regla 5.1: Subprogramas no recursivos

Su complejidad es el máximo de las complejidades de las instrucciones que lo componen (la complejidad de cada una de estas instrucciones se calcula aplicando las reglas anteriores – 1 a 4 -).

URJC-ED-Introducción

79

Regla 5: Llamadas a subprogramas

La complejidad de la instrucción que llama al subprograma es equivalente a la complejidad que resulta de ejecutar el subprograma

[I ∫ llamada a un subprograma P] T (n) = T (n) I p
[I
∫ llamada
a
un
subprograma
P]
T (n)
=
T (n)
I
p

La complejidad dependerá de si el programa es o no recursivo.

URJC-ED-Introducción

78

Regla 5.2: Subprogramas recursivos

Para calcular la complejidad de un algoritmo recursivo es necesario realizar dos pasos:

1. Plantear la ecuación recurrente asociada con el tiempo de ejecución, T(n), del subprograma.

2. Resolver la ecuación recurrente anterior (encontrar una expresión no recursiva para el valor de T(n)). :

URJC-ED-Introducción

80

Paso 1: plantear la ecuación recurrente

SUBPROGRAMA P( n ); { n = tamaño entrada }

SI es_caso_sencillo(n) ENTONCES instrucciones_caso_sencillo; { No recursivas }

SI NO { Caso recursivo } P(reducción(n));

P(reducción(n)); { ‘a’ llamadas recursivas a P }

instrucciones_caso_resursivo; { No recursivas }

Si a=1 recursividad lineal, si a>1 recursividad múltiple.

URJC-ED-Introducción

Ejemplo 1

81

FUNCIÓN Ejemplo1(num:Natural) DEVUELVE Natural SI num < 1 ENTONCES DEV 1 SI NO DEV num * Ejemplo1(num-1);

URJC-ED-Introducción

83

Paso 1: plantear la ecuación recurrente

De la estructura general anterior podemos obtener la ecuación recurrente asociada a T(n):

e.o.c

Donde:

f(n): coste de las instrucciones_caso_sencillo

a: número de llamadas recursivas que se realizan

g(n): coste de las instrucciones_caso_recursivo

URJC-ED-Introducción

Ejemplo 1

82

FUNCIÓN Ejemplo1(num:Natural) DEVUELVE Natural SI num < 1 ENTONCES DEV 1 SI NO DEV num * Ejemplo1(num-1);

Tamaño de la entrada

es_caso_sencillo(n)

instrucciones_caso_sencillo

nº llamadas recursivas

reducción(n)

instrucciones_caso_recursivo

• nº llamadas recursivas • reducción(n) • instrucciones_caso_recursivo URJC-ED-Introducción 8 4

URJC-ED-Introducción

84

Ejemplo 1

FUNCIÓN Ejemplo1(num:Natural) DEVUELVE Natural SI num < 1 ENTONCES DEV 1 SI NO DEV num * Ejemplo1(num-1);

Tamaño de la entrada parámetro entrada num

es_caso_sencillo(n)

instrucciones_caso_sencillo

nº llamadas recursivas

instrucciones_caso_recursivo

reducción(n)

• • instrucciones_caso_recursivo reducción(n) URJC-ED-Introducción Ejemplo 1 8 5 FUNCIÓN

URJC-ED-Introducción

Ejemplo 1

85

FUNCIÓN Ejemplo1(num:Natural) DEVUELVE Natural SI num < 1 ENTONCES DEV 1 SI NO DEV num * Ejemplo1(num-1);

Tamaño de la entrada parámetro entrada num

es_caso_sencillo(n) n<1

instrucciones_caso_sencillo DEVOLVER 1, con coste O(1)

nº llamadas recursivas

instrucciones_caso_recursivo

reducción(n)

• • instrucciones_caso_recursivo reducción(n) URJC-ED-Introducción 8 7 Ejemplo 1 FUNCIÓN

URJC-ED-Introducción

87

Ejemplo 1

FUNCIÓN Ejemplo1(num:Natural) DEVUELVE Natural SI num < 1 ENTONCES DEV 1 SI NO DEV num * Ejemplo1(num-1);

Tamaño de la entrada parámetro entrada num

es_caso_sencillo(n) n<1

instrucciones_caso_sencillo

nº llamadas recursivas

instrucciones_caso_recursivo

reducción(n)

• • instrucciones_caso_recursivo reducción(n) URJC-ED-Introducción Ejemplo 1 8 6 FUNCIÓN

URJC-ED-Introducción

Ejemplo 1

86

FUNCIÓN Ejemplo1(num:Natural) DEVUELVE Natural SI num < 1 ENTONCES DEV 1 SI NO DEV num * Ejemplo1(num-1);

Tamaño de la entrada parámetro entrada num

es_caso_sencillo(n) n<1

instrucciones_caso_sencillo DEVOLVER 1, con coste O(1)

nº llamadas recursivas 1

instrucciones_caso_recursivo

reducción(n)

O(1) • nº llamadas recursivas 1 • • instrucciones_caso_recursivo reducción(n) URJC-ED-Introducción 8 8

URJC-ED-Introducción

88

Ejemplo 1

FUNCIÓN Ejemplo1(num:Natural) DEVUELVE Natural SI num < 1 ENTONCES DEV 1 SI NO DEV num * Ejemplo1(num-1);

Tamaño de la entrada parámetro entrada num

es_caso_sencillo(n) n<1

instrucciones_caso_sencillo DEVOLVER 1, con coste O(1)

nº llamadas recursivas 1

reducción(n) n-1

instrucciones_caso_recursivo

• reducción(n) n-1 • instrucciones_caso_recursivo URJC-ED-Introducción Ejemplo 2 8 9 FUNCIÓN

URJC-ED-Introducción

Ejemplo 2

89

FUNCIÓN Ejemplo2(num1, num2: Natural) DEVUELVE Natural SI num = 0 ENTONCES DEV num2; SI NO SI num1 = 1 ENTONCES DEV num2*num2; SI NO PARA i DESDE 1 HASTA num1 HACER num2 := num2 + i; DEV Ejemplo2(num1-2,num2)*Ejemplo2(num1-2,num2+num1);

URJC-ED-Introducción

91

Ejemplo 1

FUNCIÓN Ejemplo1(num:Natural) DEVUELVE Natural SI num < 1 ENTONCES DEV 1 SI NO DEV num * Ejemplo1(num-1);

Tamaño de la entrada parámetro entrada num

es_caso_sencillo(n) n<1

instrucciones_caso_sencillo DEVOLVER 1, con coste O(1)

nº llamadas recursivas 1

reducción(n) n-1

instrucciones_caso_recursivo multiplicación, con coste O(1)

multiplicación, con coste O(1)   URJC-ED-Introducción 9 0 Ejemplo 2
 

URJC-ED-Introducción

90

Ejemplo 2

FUNCIÓN Ejemplo2(num1, num2: Natural) DEVUELVE Natural SI num = 0 ENTONCES DEV num2; SI NO SI num1 = 1 ENTONCES DEV num2*num2; SI NO PARA i DESDE 1 HASTA num1 HACER num2 := num2 + i; DEV Ejemplo2(num1-2,num2)*Ejemplo2(num1-2,num2+num1);

d

es_caso_sencillo(n)

a en ra

T

ama o

ñ

d

l

e

t

a

instrucciones_caso_sencillo

 

nº llamadas recursivas

 

reducción(n)

 

instrucciones_caso_recursivo

 
 

URJC-ED-Introducción

92

Ejemplo 2

FUNCIÓN Ejemplo2(num1, num2: Natural) DEVUELVE Natural SI num = 0 ENTONCES DEV num2; SI NO SI num1 = 1 ENTONCES DEV num2*num2; SI NO PARA i DESDE 1 HASTA num1 HACER num2 := num2 + i; DEV Ejemplo2(num1-2,num2)*Ejemplo2(num1-2,num2+num1);

a en ra

ama o

e

T

ñ

d

l

t

d

a

num1

es_caso_sencillo(n)

instrucciones_caso_sencillo

nº llamadas recursivas

instrucciones_caso_recursivo

reducción(n)

• • instrucciones_caso_recursivo reducción(n)   URJC-ED-Introducción 9 3 Ejemplo 2
 

URJC-ED-Introducción

93

Ejemplo 2

FUNCIÓN Ejemplo2(num1, num2: Natural) DEVUELVE Natural SI num = 0 ENTONCES DEV num2; SI NO SI num1 = 1 ENTONCES DEV num2*num2; SI NO PARA i DESDE 1 HASTA num1 HACER num2 := num2 + i; DEV Ejemplo2(num1-2,num2)*Ejemplo2(num1-2,num2+num1);

e

ama o

T

ñ

d

l

t

a en ra

d

a

num1

es_caso_sencillo(n) n<2 (n=0 ó n=1)

 

instrucciones_caso_sencillo multiplicación y retorno valor, O(1)

nº llamadas recursivas

 

reducción(n)

 

instrucciones_caso_recursivo

 
 

URJC-ED-Introducción

95

Ejemplo 2

FUNCIÓN Ejemplo2(num1, num2: Natural) DEVUELVE Natural SI num = 0 ENTONCES DEV num2; SI NO SI num1 = 1 ENTONCES DEV num2*num2; SI NO PARA i DESDE 1 HASTA num1 HACER num2 := num2 + i; DEV Ejemplo2(num1-2,num2)*Ejemplo2(num1-2,num2+num1);

T

es_caso_sencillo(n) n<2 (n=0 ó n=1)

instrucciones_caso_sencillo

nº llamadas recursivas

instrucciones_caso_recursivo

ñ

d

l

ama o

e

a en ra

a

t

d

num1

reducción(n)

ñ d l ama o e a en ra a t d num1 reducción(n)   URJC-ED-Introducción
 

URJC-ED-Introducción

94

Ejemplo 2

FUNCIÓN Ejemplo2(num1, num2: Natural) DEVUELVE Natural SI num = 0 ENTONCES DEV num2; SI NO SI num1 = 1 ENTONCES DEV num2*num2; SI NO PARA i DESDE 1 HASTA num1 HACER num2 := num2 + i; DEV Ejemplo2(num1-2,num2)*Ejemplo2(num1-2,num2+num1);

e

ama o

T

ñ

d

l

t

a en ra

d

a

num1

es_caso_sencillo(n) n<2 (n=0 ó n=1)

 

instrucciones_caso_sencillo multiplicación y retorno valor, O(1)

nº llamadas recursivas 2

 

reducción(n)

 

instrucciones_caso_recursivo

 
 

URJC-ED-Introducción

96

Ejemplo 2

FUNCIÓN Ejemplo2(num1, num2: Natural) DEVUELVE Natural SI num = 0 ENTONCES DEV num2; SI NO SI num1 = 1 ENTONCES DEV num2*num2; SI NO PARA i DESDE 1 HASTA num1 HACER num2 := num2 + i; DEV Ejemplo2(num1-2,num2)*Ejemplo2(num1-2,num2+num1);

T

es_caso_sencillo(n) n<2 (n=0 ó n=1)

instrucciones_caso_sencillo multiplicación y retorno valor, O(1)

nº llamadas recursivas 2

reducción(n) n-2

instrucciones_caso_recursivo

ñ

d

l

ama o

e

a en ra

a

t

d

num1

ñ d l ama o e a en ra a t d num1 URJC-ED-Introducción Ejemplo 3

URJC-ED-Introducción

Ejemplo 3

97

FUNCIÓN Ejemplo3(num:Natural) DEVUELVE Natural SI num < 2 ENTONCES DEV num SI NO DEV 5 * Ejemplo3(num/2) + num;

URJC-ED-Introducción

99

Ejemplo 2

FUNCIÓN Ejemplo2(num1, num2: Natural) DEVUELVE Natural SI num = 0 ENTONCES DEV num2; SI NO SI num1 = 1 ENTONCES DEV num2*num2; SI NO PARA i DESDE 1 HASTA num1 HACER num2 := num2 + i; DEV Ejemplo2(num1-2,num2)*Ejemplo2(num1-2,num2+num1);

T

es_caso_sencillo(n) n<2 (n=0 ó n=1)

instrucciones_caso_sencillo multiplicación y retorno valor, O(1)

nº llamadas recursivas 2

reducción(n) n-2

instrucciones_caso_recursivo bucle O(n) y resto O(1) O(n)

ñ

d

l

ama o

e

a en ra

a

t

d

num1

O(n) y resto O(1) O(n) ñ d l ama o e a en ra a t

URJC-ED-Introducción

Ejemplo 3

98

FUNCIÓN Ejemplo3(num:Natural) DEVUELVE Natural SI num < 2 ENTONCES DEV num SI NO DEV 5 * Ejemplo3(num/2) + num;

Tamaño de la entrada

es_caso_sencillo(n)

instrucciones_caso_sencillo

nº llamadas recursivas

reducción(n)

instrucciones_caso_recursivo

• nº llamadas recursivas • reducción(n) • instrucciones_caso_recursivo URJC-ED-Introducción 1 0 0

URJC-ED-Introducción

100

Ejemplo 3

FUNCIÓN Ejemplo3(num:Natural) DEVUELVE Natural SI num < 2 ENTONCES DEV num SI NO DEV 5 * Ejemplo3(num/2) + num;

Tamaño de la entrada parámetro entrada num

es_caso_sencillo(n)

instrucciones_caso_sencillo

nº llamadas recursivas

instrucciones_caso_recursivo

reducción(n)

• • instrucciones_caso_recursivo reducción(n) URJC-ED-Introducción Ejemplo 3 1 0 1 FUNCIÓN

URJC-ED-Introducción

Ejemplo 3

101

FUNCIÓN Ejemplo3(num:Natural) DEVUELVE Natural SI num < 2 ENTONCES DEV num SI NO DEV 5 * Ejemplo3(num/2) + num;

Tamaño de la entrada parámetro entrada num

es_caso_sencillo(n) n<2

instrucciones_caso_sencillo DEVOLVER num, O(1)

nº llamadas recursivas

instrucciones_caso_recursivo

reducción(n)

• • instrucciones_caso_recursivo reducción(n) URJC-ED-Introducción 1 0 3 Ejemplo 3 FUNCIÓN

URJC-ED-Introducción

103

Ejemplo 3

FUNCIÓN Ejemplo3(num:Natural) DEVUELVE Natural SI num < 2 ENTONCES DEV num SI NO DEV 5 * Ejemplo3(num/2) + num;

Tamaño de la entrada parámetro entrada num

es_caso_sencillo(n) n<2

instrucciones_caso_sencillo

nº llamadas recursivas