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

Curso:

Estructura de Datos

Tema:

Algoritmo de Bsqueda y Ordenacin

Profesora: Iris Cruz Florin

Integrantes:
Armas Sumaran Percy
Edwards Castro Alonso.
Gariza Campos Carlos.
Guzmn Mndez Leonardo.

Ciclo:

II

Ao:

2015

Trujillo Per

Algoritmo de ordenacin.

En computacin y matemticas un algoritmo de ordenamiento es un algoritmo que


pone elementos de una lista o un vector en una secuencia dada por una relacin de
orden, es decir, el resultado de salida ha de ser una permutacin o reordenamiento
de la entrada que satisfaga la relacin de orden dada. Las relaciones de orden ms
usadas son el orden numrico y el orden lexicogrfico. Ordenamientos eficientes son
importantes para optimizar el uso de otros algoritmos (como los de bsqueda y fusin)
que requieren listas ordenadas para una ejecucin rpida. Tambin es til para poner
datos en forma cannica y para generar resultados legibles por humanos.
Desde los comienzos de la computacin, el problema del ordenamiento ha atrado
gran cantidad de investigacin, tal vez debido a la complejidad de resolverlo
eficientemente a pesar de su planteamiento simple y familiar. Por ejemplo, BubbleSort
fue analizado desde 1956. Aunque muchos puedan considerarlo un problema resuelto,
nuevos y tiles algoritmos de ordenamiento se siguen inventado hasta el da de hoy
(por ejemplo, el ordenamiento de biblioteca se public por primera vez en el 2004). Los

algoritmos de ordenamiento son comunes en las clases introductorias a la


computacin, donde la abundancia de algoritmos para el problema proporciona una
gentil introduccin a la variedad de conceptos ncleo de los algoritmos, como notacin
de O mayscula, algoritmos divide y vencers, estructuras de datos, anlisis de los
casos peor, mejor, y promedio, y lmites inferiores.

Tipos de Algoritmos de Ordenacin:


1.- Ordenacin de Insercin.
1.1.-Descripcin:
Este algoritmo es bastante sencillo. Has jugado cartas? Cmo las vas ordenando
cuando las recibes? Yo lo hago de esta manera: tomo la primera y la coloco en mi
mano. Luego tomo la segunda y la comparo con la que tengo: si es mayor, la pongo a
la derecha, y si es menor a la izquierda. Despus tomo la tercera y la comparo con las
que tengo en la mano, desplazndola hasta que quede en su posicin final. Contino
haciendo esto, insertando cada carta en la posicin que le corresponde, hasta que las
tengo todas en orden. Lo haces as t tambin? Bueno, pues si es as entonces
comprenders fcilmente este algoritmo, porque es el mismo concepto.
Para simular esto en un programa necesitamos tener en cuenta algo: no podemos
desplazar los elementos as como as o se perder un elemento. Lo que hacemos es
guardar una copia del elemento actual (que sera como la carta que tomamos) y
desplazar todos los elementos mayores hacia la derecha. Luego copiamos el elemento
guardado en la posicin del ltimo elemento que se desplaz.

1.2.- Caractersticas del algoritmo.


Estabilidad:
- Este algoritmo nunca intercambia registros con claves iguales. Por lo tanto
es estable.
Requerimientos de Memoria:
- Una variable adicional para realizar los intercambios.
Tiempo de Ejecucin:
- Para una lista de n elementos el ciclo externo se ejecuta n-1 veces.
- El ciclo interno se ejecuta como mximo una vez en la primera iteracin, 2
veces en la segunda, 3 veces en la tercera, etc. Esto produce una
complejidad O (n2).
Ventajas:
- Fcil implementacin.
- Requerimientos mnimos de memoria.
Desventajas:
- Es un algoritmo lento, pero puede ser de utilidad para listas que estn
ordenadas o semiordenadas, porque en ese caso realiza muy pocos
desplazamientos.
- Realiza numerosas comparaciones.

