Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% encontró este documento útil (0 votos)
43 vistas12 páginas

Apuntes Complejidad Algorítmica

Descargar como pdf o txt
Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1/ 12

Estructura de Datos y Algoritmos 1

1. COMPLEJIDAD
1.1. GENERALIDADES
En computación, al hablar de complejidad, no se está refiriendo a la dificultad que se
tendría para diseñar un programa, o a lo rebuscado de un algoritmo. La teoría de
complejidad tiene que ver con dos medidas de desempeño: tiempo y espacio.
La complejidad computacional de un problema es una medida de los recursos
computacionales (generalmente el tiempo) requeridos para resolver el problema.
La complejidad temporal tiene que ver con el tiempo que tarda un programa para
ejecutarse. La complejidad espacial estudia la cantidad de espacio de almacenamiento
que es necesario para una operación. La gran mayoría de estudios de complejidad están
orientados hacia el desempeño de los algoritmos en función al tiempo, por lo que de aquí
en adelante, al hablar de complejidad, se asumirá que es en el tiempo.
Es evidente que al medir el tiempo que tarda un programa en ejecutarse, no sería
informativo el decir que tarda cinco segundos en una máquina de 166 MHz y que tarda
menos en una más rápida. Para que sea relevante el definir la complejidad temporal de
un algoritmo, ésta es expresada no en términos de la máquina, sino en un interesante
parámetro: el tamaño de la entrada. Al referir la complejidad al tamaño de la entrada,
esta medida es más representativa y útil.
Al analizar la complejidad de un algoritmo, el tiempo está expresado en término de pasos
de computación elementales (asignaciones, comparaciones, multiplicaciones, etc.), por
ejemplo, una operación de asignación ocupa una unidad de tiempo para ejecutarse, un
ciclo ocupa el número de iteraciones en que está definido, etc.

1.2. COMPLEJIDAD TEMPORAL


Ocupando el tamaño de la entrada como el parámetro que define al tiempo de ejecución
de un programa, es posible describir este tiempo como una función de la entrada T(n),
donde n simboliza al tamaño de la entrada. Por ejemplo, el tiempo de ejecución de un
algoritmo puede ser n2+2n.

Cuando se define la complejidad en función al tamaño de la entrada, no se está


considerando a los datos que forman esa entrada, sino solo al conjunto en su tamaño. En
la práctica se observa que un algoritmo ocupa diferente tiempo de ejecución para
entradas del mismo tamaño, pero con diferentes datos. Por ejemplo, un método de
ordenación de valores puede tardar menos tiempo si su entrada está ordenada, o tardar
mucho mayor tiempo incluso con los mismos valores, pero presentados en desorden (es
decir, con el mismo tamaño de entrada tiene diferente comportamiento).
Por lo anterior, se adopta el criterio de tomar siempre, como base de análisis de la
complejidad de un algoritmo, el caso en el cual consuma el mayor tiempo de ejecución,
es decir, el peor caso.

Estructura de Datos y Algoritmos


Estructura de Datos y Algoritmos 2

Ejemplo 1: La función que define el tiempo de ejecución del siguiente algoritmo es T(n)
= 4n+3.
{1} suma = 0;
{2} for(i = 1;i < = N;i++)
{3} suma+ = i;
La instrucción 1 ocupa una unidad de tiempo.
La instrucción 3 ocupa dos unidades de tiempo, una para la suma y otra para la
asignación, y es ejecutada N veces, por lo que ocupa 2N unidades de tiempo.
La instrucción 2 tiene involucrada una asignación que utiliza una unidad de tiempo,
N+1 comparaciones y N incrementos, por lo que ocupa 2N+2 unidades de tiempo.
El tiempo total del algoritmo es T(N) = 1+2N+2+2N, esto es:
T(N) = 4N+3.

1.3. ORDEN DE UN ALGORITMO


La función que define el tiempo de ejecución de un programa proporciona información
interesante para clasificar los diferentes algoritmos que existen para resolver problemas.
Con esta función es posible comparar el desempeño de diferentes algoritmos
desarrollados para un problema en particular (el problema de ordenación de valores, por
ejemplo).

Para simplificar el estudio de la complejidad, se han adoptado ciertas convenciones en su


notación, una de ellas es la del concepto de orden, que indica, de forma simple, el grado
de complejidad de un algoritmo sin considerar por completo la función de tiempo.

Para el ejemplo del método de la burbuja, se tiene una función de tiempo n(n-1)/2 (que
es igual a ( n2-n) /2), y se dice que es de orden n2, o simplemente O(n2).

Para determinar el orden un algoritmo, a partir de su función de tiempo, se eliminan


todos los términos excepto el de mayor grado y se eliminan todos los coeficientes del
término mayor.

Lo anterior es debido a que al aumentar el tamaño de la entrada, es más significativo el


