Cap2.2 Ejercicios

Descargar como pptx, pdf o txt
Descargar como pptx, pdf o txt
Está en la página 1de 114

Universidad Autónoma Gabriel Rene Moreno

FICCT
Semestre I/2018

Análisis de Algoritmos (II)

Programación II Ing. Mary López


Caso 1: Constante

La complejidad Constante es O(1) . El numero de entradas no


influirá en la complejidad del algoritmo.

//La repeticion es 5 veces


void ejer1(unsigned int x){
char tmp[10];
int k=5;
for (int i=0; i < k; i++) {
itoa(x,tmp,10);
MessageDlg(tmp, mtConfirmation,TMsgDlgButtons() << mbOK , 0);
x=x*2;
}
}
Caso 2: Lineal

La complejidad Lineal es O(n). El numero de entradas N indicara el


limite de las iteraciones del algoritmo

¿Cual es la función T(N) del algoritmo? ¿Cual es el orden de


crecimiento del algoritmo?
for j=1;j<=n;j++;se ejecutara Los términos no
1 asignación dominantes valen 0 y las
n+1 comparaciones
n incrementos constantes valen 1.
a=a+1; se ejecutara n veces Reformulando el T(n):
1 asignación
O(N) = N

Orden de crecimiento
T(N) = (1+N+1+N) + N = (2N +2)+ N =3N+2 Lineal.

Resulta lo mismo que aplicar la regla del CICLO (Ver comentario)


Caso 2: Lineal

La complejidad de un algoritmo que carga un vector es


Lineal, es decir O(n).
El numero de entradas N indicara el limite de las
iteraciones del algoritmo.

void carvec(int *vec,int n){

for (int i=0; i < n; i++) { 1 + N+1 + N

vec[i]=1+rand()%(101-1); 1 * N

} T(n) = 3N+2
 O(N)
}
Caso 2: Lineal
La complejidad de un algoritmo que invierte un vector
es Lineal, es decir O(n).
El numero de entradas N indicara el limite de las
iteraciones del algoritmo.
void mosinv(int *vec,unsigned int n){
for (int i=n-1;i>=0;i--) { 1 + N+1 + N
char tmp[10];
int x=vec[i];
3 * N
itoa(x,tmp,10);
MessageDlg(tmp,
mtConfirmation,
TMsgDlgButtons() << mbOK , 0); T(n) = 5N+2
 O(N)
}
}
Caso 2: Lineal

Al invertir un vector.
¿Podemos de alguna forma disminuir el total de instrucciones ?

void invecI(int *vec,unsigned int n){


- Mejora el T(n)
unsigned int ini=(n/2)-1; - Complejidad sigue LINEAL
unsigned int fin=ini+1;
int aux;
3
if(n %2 != 0) fin=fin+1;
for (int i=ini; i >=0; i--) { 1 + (N/2)+1 + N/2
aux=vec[i] ;
vec[i]=vec[fin]; 4 * N/2
vec[fin]=aux;
fin=fin+1;
} T(n) = 3N + 5
 O(N)
}
Caso 2: Lineal

Al invertir un vector.
¿Podemos de alguna forma disminuir el total de instrucciones ?

- Mejora el T(n)
void invecII(int *vec,unsigned int n){ - Complejidad sigue LINEAL
unsigned int med=n/2;
unsigned int fin=n-1;
2
int aux;
for (unsigned int i=0; i <med; i++) { 1 + (N/2)+1 + N/2
aux=vec[i] ;
vec[i]=vec[fin];
4 * N/2
vec[fin]=aux;
fin=fin-1;
}
} T(n) = 3N + 4
 O(N)
Caso 2: Lineal
Obsérvese el comportamiento de los siguientes algoritmos:

- Pertenece1  Realiza N vueltas


- Pertenece2  Se puede asumir que es la suma de mínimo (1) de
comparaciones con el máximo de comparaciones (n) dividido entre 2
=> (1+N)/2 = ½ * (1+N) = N
=> O (N)
Caso 3: Cuadrático

Supongamos en lenguaje C :
for i=1;i<=n; i++;
for j=1; j<=n; j++;
a=a+1;
¿Cual es la función T(N) del algoritmo? ¿Cual es el orden de crecimiento
del algoritmo?

for i=1;i<=n; i++  1+ n+1+ n Los términos no dominantes