1.3.- Un ejemplo:
Te acuerdas de nuestra famosa lista?
4-3-5-2-1
temp toma el valor del segundo elemento, 3. La primera carta es el 4. Ahora
comparamos: 3 es menor que 4. Luego desplazamos el 4 una posicin a la derecha y
despus copiamos el 3 en su lugar.
4-4-5-2-1
3-4-5-2-1
El siguiente elemento es 5. Comparamos con 4. Es mayor que 4, as que no ocurren
intercambios.
Continuamos con el 2. Es menor que cinco: desplazamos el 5 una posicin a la
derecha:
3-4-5-5-1
Comparamos con 4: es menor, as que desplazamos el 4 una posicin a la derecha:
3-4-4-5-1
Comparamos con 3. Desplazamos el 3 una posicin a la derecha:
3-3-4-5-1
Finalmente copiamos el 2 en su posicin final:
2-3-4-5-1
El ltimo elemento a ordenar es el 1. Cinco es menor que 1, as que lo desplazamos
una posicin a la derecha:
2-3-4-5-5
Continuando con el procedimiento la lista va quedando as:
2-3-4-4-5
2-3-3-4-5
2-2-3-4-5
1 - 2 - 3 - 4 - 5.
1.4.- Pseudocdigo:
^

Tabla de variables
Nombre Tipo

Uso

Tabla de variables
Nombre Tipo

Uso

TAM
i
j
temp

Tamao de la lista
Contador
Contador
Para realizar los intercambios

Constante Entera
Entero
Entero
El mismo que los elementos de la lista

1. for (i=1; i<TAM; i++)


2.
temp = lista[i];
3.
j = i - 1;
4.
while ( (lista[j] > temp) && (j >= 0) )
5.
lista[j+1] = lista[j];
6.
j--;
7.
lista[j+1] = temp;

2.- Ordenacin Mergesort o por Mescla.


2.1.- Historia:
- Fue desarrollado en 1945 por John Von Neumann.
2.2.- Descripcin:
Conceptualmente, el ordenamiento por mezcla funciona de la siguiente manera:
1. Si la longitud de la lista es 0 1, entonces ya est ordenada. En otro caso:
2. Dividir la lista desordenada en dos sublistas de aproximadamente la mitad del
tamao.
3. Ordenar cada sublista recursivamente aplicando el ordenamiento por mezcla.
4. Mezclar las dos sublistas en una sola lista ordenada.
El ordenamiento por mezcla incorpora dos ideas principales para mejorar su tiempo de
ejecucin:
1. Una lista pequea necesitar menos pasos para ordenarse que una lista
grande.
2. Se necesitan menos pasos para construir una lista ordenada a partir de dos
listas tambin ordenadas, que a partir de dos listas desordenadas.

Por ejemplo: Slo ser necesario entrelazar cada lista una vez que estn
ordenadas.

2.3.- Ejemplo:

2.4.- Caractersticas del Algoritmo:


Ventajas:
-

Mtodo
estable

de

ordenamiento mientras la operacin de mezclas (merge) est bien


implementada.
- Este algoritmo es efectivo para conjuntos de datos que se puedan
acceder como arreglos, vectores y listas ligadas.
Desventajas:
- Su principal desventaja radica en que est definido recursivamente y
su implementacin no recursiva emplea una pila , por lo que requiere
un espacio adicional de memoria para almacenarla
2.5.- Pseudocdigo:

Inicio combina( A : vector ; B : vector)


Crear Vector C con longitudes de A y B

Mientras (I < longitud A) hacer


C[ K ] A[ I ]

I1

KK+1

J 1

II+1

K 1
Mientras (I < longitud A) y (j <
longitud B)
hacer
Si A[ I ] < B[ J ] entonces
C[ K ] A[ I ]
KK+1
II+1
de lo contrario
C[ K ] B[ J ]

3.- Algoritmos Recursivos de


Bsqueda y Ordenacin y sus tiempos.
1. Algoritmos de ordenacin recursivos

Mientras (J < longitud B) hacer