incremento en el término de mayor orden que el de los demás.
Ejemplo 2: El orden de un algoritmo cuyo tiempo de ejecución está dado por T(n) =
3n3+2n+6 esO(T(n)) = O(n3).
Existen algunas reglas que son útiles para determinar el orden de un algoritmo:
Regla 1 (Ciclos FOR): El tiempo de ejecución de un ciclo FOR es al menos el tiempo
de ejecución de las instrucciones dentro de él multiplicado por el número de iteraciones.

Estructura de Datos y Algoritmos


Estructura de Datos y Algoritmos 3

Ejemplo 3: El orden del siguiente algoritmo es O(n).


for(i = 1;i < = N;i++)
suma+ = i;
La función de tiempo para el algoritmo es T(N) = 4N+2, ya que el ciclo ocupa 2N+2 y la
suma 2N , por lo que tiene un orden O(n)).
Regla 2 (Ciclos FOR anidados): Se analiza desde dentro hacia afuera. El tiempo total
de una instrucción dentro de un conjunto de ciclos anidados es igual al tiempo de
ejecución de las instrucciones internas multiplicado por el producto del tamaño de los
ciclos.
Ejemplo 4: El orden del siguiente algoritmo es O(n2).
for(i = 1;i < = N;i++)
for(j = 1;j < = N;j++)
suma+ = ij;
Regla 3 (Condicional): El tiempo de ejecución nunca es mayor que el tiempo de
ejecución de la condicional más el mayor de los tiempo de ejecución de las alternativas.
Ejemplo 4: El orden del siguiente algoritmo es O(n2):
if(i = = j)
for(i = 1;i < = N;i++)
suma+ = i;
else
for(i = 1;i < = N;i++)
for(j = 1;j < = N;j++)
suma+ = ij;
Debido a que el tiempo de ejecución de la condición es de orden O(1) más el mayor
tiempo de ejecución de las alternativas: cuando se cumple la condición es O(n) y cuando
no se cumple es O(n2), por lo cual el orden es O(1)+O(n2), pero, como ya se ha dicho,
solo se toma el mayor, quedando el orden del programa en O(n2).
A los algoritmos de orden n se les llama de orden lineal, los de n2 de orden cuadrado, etc.
Si se grafica el orden de un algoritmo para varios tamaños de entrada, se puede observar
su comportamiento. Como se muestra en la figura 1, un algoritmo de orden O(n2) (línea
gruesa) tiene una velocidad de crecimiento menor que uno con orden O(2n), representado
por la línea delgada. El eje vertical representa T(n) y el eje horizontal a n .

Estructura de Datos y Algoritmos


Estructura de Datos y Algoritmos 4

Figura 1: Comparación de complejidad de dos programas.


Se puede decir que un algoritmo tiene complejidad polinomial, o se ejecuta en tiempo
polinomial, si tiene un orden O(nx). Estos algoritmos se dice que son algoritmos
eficientes y los problemas que se resuelven con estos algoritmos se dice que son
problemas tratables.
Ejemplo 5: El problema de ordenación es tratable, ya que se puede resolver aplicando
un algoritmo de tiempo polinomial.
Un algoritmo tiene complejidad exponencial si la función de tiempo T(n) tiene un orden
O(xn). Los problemas que se resuelven usando algoritmos de tiempo exponencial se
conoce como problemas intratables y a los algoritmos como algoritmos ineficientes.
Ejemplo 6: El problema de las Torres de Hanoi tiene complejidad exponencial de orden
2n.
El algoritmo de las Torres de Hanoi es el siguiente:
void Hanoi(intN,intA,intB,intC)
{
if(n = = 1)
MueveAnillo(A,B);
else{
Hanoi(n-1,A,C,B);
MueveAnillo(A,B);
Hanoi(n-1,C,B,A);
}
}
Debido a que al algoritmo es recursivo, el tiempo de ejecución puede ser descrito por la
función t(n) = 2t(n-1)+constante. De esta forma se observa que al aumentar el tamaño
de la entrada, el tiempo se duplica (factor de dos), por lo que es fácil deducir que el
orden del algoritmo es O(2n).

Estructura de Datos y Algoritmos


Estructura de Datos y Algoritmos 5

Un algoritmo de tiempo polinomial se dice que es eficiente ya que (como se observa en


la figura 1) su tiempo crece mas despacio que un exponencial al aumentar el tamaño de
la entrada, esto significa que aprovechan mejor los cambios tecnológicos.

Estructura de Datos y Algoritmos


Estructura de Datos y Algoritmos 6

2. ORDENAMIENTO DE DATOS

2.1. CONCEPTO DE ORDENAMIENTO

Ordenar significa reorganizar un conjunto de datos u objetos de acuerdo a una secuencia