for j=1; j<=n; j++;  (1+n+1+n)*n valen 0 y las constantes valen 1.
a=a+1  1* n*n
Reformulando el T(n):
Luego: O(N) = N2
T(N) = (2N + 2) + (2N + 2)N + NN
=2N+2 + 2N^2 +2n +N^2 Orden de crecimiento Cuadrático.

Resulta lo mismo que aplicar la regla del CICLO (Ver comentario)


Caso 3: Cuadrático
Supongamos en un lenguaje X :
for i=1;i<=n; i++;
for j=i; j<=n; j++;
a=a+1;
¿Cual es la función T(N) del algoritmo? ¿Cual es el orden de
Considere solo incrementos (termino crecimiento del algoritmo?
Dominante). Los términos no
dominantes valen 0 y las
for i=1;i<=n; i++  incrementa i n veces constantes valen 1.
for j=i; j<=n; j++  incrementa j n*(n/2) veces Reformulando
2
el T(n):
a=a+1  se ejecuta 1*(n)*(n/2) O(N) = N
Luego: Orden de crecimiento
T(N) = N + 1/2 N2 + 1/2 N2
Cuadrático.
= N + N2

Resulta lo mismo que aplicar la regla DE LA SERIE (Verifique)


Caso 3: Cuadrático

 El tiempo que toma un algoritmo puede variar en función de


diferentes instancias para un mismo tamaño N de entradas.
 Para comprender esto mejor consideremos el ejemplo del
programa de ordenación por inserción.

insercion(t)
for i=1 to n
x= t[i]
j=i-1
while j > 0 and x<t[j]
t[j+1]=t[j]
j=j-1
t[j+1]=x
Caso 3: Cuadrático
Ordenación por Burbuja. Se basa en el principio de comparar e intercambiar
pares de elementos contiguos hasta que todos estén ordenados.
 Desde el primer elemento hasta el penúltimo no ordenado comparar cada
elemento con su sucesor e intercambiar si no están en orden

void burbuja(int *vec,unsigned int n)


{ int aux; unsigned int pasada; unsigned int j;
for(pasada=0; pasada < n-1; pasada++) 1 + N + N-1
for (j=0; j < (n-pasada-1); j++) 1*(N-1) + [(2+N+1)/2]*(n) + [(1+N)/2]*(n)

if (vec[j] > vec[j+1]) {


aux=vec[j];
vec[j]=vec[j+1]; 4 * [(3+N)/2]*(n)
vec[j+1]=aux; T(n) = 3N2 + 10N -1
}
}  O(N2)

Si en la primera PASADA se ordenara todo igual tendría que hacer las N pasadas.
pasada N J Inc J Com J
0 4 0 3 4
1
2
3
1 0 2 3
1
2
2 0 1 2
1
3
6 9

Incrementos De J --> Suma total de la serie = 1 + 2 + 3 = 6 --> [(1+N)/2]*(n)


Comparaciones De J --> Suma total de la serie = 2 + 3 + 4 = 9 --> [(2+N+1)/2]*n
Caso 3: Cuadrático Realizar la tabla : Numero
de pasadas vs Numero de
intercambios y
public void BurbujaMejor() { comparaciones
Booleann Ordenado= false;
Int pasada = 0;
While ((Ordenado==false) && (pasada < N-1))
{
Ordenado= true;
for (int j=0; j < (N-pasada-1); j++)
if (A[j] > A[j+1]) {
intercambiar(j,j+1);
Ordenado= false;
}
pasada ++;
}
}
Caso 3: Cuadrático

Tablas de multiplicar hasta el 10

void ejer10(){
AnsiString Cadena;
for (int M = 1; M <= 10; M++)
{
for (int N = 1; N <= 10; N++)
Cadena += AnsiString(M) + "x" + AnsiString(N) + "=" + AnsiString(M*N) + " ";
Cadena += "\n";
}
ShowMessage(Cadena);
}
Caso 4: Cubico

Obtener el Producto de 2 Matrices

void proMat(int **a, int **b, int **c, unsigned int n,unsigned int
m,unsigned int p)
{ unsigned int i,j,k;
for (i=0; i<n; i++)
for (j=0; j<m; j++)
{
c[i][j] = 0;
for (k=0; k<p; k++)
c[i][j] = c[i][j] + ( a[i][k] * b[k][j] );
}
}
Caso 5: Logaritmico
• El algoritmo de búsqueda binaria es de complejidad Logaritmica, es decir
O(ln n).
• Este algoritmo divide a la mitad al conjunto por cada iteración
•  O (Log 2 N)