C[ K ] B[ J ]
KK+1
JJ+1
Fin combina

1.1. Mergesort, Ordenamiento por fusin


Mergesort se ejecuta en un tiempo de O (nlogn) en el peor caso, donde n es el tamao
del array a ordenar. La cantidad de comparaciones realizadas es cerca de optima. Es
un ejemplo bueno de algoritmo recursivo.
La operacin fundamental del algoritmo es la de fusionar dos arrays ordenados. Como
los arrays estn ordenados esto se puede hacer en una pasada a travs de los
arrays. La salida es puesta en un tercer array. Tendremos dos arrays de entrada A y B
y un array de salida C y tres contadores.
Aptr, Bptr y Cptr que estn inicializados al comienzo de los arrays respectivos. El
elemento menor entre A [Aptr] y B [Bptr] es copiado a C [Cptr]. Y los contadores que
corresponda son incrementados. Cuando uno de los arrays de entrada fue copiado
totalmente, el resto del otro array se copia a C.
El tiempo de realizar el merge de dos arrays es lineal porque a lo mximo se realizan
n 1 comparaciones donde n es la cantidad total de elementos.
Cada comparacin agrega un elemento a C excepto la ltima que agrega dos.
El algoritmo de ordenamiento por fusin es sencillo de describir. Si n = 1 la repuesta es
dicho elemento, sino divido el array en dos mitades. Cada mitad es ordenada
recursivamente, esto me da dos mitades ordenadas que pueden ser fusionadas
utilizando el programa de fusin descripto antes.
Presentamos el programa abajo:
void sort por fusion(int A[], int B[], int izq, int der)
{
int centro;
if (izq < der) {
centro=(izq+der)/2;
sort por fusion(A,B,izq,centro);
sort por fusion(A,B,centro+1,der);
fusion(A,B,izq,centro+1,der);
}
}
void fusion(int A[], int B[], int izq, int centro, int der)
{
int final izq, nroelem, tmp;
final izq = centro - 1;

tmp = izq;
nroelem=der-izq+1;
while ((izq <= final izq) && (centro <= der))
{
if (A[izq] < A[centro])
{
B[tmp]=A[izq];
izq++;}
else
{
B[tmp]=A[centro];
centro++;
}
tmp++;
}
while (izq <= final izq)
{
B[tmp]=A[izq];
tmp++;
izq++;
}
while (centro <= der)
{
B[tmp]=A[centro];
tmp++;
centro++;
}
for(int i=1;i<=nroelem;i++)
{
A[der]=B[der];
der- -;

}
}

1.1.1. Anlisis del ordenamiento por fusin.


El ordenamiento por fusin es un ejemplo clsico de las tcnicas usadas para analizar
programas recursivos. Escribiremos una relacin de recurrencia para el clculo del
tiempo de ejecucin.
Asumimos n es potencia de 2 de modo que siempre dividimos la entrada en dos
mitades. Para n = 1 el tiempo es constante, luego lo denotaremos por 1.
En otro caso el tiempo de ordenar n nmeros es igual al tiempo de realizar dos
ordenamientos recursivos de tamao n/2, ms el tiempo de fusin que es lineal.
Obtenemos la siguiente recurrencia:
T(1) = 1
T(n) = 2T(n/2) + n
Resolvamos la recurrencia:
T(n) = 2T(n/2) + n sustituimos n por n/2, obtenemos
T(n/2) = 2T(n/4) + n/2 luego
2T(n/2) = 4T(n/4) + n sustituimos n por n/2, obtenemos
2T(n/4) = 4t(n/8) + n/2 luego
4T(n/4) = 8T(n/8) + n
Tenemos:
T(n) = 2T(n/2) + n = 4T(n/4) + 2n = 8T(n/8) + 3n
si continuamos de esta manera obtenemos:
T(n) = 2kT(n/2
k
) + k.n
Como n = 2k
Entonces k = log2n, obtenemos: T(n) = nT(1) + nlog2n = nlog2n + n = O(nlog2n).

