Apuntes Complejidad Algorítmica
Apuntes Complejidad Algorítmica
Apuntes Complejidad Algorítmica
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.
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.
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).
2. ORDENAMIENTO DE DATOS
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).
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.
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: 15 67 08 16 44 27 12 35
SEGUNDA PASADA
A: 08 15 67 16 44 27 12 35
TERCERA PASADA
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].
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;
}
}
Ejemplo:
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;
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;
}
}
}
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.
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
PRIMERA PASADA
A: 08 15 67 12 16 44 27 35
SEGUNDA PASADA
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.
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
void Intercambio_Directo(int n)
{
int i,j,aux;
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;
}
}
}
que es igual a:
C = (n2 -n)/2
Mmin = 0
Así por ejemplo si tiene que ordenarse un arreglo que contiene 500 elementos, se
efectuará :
• 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.