bool busBin(int *vec,unsigned int n, unsigned int clave) {


1. int menor=0; int mayor=n; bool encontrado=false;
int medio;
2. while(menor <= mayor && encontrado == False){
3. medio = (menor + mayor) / 2;
4. if(clave > vec[medio])
5. menor = medio + 1;
else
6. if(clave<vec[medio])
7. mayor=medio-1;
8. else encontrado=true;
}
9. return encontrado;
}
Caso 6: Recursivos

Recursión = Repetición
Es un algoritmo que se llama a si mismo para
solucionar el problema
El análisis recursivo de un algoritmo es normalmente casi directo y por simple
inspección, Para esto se busca representar el comportamiento del algoritmo
mediante una ecuación de recurrencia.
Una operación compleja se puede descomponer recursivamente en términos
más sencillos, para que los resultados parciales generen la solución del problema
completo. Así la función recursiva tiene 2 partes:
- Caso Base  T(1)
- Caso Recursivo  T(?) -
El caso recursivo es donde la función se llama a si mismo produciendo una
especie de repetición controlada por la variable de recursión. Es esto
justamente el comportamiento de esta variable la que define la ecuación de
recurrencia y como se representara la expresión algebraica buscada.
Si consideremos el siguiente problema para buscar un elemento t en
un arreglo A recursivamente:

En este algoritmo podemos ver que para los casos en que :


• El tiempo es una constante cuando se tiene que:
• n=0
• El valor es encontrado.
• En los otros casos depende del valor n − 1.

Esto SE PUEDE representar por una función recurrente de forma CASO 1:


Complejidad Recursivos: Tipo 1
Int Recursiva1 (int n) {
If n<=1 return 0;
else return Recursiva1(n-1);
}

c1 Tiempo de ejecucion del caso trivial n<=1


Si n>1, el tiempo puede dividirse en dos partes :
 T(n-1) La llamada RECURSIA con (n-1)
 c2 El tiempo para evaluar (n>1) y la operacion aritmetica con la llamada
recursiva
Complejidad Recursivos: Tipo 2

Int Recursiva2 (int n, int x) {


If n<=1
return 1;
else {
for (int i=1;i<=n;i++)
x=x+1;
return (Recursiva2(n-1,x));
}
}
Complejidad Recursivos: Tipo 3

T(x) = T(x/2) + 1
Si x=N => T(N) = T(N/2) + 1
Si x=N/2 => T(N/2) = T(N/4) + 1
Si x=N/4 => T(N/4) = T(N/8) + 1
Luego podemos reemplazar:
T(N) = T(N/2) + 1
= [ T(N/4) + 1 ] + 1 = T(N/4)+2
= [T(N/8) + 1 ] + 2 = T(N/ 23 )+ 3
Si: K = 3
= T(N/ 2k )+ K
Si: N/ 2k=1 => Aplicando logaritmos => k = ln n
= T(1)+(Ln n) = 1 + Ln n
O(Ln n )
http://segweb.blogspot.com/2012/03/recurrencia.html
http://segweb.blogspot.com/2012/03/recurrencia.html
Complejidad Recursivos: Tipo 4