1.2. Quicksort, Ordenamiento rpido


Como implica el nombre el ordenamiento rpido es el programa de ordenamiento
Ms rpido conocido en prctica. Su tiempo de ejecucin promedio es O (nlogn). Tiene
un peor caso de O(n2) pero este caso es muy poco probable.

El algoritmo de ordenamiento rpido es simple de entender y probar correcto.


El algoritmo bsico consiste de los siguientes pasos:
1. Si el nmero de elementos es 0 o 1 est ordenado.
2. Elija un elemento cualquiera en la entrada, este elemento es llamado pivote.
3. Particionar el conjunto sin el pivote en dos conjuntos disjuntos: los menores o
iguales a l y los mayores o iguales a el.
4. devolver la ordenacin del primero de los conjuntos seguido del pivote seguido de la
ordenacin del segundo de los conjuntos. sort rpido(i,j) ordena desde A[i] hasta A[j]
en su lugar.
Comenzamos definiendo una funcin hallo pivote. Si hallo pivote no encuentra dos
valores distintos retorna 0, sino retorna el ndice del mayor de los primeros dos
elementos distintos. La funcin es como sigue:
int hallo pivote(int A [],int i,int j)
{
int clave1,k;
clave1=A[i];
for (k=i+1;k<=j;k++)
if (A[k]>clave1) return k;
else if (A[k]<clave1) return i;
return 0;}
A continuacin consideremos el problema de ordenar de A[i] a A[j] en su lugar de modo
que las claves menores que el pivote aparezcan a la izquierda que las otras. Para
hacer esto introducimos dos cursores izq y der inicialmente indicando los extremos
izquierdos y derechos de la porcin de A que estamos ordenando respectivamente. En
todo momento los elementos a la izquierda de izq esto es A[i], . . . , A[izq 1] tendrn
claves menores que el pivote y todos los elementos a la derecha de der, esto es A[der
+ 1], . . . , A[j] tendrn claves iguales o mayores que el pivote.
Inicialmente i = izq y j = der de forma que las sentencias anteriores se cumplen pues
no hay nada a la izquierda de izq ni a la derecha de der. Aplicamos repetidamente los
siguientes pasos que mueven izq a la derecha y der a la izquierda hasta que se cruzan
despues de lo cual A[i], . . . , A[izq 1] va a contener todas las claves menores que el
pivote y A[der + 1], . . . , A[j] todas las claves mayores que el pivote:
1. Bsqueda: mover izq a la derecha mientras A[izq] sea menor que el pivote.
Mover der a la izquierda mientras A[der] sea mayor o igual al pivote.

2. Testeo: si izq > der (que significa izq = der + 1) hemos particionado exitosamente la
entrada.
3. Cambio: si izq < der intercambiar A[izq] con A[der]. Luego de hacer esto A[izq] tiene
una clave menor que el pivote y A[der] tiene una clave al menos igual al pivote de
modo que sabemos que en la siguiente bsqueda izq se va a mover al menos una
posicin a la derecha y der se va a mover al menos una posicin a la izquierda.
int particion (int A[],int i,int j,int pivote)
{
int izq,der;
izq=i;
der=j;
do
{
intercambio(A,izq,der);
while(A[izq] < pivote) izq++;
while(A[der] >= pivote) der- -;
}
while (izq <= der);
return izq;
}
El intercambio inicial no interesa ya que no asumimos ningn orden en la entrada al
comienzo del programa.
El programa final es el siguiente:
Void sort rapido (int A[], int i, int j)
{
int pivote,indice,k;
indice=hallo pivote(A,i,j);
if (indice! =0)
{
pivote=A[indice];
k=particion(A,i,j,pivote);

sort rapido(A,i,k-1);
sort rapido(A,k,j);
}
}

1.2.1. Anlisis del ordenamiento rpido