específica. El proceso de ordenación es importante cuando requiere optimizarse un
proceso de búsqueda.

Los métodos de ordenamiento de datos procesos pueden clasificar en internos o


externos dependiendo del lugar en el que se encuentre almacenada la información.

Los internos actúan sobre datos contenidos en memoria principal; los externos se aplican
sobre datos almacenados en memoria secundaria (Discos flexibles, cintas, discos duros,
etcétera).

Formalmente definimos ordenación de la siguiente manera:

Sea A una lista de n elementos Ao, A1, A2,...,An.

La lista A estará ordenada después de aplicarle un proceso logramos que:

a) Ao <= A1 <= A2 ... <=An (ordenamiento ascendente)


b) Ao>= A1 >= A2 ...>= An (ordenamiento Descendente)

Un método de ordenación es estable si el orden relativo de elementos iguales permanece


inalterado durante el proceso de ordenación. La estabilidad es conveniente si los
elementos ya se encontraban ordenados conforme a algún otro campo.

Un método de ordenación es inestable si se altera el orden relativo de elementos iguales


durante el proceso de ordenación.

2.2. ORDENAMIENTO POR INSERCIÓN DIRECTA

El método de ordenación por inserción directa es el que generalmente utilizan los


jugadores de cartas cuando ordenan éstas, de ahí que también se conozca con el nombre
de método e la baraja.

La idea central de este algoritmo consiste en insertar un elemento del arreglo en la parte
izquierda del mismo, que ya se encuentra ordenada. Este proceso se repite desde el
segundo hasta el n-ésimo elemento.

Estructura de Datos y Algoritmos


Estructura de Datos y Algoritmos 7

Ejemplo:

Supóngase que se desea ordenar las siguientes claves del arreglo A utilizando el método
de inserción directa.

A: 15 67 08 16 44 27 12 35

PRIMERA PASADA

A[2]<A[1] (67<15) no hay intercambio

A: 15 67 08 16 44 27 12 35

SEGUNDA PASADA

A[3]<A[2] (08<67) sí hay intercambio


A[2]<A[1] (08<15) sí hay intercambio

A: 08 15 67 16 44 27 12 35

TERCERA PASADA

A[4]<A[3] (16<67) sí hay intercambio


A[3]<A[2] (16<15) no hay intercambio

A: 08 15 16 67 44 27 12 35

Obsérvese que una vez que se determina la posición correcta del elemento se
interrumpen las comparaciones. Por ejemplo, en el caso anterior no se realizó la
comparación A[2]<A[1].

Las restantes pasadas se presentan a continuación:

Estructura de Datos y Algoritmos


Estructura de Datos y Algoritmos 8

void insercion_directa(int n)
{
int i,j,aux;
i=j=1;
for(;j<n;j++)
for(i=j;i > 0 && (arr[i] < arr[i-1]); i--)
{
aux=arr[i];
arr[i]=arr[i+1];
arr[i+1]=aux;
}
}

2.3. ORDENAMIENTO POR SELECCIÓN DIRECTA


El método de ordenación por selección directa es más eficiente que los métodos
analizados anteriormente.
Pero, aunque su comportamiento es mejor que el de aquéllos y su programación es fácil
y comprensible, no es recomendable utilizarlo cuando el número de elementos del
arreglo es medio grande.

La idea básica de este algoritmo consiste en buscar el menor elemento en el arreglo y


colocarlo en primera posición. Luego se busca el segundo elemento más pequeño del
arreglo y se lo coloca en segunda posición. El proceso continua hasta que todos los
elementos del arreglo hayan sido ordenados. El método se basa en los siguientes
principios:

1. Seleccionar el menor elemento del arreglo.


2. Intercambiar dicho elemento con el primero.
3. Repetir los pasos anteriores con los (n-1), (n-2 ) elementos y así sucesivamente hasta
que sólo quede el elemento mayor.

Ejemplo:

Supongase que se desea ordenar las siguientes claves del arreglo

A: 15 67 08 44 27 12 35

void seleccion_directa(int n)
{
int i,j,min,k;
int cambio;
for(i=0;i<n;i++)
{
min=arr[i];
k=0;

Estructura de Datos y Algoritmos


Estructura de Datos y Algoritmos 9

cambio=0;
for(j=i+1;j<n;j++)
{
if (arr[j]<min)
{
min=arr[j];
k=j;
cambio=1;}
}
if (cambio )
{
arr[k]=arr[i];
arr[i]=min;
}
}
}

2.4. ORDENAMIENTO POR INTERCAMBIO DIRECTO (BURBUJA)

El método de intercalación directo, conocido coloquialmente con el nombre de la


burbuja, es el más utilizado entre los estudiantes de computación, por su fácil
compresión y programación. Pero es preciso señalar que es probablemente el método
más ineficiente.