Int Recursiva4 (int n) {

If n<=1 return 1;

else return Recursiva4(n-1) + Recursiva4(n-1);

T(x) = 2T(x-1) + 1
Si x=N => T(N) = 2T(N-1) + 1
Si x=N-1 => T(N-1) = 2T(N-2) + 1
Si x=N-2 => T(N-2) = 2T(N-3) + 1
Luego podemos reemplazar:
T(N) = 2T(N-1) + 1
= 2 [2T(N-2) + 1 ] + 1 = 22 T(N-2)+3
= 22 [2T(N-3) + 1 ] + 3 = 23 T(N-3)+ 7 = 23 T(N-3)+ (23 -1)
Si: K = 3
= 2k T(N-k)+(2k -1)
Si: N-K=1
= 2k T(1)+(2k -1) = 2k +2k -1 = 2n-1
O(2n ).
Recursivo: Logarítmico-Lineal

 Prerrequisito :
Comprender la Recursión

 El MERGESORT consiste en :
 Dividir los elementos en dos secuencias de la misma
longitud aproximadamente.
 Ordenar de forma independiente cada sub-secuencia.
 Mezclar las dos secuencias ordenadas para producir la
secuencia final ordenada.

Algoritmo de fácil división y difícil unión


Arbol Merge-Sort
 Una ejecución de merge-sort esta representado por un árbol
binario :

 La raíz es la primera llamada


 Cada nodo representa una llamada recursiva de merge-sort
• Secuencia sin ordenar antes de la ejecución y su partición
• Secuencia ordenada al final de la ejecución
 Las hojas son llamadas a secuencias de tamaño 0 o 1

6 2 9 4 3 8 6 1
Arbol Merge-Sort

Partición del conjunto en 2 partes

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9

7 2 9 4  2 4 7 9 3 8 6 1  1 3 8 6

7 2  2 7 9 4  4 9 3 8  3 8 6 1  1 6

77 22 99 44 33 88 66 11


Arbol Merge-Sort

Llamada recursiva , Partición

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9
mergeSort

6 29 4 2 4 7 9 3 8 6 1  1 3 8 6

7 2  2 7 9 4  4 9 3 8  3 8 6 1  1 6

77 22 99 44 33 88 66 11


Arbol Merge-Sort

Llamada recursiva , Particion

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9

629 4 2 4 7 9 3 8 6 1  1 3 8 6
mergeSort

622 7 9 4  4 9 3 8  3 8 6 1  1 6

77 22 99 44 33 88 66 11


Arbol Merge-Sort

Llamada recursiva , Caso Base

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9

6 29 4 2 4 7 9 3 8 6 1  1 3 8 6

622 7 9 4  4 9 3 8  3 8 6 1  1 6
mergeSort

6 6 22 99 44 33 88 66 11


Arbol Merge-Sort

Llamada recursiva , Caso Base

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9

6 29 4 2 4 7 9 3 8 6 1  1 3 8 6

622 7 9 4  4 9 3 8  3 8 6 1  1 6
mergeSort

66 22 99 44 33 88 66 11


Arbol Merge-Sort

Mezcla  Merge

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9

6 29 4 2 4 7 9 3 8 6 1  1 3 8 6

622 6 9 4  4 9 3 8  3 8 6 1  1 6

merge

66 22 99 44 33 88 66 11


Arbol Merge-Sort

Mezcla  Merge

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9

6 29 4 2 4 7 9 3 8 6 1  1 3 8 6
mergeSort

622 6 9 4 3 8  3 8 6 1  1 6

66 22 99 44 33 88 66 11


Arbol Merge-Sort

Mezcla  Merge

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9

6 29 4 2 4 7 9 3 8 6 1  1 3 8 6

622 6 9 4 3 8  3 8 6 1  1 6
mergeSort

66 22 99 44 33 88 66 11


Arbol Merge-Sort

Mezcla  Merge

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9

6 29 4 2 4 7 9 3 8 6 1  1 3 8 6

622 6 9 4 3 8  3 8 6 1  1 6
mergeSort

66 22 99 44 33 88 66 11


Arbol Merge-Sort

Llamada recursiva ,… , Caso Base, Mezcla

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9

6 29 4 2 4 7 9 3 8 6 1  1 3 8 6

622 6 9 4  4 9 3 8  3 8 6 1  1 6

merge

66 22 99 44 33 88 66 11


Arbol Merge-Sort

Mezcla

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9

6 29 4 2 4 6 9

merge

622 6 9 4  4 9 3 8 6 1  1 6

66 22 99 44 3 88 66 11


Arbol Merge-Sort

Mezcla

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9
mergeSort

6 29 4 2 4 6 9 3 8 6 1

622 6 9 4  4 9 3 8 6 1  1 6

66 22 99 44 3 88 66 11


Arbol Merge-Sort

Mezcla

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9

6 29 4 2 4 6 9 3 8 6 1
mergeSort

622 6 9 4  4 9 3 8 3 8 6 1  1 6

66 22 99 44 88 66 11


Arbol Merge-Sort

Mezcla

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9

6 29 4 2 4 6 9 3 8 6 1

622 6 9 4  4 9 3 8 3 8 6 1  1 6
mergeSort

66 22 99 44 33 88 66 11


Arbol Merge-Sort

Mezcla

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9

6 29 4 2 4 6 9 3 8 6 1

622 6 9 4  4 9 3 8 3 8 6 1  1 6
mergeSort

66 22 99 44 33 88 66 11


Arbol Merge-Sort

Mezcla

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9

6 29 4 2 4 6 9 3 8 6 1

622 6 9 4  4 9 3 8  3 8 6 1  1 6

merge

66 22 99 44 33 88 66 11


Arbol Merge-Sort

Mezcla

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9

6 29 4 2 4 6 9 3 8 6 1
mergeSort

622 6 9 4  4 9 3 8  3 8 6 1 6

66 22 99 44 33 88 66 11


Arbol Merge-Sort

Mezcla

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9

6 29 4 2 4 6 9 3 8 6 1

622 6 9 4  4 9 3 8  3 8 6 1 6
mergeSort

66 22 99 44 33 88 66


Arbol Merge-Sort

Mezcla

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9

6 29 4 2 4 6 9 3 8 6 1

622 6 9 4  4 9 3 8  3 8 6 1 6
mergeSort

66 22 99 44 33 88 66 11


Arbol Merge-Sort

Llamada recursiva ,… , Mezcla, Mezcla

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9

6 29 4 2 4 6 9 3 8 6 1 |

622 6 9 4  4 9 3 8  3 8 6 1  1 6

merge

66 22 99 44 33 88 66 11


Arbol Merge-Sort

Llamada recursiva ,… , Mezcla, Mezcla

6 2 9 43 8 6 1  1 2 3 4 6 7 8 9

6 29 4 2 4 6 9 3 8 6 1  1 3 6 8

merge

622 6 9 4  4 9 3 8  3 8 6 1  1 6

66 22 99 44 33 88 66 11


Arbol Merge-Sort

Mezcla

6 2 9 43 8 6 1  1 2 3 4 6 6 8 9

merge

6 29 4 2 4 6 9 3 8 6 1  1 3 6 8

622 6 9 4  4 9 3 8  3 8 6 1  1 6

66 22 99 44 33 88 66 11


MergeSort

void mergeSort (int *A, unsigned int bajo, unsigned int


alto,unsigned int n){
if (bajo < alto) //Si hay más de un elemento
{
int medio = (alto + bajo)/2;
mergeSort (A, bajo, medio,n);
mergeSort (A, medio+1, alto,n);
//Proceso que mezcla el resultado de las dos llamadas anteriores
merge (A, bajo, medio+1, alto,n);
}
}
MergeSort

void merge (int *A, unsigned int bajo, unsigned int bajo_2,
unsigned int alto,unsigned int n) {
unsigned int i = bajo; //Variable de 1ro elemento de la 1ra subsecuencia
unsigned int finbajo = bajo_2 -1; // Ultimo elemento de la 1ra subsecuencia
unsigned int j = bajo_2; //1ro elemento de la 2da subsecuencia
unsigned int k = bajo;
int *Temp=new int[n]; /* Temp es un array ya definido*/
while (( i <= finbajo) && (j<= alto))
{
if (A[i] <= A[j]) Temp[k++] = A[i++];
else Temp[k++] = A[j++];
}
MergeSort

while (i <= finbajo) //Si se agotan todos los elementos de la 2da subsec
Temp[k++] = A[i++];
while (j <= alto) //Si se agotaron los de la 1ra subsecuecia
Temp[k++] = A[j++];
//Paso todos los elementos del Temp al array A
for (i = bajo; i <= alto; i++)
A[i] = Temp[i];
}
MergeSort – Complejidad O

Si analizamos el proceso Merge:


 La entrada consiste en el total de elementos n y que cada
comparación asigna un elemento al vector Temp.
 El número de comparaciones es (n+1) y el número de
asignaciones es n. Por lo tanto, el algoritmo de mezcla se
ejecuta en un tiempo lineal O(n).
 Si analizamos el proceso MergeSort :
 El análisis de eficiencia de la ordenación por mezcla da
lugar a una ecuación recurrente (algoritmo recursivo)
para el tiempo de ejecución.
MergeSort – Complejidad O

 Suponemos n potencia de 2
n = 2K
log2 n = K
 Tiempo de Ordenación
 Para N = 1, Tiempo constante.
 Para N > 1, El tiempo de ordenación para n números
es igual al tiempo para:
• 2 ordenaciones recursivas de tamaño n/2
• El tiempo para mezclar (que es lineal)
 Por tanto,
T(n) = 2 T(n/2) + n
MergeSort – Complejidad O

 (1) if n  1
T ( n)  
T ( n / 2)  T ( n / 2)  (n) if n  1

¿Cómo se resuelve esta recurrencia?


MergeSort – Complejidad O

T (n)  2 * T (n / 2)  (n)
 2 * 2 * T (n / 4)  (n / 2)   (n)
 2 * T (n / 2 )  2 * (n / 2)  (n)
2 2

2
 3 2

 2 * 2 * T ( n / 2 )  ( n / 2 )  ( n )  ( n )
 2 * T ( n / 2 )  2 * ( n / 2 )  2 * ( n )
3 3 2 2

 2 * T (n / 2 )  4 * (n / 4)  2 * (n)
3 3

 2 * T ( n / 2 )  3 * ( n )
3 3

 2 k * T ( n / 2 k )  k * ( n )
MergeSort – Complejidad O

La descomposición termina cuando:


n / 2k  1
2k  n
k  log 2 n

T ( n)  n * (1)  log 2 n * ( n)
 n *1  log 2 n * n
 n  n log 2 n
 n(1  log 2 n)
 n(log 2 n)
 ( n log 2 n)
MergeSort – Complejidad O

En su caso mejor es Ω(n ln n)


En su caso peor es O(n ln n)
En su caso promedio es Ɵ (n ln n)

Por que ?
Recursivo: Cuadrático

 En la ordenación rápida, la secuencia inicial de elementos se


divide en dos sub-secuencias de diferente tamaño.
 La obtención de las dos sub-secuenciases el proceso que
acarrea más tiempo mientras que la combinación de las sub-
secuencias ordenadas para obtener la secuencia final consume
muy poco tiempo.
 Para dividir en dos la secuencia de elementos, se selecciona un
elemento sobre el cual efectuar la división, el PIVOTE.
 Se dividen los elementos en dos grupos, los elementos
menores que el pivote y aquellos mayores o igual al pivote.

Algoritmo de difícil división y fácil unión,


QuickSort

 La elección del elemento Pivote se puede seleccionar de diferentes


formas:
 El mayor de los dos primeros elementos distintos encontrados.
 Otros criterios (1ro, Ultimo, el del centro, etc).
 Para ordenar los elementos comprendidos entre Ai y Aj
1. Si desde Ai hasta Aj hay al menos dos elementos distintos
entonces comenzar la aplicación del algoritmo.
2. Seleccionar el PIVOTE como el elemento mayor de los dos
primeros elementos distintos encontrados.
3. Insertar PIVOTE en la última posición.
QuickSort

4. Permutar los elementos desde Ai hasta Aj de modo que, para


algún i <= k <= j :

Ai, ..., Ak-1< PIVOTE


Ak, ..., Aj>= PIVOTE

Es decir, en las (k-1) primeras posiciones queden los elementos


menores que pivote, mientras que en la posición k hacia delante
queden los elementos mayores o iguales que el pivote.
5. Invocar a:
QUICKSORT desde i hasta (k –1)
QUICKSORT desde k hasta j
QuickSort - Explicación

1) Elegir Pivote: Tomar un