Tiempo de particion:
A cada elemento asociamos un tiempo que veremos es constante. Luego el tiempo no
es mayor que esa constante por el nmero de tems.
En particin los tems son los elementos de A[i] a A[j]. La constante es el tiempo desde
que izq o der apunta por primera vez al elemento hasta que deja el elemento. Hay que
notar que una vez que se deja un elemento no se vuelve a l. Dejamos un elemento ya
sea aumentando izq o dismuyendo der. Cunto tiempo puede pasar hasta que
ejecutamos estas sentencias? en el peor caso ejecutamos: la inicializacin de izq y
der, un intercambio, podemos testear los loops sin modificar izq ni der, en una segunda
pasada se ejecuta el intercambio lo que nos asegura que los loops interiores van a
modificar izq y der. Esto es un tiempo constante independiente de i y j.

Tiempo de quicksort:
El tiempo de hallo pivote es O(j i+ 1) y en muchos casos ms pequeo. La llamada a
particin lleva tiempo O(ji+1), entonces el tiempo de cada llamada individual a
quicksort tiene tiempo proporcional al nmero de elementos.
Dicho de otra forma, el tiempo total que toma quicksort es la suma sobre todos los
elementos de la cantidad de veces que el elemento es parte de un sub-array para el
cual una llamada recursiva se realizo.
En el peor caso, el pivote coincide con el elemento mayor del array, esto divide el array
en uno de n-1 elementos y el otro de 1. El elemento ri forma parte de n i + 1
llamadas luego el tiempo est dado por:
n i=1 (n i + 1) = n i=1n n i=1i + n i=11 = n 2 n(n + 1)/2 + n =
2n 2/2 n 2/2 n/2 + n = n 2/2 + n/2

Luego en el peor caso quicksort toma un tiempo proporcional a n^2.


(ambos O(n^2) y (n^2)).
El tiempo promedio de quicksort es O(nlog2n).

2. Algoritmos de Bsqueda.
2.1. Bsqueda lineal recursiva.

La bsqueda lineal compara los elementos del array con la clave de bsqueda hasta
que encuentra el elemento o bien hasta que se determina que no se encuentra.
int busqueda lineal (int A[], int clave, int n, int i)
{
if (i==n+1) return -1;
elseif (A[i]==clave) return i;
else return busqueda lineal(A,clave,n,i+1);
return -1;
}
La funcin se invoca inicialmente con: bsqueda lineal(A, n, 1).

2.1.1. Anlisis del algoritmo de bsqueda lineal


En el peor caso el elemento se encuentra en la ltima posicin o no se
encuentra.
Esto da la siguiente recurrencia: (T(j) corresponde a cuando el elemento est
en la posicin j)
T(1) = 1
T(2) = T(1) + 1
.
.
.
T(n-1) = T(n-2) + 1
T(n) = T(n-1) + 1
Luego
T(n) = T(n-1) + 1 = T(n-2) + 2 = . . . = T(1) + (n-1) = n
Luego la bsqueda lineal es O(n) y (n).
2.2. Bsqueda binaria.
Dados un entero X y un array A de n enteros que se encuentran ordenados y
en memoria, encontrar un i talque A[i] == X o retornar 0 si X no se encuentra en
el array (consideramos los elementos del array de 1 a N.
La estrategia es la misma que en el caso iterativo.

Para simplificar el codigo definimos A[0]=X.


int busqueda binaria(int A[],int X, int i, int j)
{
int medio;
if (i>j) return 0;
medio = (i+j) / 2;
if (A[medio] < X) return busqueda binaria(A,X,medio+1,j)
else if (A[medio] > X) return busqueda binaria(A,X,i,medio-1)
else return medio;
}
2.2.1. Anlisis del algoritmo de bsqueda binaria.
El tiempo del programa sin contar las llamadas recursivas es constante. Si
planteamos una recurrencia para calcular el tiempo es:
T(n) = T(n/2) + 1
T(n/2) = T(n/4) + 1
.
.
.
T(2) = T(1) + 1
T(1) = 1
T(0) = 1
O sea la misma que en el caso iterativo. Luego el tiempo es O(log2n).

Вам также может понравиться