El método de intercambio directo puede trabajar de dos maneras diferentes. Llevando los
elementos más pequeños hacia la parte izquierda del arreglo o bien llevando los
elementos más grandes hacia la parte derecha del mismo.

La idea básica de este algoritmo consiste en comparar pares de elementos adyacentes e


intercambiarlos entre sí hasta que todos se encuentran ordenados. Se realizan (n-1)
pasadas, transportando en cada una de las mismas el menor o mayor elemento (según sea
el caso) a su posición ideal. Al final de las (n-1) pasadas los elementos del arreglo
estarán ordenados.

Ejemplo :

Supóngase que desean ordenar las siguientes claves del arreglo A, transportando en cada
pasada el menor elemento hacia la parte izquierda del arreglo.

A: 15 67 08 16 44 27 12 35

Las comparaciones que se realizan son las siguientes:

PRIMERA PASADA

Estructura de Datos y Algoritmos


Estructura de Datos y Algoritmos 10

a[7]>a[8] (12>35) no hay intercambio


a[6]>a[7] (27>12) si hay intercambio
a[5]>a[6] (44>12) si hay intercambio
a[4]>a[5] (16>12) si hay intercambio
a[3]>a[4] (08>12) no hay intercambio
a[2]>a[3] (67>08) si hay intercambio
a[1]>a[2] (15>08) si hay intercambio

Luego de la primera pasada el arreglo queda de la siguiente forma:

A: 08 15 67 12 16 44 27 35

Obsérvese que el elemento 08 fue situado en la parte izquierda del arreglo.

SEGUNDA PASADA

a[7]>a[8] (27>35) no hay intercambio


a[6]>a[7] (44>27) si hay intercambio
a[5]>a[6] (16>27) no hay intercambio
a[4]>a[5] (12>16) no hay intercambio
a[3]>a[4] (67>12) si hay intercambio
a[2]>a[3] (15>12) si hay intercambio

Luego de la segunda pasada el arreglo queda de la siguiente forma:

A: 08 12 15 67 16 27 44 35

y el segundo elemento más pequeño del arreglo, en este caso 12, fue situado en la
segunda posición.

A continuación se muestra el resultado de las siguientes pasadas:

3era. Pasada : 08 12 15 16 67 27 35 44
4ta. Pasada : 08 12 15 16 27 67 35 44
5ta. pasada : 08 12 15 16 27 35 67 44
6ta. Pasada : 08 12 15 16 27 35 44 67
7ma. Pasada : 08 12 15 16 27 35 44 67

El algoritmo de ordenación por el método de intercambio directo que transporta en cada


pasada el menor elemento hacia la parte izquierda del arreglo es el siguiente :

void Intercambio_Directo(int n)
{
int i,j,aux;

Estructura de Datos y Algoritmos


Estructura de Datos y Algoritmos 11

i=0;
j= n-1;
for(;j>0;j--)
for(i=0;i<j;i++) //recorre el arreglo de 0 a n-1
{
if (arr[i]>arr[i+1]) //si el elemento actual es mayor que el elemento
siguiente
{
aux=arr[i]; //intercambio de elementos
arr[i]=arr[i+1];
arr[i+1]=aux;
}
}
}

ANÁLISIS DE EFICIENCIA DEL MÉTODO DE INTERCAMBIO DIRECTO

El número de comparaciones en el método de la burbuja es fácilmente contabilizable. En


la primera pasada realizamos (n-1) comparaciones, en la segunda pasada (n-2)
comparaciones, en la tercera pasada (n-3) comparaciones y así sucesivamente hasta
llegar a 2 y 1 comparaciones entre claves, siendo n el número de elementos del arreglo.
Por lo tanto:

C = (n-1) + (n-2) +...+2 + 1 = (n*(n-1))/2

que es igual a:

C = (n2 -n)/2

Respecto al número de movimientos, éstos dependen de si el arreglo está ordenado,


desordenado o en orden inverso. Los movimientos para cada uno de estos casos son:

Mmin = 0

Mmed = 0.75 * (n2 - n)

Mmáx = 1.5 * (n2 - n)

Así por ejemplo si tiene que ordenarse un arreglo que contiene 500 elementos, se
efectuará :

Si el arreglo se encuentra ordenado :


• 124 750 comparaciones

Estructura de Datos y Algoritmos


Estructura de Datos y Algoritmos 12

• 0 movimiento
Si los elementos del arreglo se encuentran dispuestos en forma aleatoria :
• 124 750 comparaciones
• 187 125 movimientos
Si los elementos del arreglo se encuentran en orden inverso:
• 124 750 comparaciones
• 374 250 movimientos
Ahora bien, el tiempo necesario para ejecutar el algoritmo de burbuja es proporcional a
n2, donde n es el número de elementos del arreglo.

Estructura de Datos y Algoritmos

También podría gustarte