elemento

2) Dividir: Reordenar los


elementos tal que x va a su
posición final E

3) Recursión y Vencer: Ordenar


recursivamente
68
Árbol QuickSort
Inicia
Árbol QuickSort
Partir (1)
Índice
i ini Pivote Fin

0 1 2 3 4 5 6 7
7 6 2 10 4 5 9 8 Pivote

Como 10 es mayor que 8 este no esta en una posición correcta. Luego debemos
continuar avanzando con i hasta encontrar uno menor que el pivote 8.

Índice
ini i Pivote Fin

0 1 2 3 4 5 6 7
7 6 2 10 4 5 9 8 Pivote

Como 10 es mayor que 8 este no esta en una posición correcta. Luego debemos continuar
avanzando con i hasta encontrar uno menor que el pivote 8.

Índice
ini Pivote i Fin

0 1 2 3 4 5 6 7
7 6 2 10 4 5 9 8 Pivote

Encontramos el 4. Luego este lo intercambiamos por el 10


Árbol QuickSort
Índice
ini Pivote i Fin

0 1 2 3 4 5 6 7
7 6 2 4 10 5 9 8 Pivote

Como 10 es mayor que 8 este no esta en una posición correcta. Luego debemos
continuar avanzando con i hasta encontrar uno menor que el pivote 8.
Índice
ini Pivote i Fin

0 1 2 3 4 5 6 7
7 6 2 4 10 5 9 8 Pivote

Encontramos el 4. Luego este lo intercambiamos por el 10

Índice
ini Pivote i Fin

0 1 2 3 4 5 6 7
7 6 2 4 5 10 9 8 Pivote

Encontramos el 5. Luego este lo intercambiamos por el 10


Árbol QuickSort
Índice
ini Pivote i Fin

0 1 2 3 4 5 6 7
7 6 2 4 5 10 9 8 Pivote
Como 10 es mayor que 8 este no esta en una posición correcta. Luego
debemos continuar avanzando con i hasta encontrar uno menor que el pivote 8.

El apuntador i llego a su posición máxima. Finalmente hay que mover el pivote 8 a la posición donde quedo el
apuntador indicepivote ya que este es mayor y debe ir a la derecha.

Índice
ini Pivote Fin

0 1 2 3 4 5 6 7
7 6 2 4 5 10 9 8 Pivote

Índice
ini Pivote Fin

0 1 2 3 4 5 6 7
7 6 2 4 5 8 9 10

Pivote
El algoritmo termina poniendo el Pivote en su posición de ordenación correcta y al mismo tiempo divide al conjunto en
2 para continuar ordenando
Árbol QuickSort

partición
Árbol QuickSort

quickSort (I)
Árbol QuickSort
Partir (2)

0 1 2 3 4
7 6 2 4 5 ip piv ini fin i
0 5 0 4 0
1 1
0 1 2 3 4 2 2
2 6 7 4 5 3
4

0 1 2 3 4
2 4 7 6 5

0 1 2 3 4
2 4 5 6 7
Árbol QuickSort

partición
Árbol QuickSort

Partir (3)

0 1
2 4 ip piv ini fin i
0 4 0 1 0
1 1
0 1
2 4

0 1
2 4
Árbol QuickSort

quickSort (I)
Árbol QuickSort

partición
Árbol QuickSort

partición
Árbol QuickSort

partición
Árbol QuickSort

partición
Árbol QuickSort

partición
Árbol QuickSort
Árbol QuickSort
Árbol QuickSort

quickSort (D)
Árbol QuickSort

partición
Árbol QuickSort

partición
Árbol QuickSort

partición
Árbol QuickSort

partición
Árbol QuickSort

partición
Árbol QuickSort
Árbol QuickSort
Árbol QuickSort
Árbol QuickSort

quickSort (D)
Árbol QuickSort

partición
Árbol QuickSort

partición
Árbol QuickSort

partición
Árbol QuickSort

partición
Árbol QuickSort

partición
Árbol QuickSort
Árbol QuickSort
QuickSort

void quickSort( int *A, int ini, int fin )


{
if (ini < fin)
{
int indicepivote = particion(A,ini, fin);
//El pivote ya esta en su posición correcta
//Por eso no se lo toma encuenta en la union
quickSort(A, ini, indicepivote – 1 );
quickSort(A, indicepivote+1, fin);
}

}
QuickSort

int particion(int *A,int ini, int fin)


{
int pivote = A[fin];
int indicepivote = ini;
for ( int i=indicepivote; i< fin ; i++) {
if (A[i] < pivote) {
//Intercambiar solo si i es distinto de indicepivote
intercambiar(A, i ,indicepivote);
indicepivote=indicepivote+1;
}
}
intercambiar(A, indicepivote,fin);
return indicepivote;
}
QuickSort

void intercambiar( int *A, int ptr1, int ptr2 )


{
int temp;
temp = A[ptr1];
A[ptr1] = A[ptr2];
A[ptr2] = temp;
}
QuickSort3

Variacion del QuckSort si se toma como pivote el elemento central.


void QuickSort3 (int *vec, int ini, int fin)
{ int i ,j, medio, tmp,pivote;
medio = (ini + fin)/2;
pivote = vec[medio];
i = ini;
j = fin;
do {
while (vec[i] < pivote) i++;
while (vec[j] > pivote) j--;
if (i <= j) {
tmp = vec[i];
vec[i] = vec[j];
vec[j] = tmp;
i++;
j--;}
}while (i <= j);
if (ini < j)
QuickSort3(vec, ini, j);
if (i < fin)
QuickSort3(vec, i, fin);
}
QuickSort – Complejidad Ω

Caso Mejor: Cuando el pivote, divide al


conjunto en dos subconjuntos de igual tamaño.
En este caso hay dos llamadas con un tamaño
de la mitad de los elementos, y una sobrecarga
adicional lineal. Esto es similar al MergeSort,
Luego en consecuencia el tiempo de ejecución
es :
O(n log n).
QuickSort – Complejidad O

 Caso Peor: Se podría esperar que los subconjuntos de


tamaño muy distinto proporcionen resultados malos
 Que a la Izquierda se quede con un elemento y a la derecha sean (n-
1) elementos.
 Para n=1
• El tiempo de ordenar 1 elemento es sólo 1 unidad
 Para n>1
• Supóngase que en cada paso de recursión sólo hay un elemento
menor a pivote. En tal caso el subconjunto I (elementos menores
que pivote) será uno y el subconjunto D (elementos mayores o igual
a pivote) serán todos los elementos menos uno.
• El tiempo para Partir el conjunto => T(n)
• El tiempo de ordenar 1 elemento de la Izquierda => T(1)
• El tiempo de ordenar los n-1 de la Derecha => T(n-1)
QuickSort - Complejidad

 (1) if n  1
T ( n)  
T (1)  T ( n  1)  (n) if n  1

¿Cómo se resuelve esta recurrencia?


Exceptuando la constante T(1) para
simplificar se tiene:
QuickSort - Complejidad
T(x) = T(x-1) + x
Si x=N => T(N) = T(N-1) + N
Si x=N => T(N-1) = T(N-2) + (N-1)
Si x=N => T(N-2) = T(N-3) + (N-2)

Luego podemos ir reemplazando en :

T(N) = T(N-1) + N
= T(N-2) + (N-1) + N
= T(N-3) + (N-2) + (N-1) + N
Si: N-3 =K
= T(N-K) + (N-K+1) + (N-K+2) + (N-K+3)
Si N-K=1
= T(1) + (2) + (3) +(4)
=1 + 2 + 3 + 4 +N
T(N) = N (N+1) /2
O(n2).
Caso 7: Exponenciales
Caso 7: Complejidad Exponencial

Obtener el Enésimo termino de la serie de Fibonacci  2N

unsigned int fib(unsigned int n){


if(n<=1)
return n;
else return fib(n-1) + fib(n-2);
}
El análisis muestra
F0=0
F1=1
Fn=fn-1 + fn-2 .. for n>=2

Calculando los primeros :


F2=f1+f0=1+0=1
F3=f2+f1=1+1=2
F4=f3+f2=2+1=3
F5=f4+f3=3+2=5, etc.

 La siguiente figura muestra el porque es ineficiente ?


Para calcular Fib(5) 15 NODOS?

 El hijo de un nodo en el arbol contiene las llamadas recursivas realizadas


por la llamada al NODO
 Como el árbol muestra  La función es ineficiente porque los valores son
computados una y otra vez .
• Así por ejemplo Fib(2) es computado tres ves. (Ver Tabla)
 Luego que tan ineficiente es el algoritmo ?
• La figura anterior lo muestra
 Para fib(n) el algoritmo computa
• FOR 0<=n<=6

N Numero de veces que computa


0 1
1 1
2 3
3 5
4 9
5 15
6 25 =2*2*2*2
Lineal Vs Exponencial

Obtener el Enésimo termino de la serie de Fibonacci  O(n)

unsigned int fibI(unsigned int n){


unsigned int *f=new unsigned int[n+1] ;
f[0]=0;
if(n>0){
f[1]=1;
for(int i=2; i<=n; i++){
f[i]=f[i-1]+f[i-2];
}
}
unsigned int x=f[n];
delete f [];
return x;
}
Web
http://www.lab.dit.upm.es/~lprg/material/apuntes/o/index.html
http://latecladeescape.com/articulos/1515-que-es-la-complejidad-de-un-
algoritmo
http://www.virtual.unal.edu.co/cursos/sedes/manizales/4060024/Lecciones/Capi
tulo%20II/rbasicas.htm

Texto electrónico
http://www.lcc.uma.es/~av/Libro/CAP1.pdf

Libro Universidad de Málaga


Antonio Vallecillo
Depto.. Lenguajes y Ciencias de la Computación
ETSI Informática, Campus de Teatinos.

También podría gustarte