viernes, 24 de septiembre de 2010
sábado, 11 de septiembre de 2010
jueves, 9 de septiembre de 2010
domingo, 5 de septiembre de 2010
METODOS DE ORDENAMIENTO
ENTRADAS DE ORDENAMIENTO
1. Ordenamiento de burbuja: Funciona revisando cada elemento de la lista que va a ser ordenada con el siguiente, intercambiándolos de posición si están en el orden equivocado. Es necesario revisar varias veces toda la lista hasta que no se necesiten más intercambios, lo cual significa que la lista está ordenada. Este algoritmo obtiene su nombre de la forma con la que suben por la lista los elementos durante los intercambios, como si fueran pequeñas "burbujas". También es conocido como el método del intercambio directo. Dado que solo usa comparaciones para operar elementos, se lo considera un algoritmo de comparación, siendo el más sencillo de implementar.
EJEMPLO:
//Ordenamiento por Burbuja
// by ramses2999
public static int[] OrdenarBurbuja(int[] n){
int temp;
int t = n.length;
for (int i = 1; i < t; i++) {
for (int k = t- 1; k >= i; k--) {
if(n[k] < n[k-1]){
temp = n[k];
n[k] = n[k-1];
n[k-1]= temp;
}//fin if
}// fin 2 for
}//fin 1 for
return n;
}//fin
2
3. El ordenamiento Shell (Shell sort en inglés) es un algoritmo de ordenamiento. El método se denomina Shell en honor de su inventor Donald Shell. Su implementación original, requiere O(n2) comparaciones e intercambios en el peor caso. Un cambio menor presentado en el libro de V. Pratt produce una implementación con un rendimiento de O(nlog2 n) en el peor caso. Esto es mejor que las O(n2) comparaciones requeridas por algoritmos simples pero peor que el óptimo O(n log n). Aunque es fácil desarrollar un sentido intuitivo de cómo funciona este algoritmo, es muy difícil analizar su tiempo de ejecución.
El Shell sort es una generalización del ordenamiento por inserción, teniendo en cuenta dos observaciones: El ordenamiento por inserción es eficiente si la entrada está "casi ordenada".
El ordenamiento por inserción es ineficiente, en general, porque mueve los valores sólo una posición cada vez.
public static void shellSort(int[] a) {
for ( int increment = a.length / 2;
increment > 0;
increment = (increment == 2 ? 1 : (int) Math.round(increment / 2.2))) {
for (int i = increment; i < a.length; i++) {
for (int j = i; j >= increment && a[j - increment] > a[j]; j -= increment) {
int temp = a[j];
a[j] = a[j - increment];
a[j - increment] = temp;
}
}
}
}
4. El algoritmo de ordenamiento por mezcla (merge sort en inglés) es un algoritmo de ordenamiento externo estable basado en la técnica divide y vencerás. Es de complejidad O(n log n).
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 tamaño.
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 ejecución:
1. Una lista pequeña necesitará menos pasos para ordenarse que una lista grande.
2. Se necesitan menos pasos para construir una lista ordenada a partir de dos listas también ordenadas, que a partir de dos listas desordenadas. Por ejemplo, sólo será necesario entrelazar cada lista una vez que están ordenadas.
public class MergeSort{
private int A[];
public int[] OrdenaMerge(int[] L) {
int n = L.length;
if (n > 1){
int m = (int) (Math.ceil(n/2.0));
int [] L1 = new int[m];
int [] L2 = new int[n-m];
for (int i = 0; i < m; i++){
L1[i] = L[i];
}
for (int i = m; i < n; i++){
L2[i-m] = L[i];
}
L = merge(OrdenaMerge(L1), OrdenaMerge(L2));
}
return L;
}
public int[] eliminar(int [] l){
int [] L = new int[l.length-1];
for(int i = 1; i < l.length; i++){
L[i-1] = l[i];
}
return L;
}
public int[] merge(int[] L1, int[] L2) {
int[] L = new int[L1.length+L2.length];
int i = 0;
while ((L1.length != 0) && (L2.length != 0)) {
if (L1[0] < L2[0]){
L[i++] = L1[0];
L1 = eliminar(L1);
if (L1.length == 0){
while (L2.length != 0) {
L[i++] = L2[0];
L2 = eliminar(L2);
}
}
}
else{
L[i++] = L2[0];
L2 = eliminar(L2);
if (L2.length == 0) {
while (L1.length != 0) {
L[i++] = L1[0];
L1 = eliminar(L1);
}
}
}
}
return L;
}
public void generarNumeros(){
Random ran = new Random();
int x;
for(int i = 0; i < A.length; i++){
x = (int)(ran.nextDouble()*10000);
A[i] = x;
}
}
public void imprimir(){
for(int i = 0; i < A.length; i++){
System.out.println(A[i]);
}
}
public int[] getA(){
return A;
}
public void setA(int []A){
this.A = A;
}
}
1. Ordenamiento de burbuja: Funciona revisando cada elemento de la lista que va a ser ordenada con el siguiente, intercambiándolos de posición si están en el orden equivocado. Es necesario revisar varias veces toda la lista hasta que no se necesiten más intercambios, lo cual significa que la lista está ordenada. Este algoritmo obtiene su nombre de la forma con la que suben por la lista los elementos durante los intercambios, como si fueran pequeñas "burbujas". También es conocido como el método del intercambio directo. Dado que solo usa comparaciones para operar elementos, se lo considera un algoritmo de comparación, siendo el más sencillo de implementar.
EJEMPLO:
//Ordenamiento por Burbuja
// by ramses2999
public static int[] OrdenarBurbuja(int[] n){
int temp;
int t = n.length;
for (int i = 1; i < t; i++) {
for (int k = t- 1; k >= i; k--) {
if(n[k] < n[k-1]){
temp = n[k];
n[k] = n[k-1];
n[k-1]= temp;
}//fin if
}// fin 2 for
}//fin 1 for
return n;
}//fin
2
Quicksort
Tabla de variables | ||
Nombre | Tipo | Uso |
lista | Cualquiera | Lista a ordenar |
inf | Entero | Elemento inferior de la lista |
sup | Entero | Elemento superior de la lista |
elem_div | El mismo que los elementos de la lista | El elemento divisor |
temp | El mismo que los elementos de la lista | Para realizar los intercambios |
i | Entero | Contador por la izquierda |
j | Entero | Contador por la derecha |
cont | Entero | El ciclo continua mientras cont tenga el valor 1 |
Nombre Procedimiento: OrdRap
Parámetros:
lista a ordenar (lista)
índice inferior (inf)
índice superior (sup)
// Inicialización de variables
1. elem_div = lista[sup];
2. i = inf - 1;
3. j = sup;
4. cont = 1;
// Verificamos que no se crucen los límites
5. if (inf >= sup)
6. retornar;
// Clasificamos la sublista
7. while (cont)
8. while (lista[++i] < elem_div);
9. while (lista[--j] > elem_div);
10. if (i < j)
11. temp = lista[i];
12. lista[i] = lista[j];
13. lista[j] = temp;
14. else
15. cont = 0;
// Copiamos el elemento de división
// en su posición final
16. temp = lista[i];
17. lista[i] = lista[sup];
18. lista[sup] = temp;
// Aplicamos el procedimiento
// recursivamente a cada sublista
19. OrdRap (lista, inf, i - 1);
20. OrdRap (lista, i + 1, sup);
Nota:
- La primera llamada debería ser con la lista, cero (0) y el tamaño de la lista menos 1 como parámetros.
Esta vez voy a cambiar de lista ;-D
5 - 3 - 7 - 6 - 2 - 1 - 4
Comenzamos con la lista completa. El elemento divisor será el 4:
5 - 3 - 7 - 6 - 2 - 1 - 4
Comparamos con el 5 por la izquierda y el 1 por la derecha.
5 - 3 - 7 - 6 - 2 - 1 - 4
5 es mayor que cuatro y 1 es menor. Intercambiamos:
1 - 3 - 7 - 6 - 2 - 5 - 4
Avanzamos por la izquierda y la derecha:
1 - 3 - 7 - 6 - 2 - 5 - 4
3 es menor que 4: avanzamos por la izquierda. 2 es menor que 4: nos mantenemos ahí.
1 - 3 - 7 - 6 - 2 - 5 - 4
7 es mayor que 4 y 2 es menor: intercambiamos.
1 - 3 - 2 - 6 - 7 - 5 - 4
Avanzamos por ambos lados:
1 - 3 - 2 - 6 - 7 - 5 - 4
En este momento termina el ciclo principal, porque los índices se cruzaron. Ahora intercambiamos lista[i] con lista[sup] (pasos 16-18):
1 - 3 - 2 - 4 - 7 - 5 - 6
Aplicamos recursivamente a la sublista de la izquierda (índices 0 - 2). Tenemos lo siguiente:
1 - 3 - 2
1 es menor que 2: avanzamos por la izquierda. 3 es mayor: avanzamos por la derecha. Como se intercambiaron los índices termina el ciclo. Se intercambia lista[i] con lista[sup]:
1 - 2 - 3
Al llamar recursivamente para cada nueva sublista (lista[0]-lista[0] y lista[2]-lista[2]) se retorna sin hacer cambios (condición 5.).Para resumir te muestro cómo va quedando la lista:
Segunda sublista: lista[4]-lista[6]
7 - 5 - 6
5 - 7 - 6
5 - 6 - 7
Para cada nueva sublista se retorna sin hacer cambios (se cruzan los índices).
Finalmente, al retornar de la primera llamada se tiene el arreglo ordenado:
1 - 2 - 3 - 4 - 5 - 6 - 7
Eso es todo. Bastante largo ¿verdad?
Sólo voy a mencionar algunas optimizaciones que pueden mejorar bastante el rendimiento de quicksort:
- Hacer una versión iterativa: Para ello se utiliza una pila en que se van guardando los límites superior e inferior de cada sublista.
- No clasificar todas las sublistas: Cuando el largo de las sublistas va disminuyendo, el proceso se va encareciendo. Para solucionarlo sólo se clasifican las listas que tengan un largo menor que n. Al terminar la clasificación se llama a otro algoritmo de ordenamiento que termine la labor. El indicado es uno que se comporte bien con listas casi ordenadas, como el ordenamiento por inserción por ejemplo. La elección de n depende de varios factores, pero un valor entre 10 y 25 es adecuado.
- Elección del elemento de división: Se elige desde un conjunto de tres elementos: lista[inferior], lista[mitad] y lista[superior]. El elemento elegido es el que tenga el valor medio según el criterio de comparación. Esto evita el comportamiento degenerado cuando la lista está prácticamente ordenada.
- Estabilidad: No es estable.
- Requerimientos de Memoria: No requiere memoria adicional en su forma recursiva. En su forma iterativa la necesita para la pila.
- Tiempo de Ejecución:
- Caso promedio. La complejidad para dividir una lista de n es O(n). Cada sublista genera en promedio dos sublistas más de largo n/2. Por lo tanto la complejidad se define en forma recurrente como:
f(1) = 1
f(n) = n + 2 f(n/2)
La forma cerrada de esta expresión es:
f(n) = n log2n
Es decir, la complejidad es O(n log2n).
- El peor caso ocurre cuando la lista ya está ordenada, porque cada llamada genera sólo una sublista (todos los elementos son menores que el elemento de división). En este caso el rendimiento se degrada a O(n2). Con las optimizaciones mencionadas arriba puede evitarse este comportamiento.
Ventajas:
- Muy rápido
- No requiere memoria adicional.
Desventajas:
- Implementación un poco más complicada.
- Recursividad (utiliza muchos recursos).
- Mucha diferencia entre el peor y el mejor caso.
La mayoría de los problemas de rendimiento se pueden solucionar con las optimizaciones mencionadas arriba (al costo de complicar mucho más la implementación). Este es un algoritmo que puedes utilizar en la vida real. Es muy eficiente. En general será la mejor opción. Intenta programarlo. Mira el código si tienes dudas.
3. El ordenamiento Shell (Shell sort en inglés) es un algoritmo de ordenamiento. El método se denomina Shell en honor de su inventor Donald Shell. Su implementación original, requiere O(n2) comparaciones e intercambios en el peor caso. Un cambio menor presentado en el libro de V. Pratt produce una implementación con un rendimiento de O(nlog2 n) en el peor caso. Esto es mejor que las O(n2) comparaciones requeridas por algoritmos simples pero peor que el óptimo O(n log n). Aunque es fácil desarrollar un sentido intuitivo de cómo funciona este algoritmo, es muy difícil analizar su tiempo de ejecución.
El Shell sort es una generalización del ordenamiento por inserción, teniendo en cuenta dos observaciones: El ordenamiento por inserción es eficiente si la entrada está "casi ordenada".
El ordenamiento por inserción es ineficiente, en general, porque mueve los valores sólo una posición cada vez.
public static void shellSort(int[] a) {
for ( int increment = a.length / 2;
increment > 0;
increment = (increment == 2 ? 1 : (int) Math.round(increment / 2.2))) {
for (int i = increment; i < a.length; i++) {
for (int j = i; j >= increment && a[j - increment] > a[j]; j -= increment) {
int temp = a[j];
a[j] = a[j - increment];
a[j - increment] = temp;
}
}
}
}
4. El algoritmo de ordenamiento por mezcla (merge sort en inglés) es un algoritmo de ordenamiento externo estable basado en la técnica divide y vencerás. Es de complejidad O(n log n).
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 tamaño.
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 ejecución:
1. Una lista pequeña necesitará menos pasos para ordenarse que una lista grande.
2. Se necesitan menos pasos para construir una lista ordenada a partir de dos listas también ordenadas, que a partir de dos listas desordenadas. Por ejemplo, sólo será necesario entrelazar cada lista una vez que están ordenadas.
public class MergeSort{
private int A[];
public int[] OrdenaMerge(int[] L) {
int n = L.length;
if (n > 1){
int m = (int) (Math.ceil(n/2.0));
int [] L1 = new int[m];
int [] L2 = new int[n-m];
for (int i = 0; i < m; i++){
L1[i] = L[i];
}
for (int i = m; i < n; i++){
L2[i-m] = L[i];
}
L = merge(OrdenaMerge(L1), OrdenaMerge(L2));
}
return L;
}
public int[] eliminar(int [] l){
int [] L = new int[l.length-1];
for(int i = 1; i < l.length; i++){
L[i-1] = l[i];
}
return L;
}
public int[] merge(int[] L1, int[] L2) {
int[] L = new int[L1.length+L2.length];
int i = 0;
while ((L1.length != 0) && (L2.length != 0)) {
if (L1[0] < L2[0]){
L[i++] = L1[0];
L1 = eliminar(L1);
if (L1.length == 0){
while (L2.length != 0) {
L[i++] = L2[0];
L2 = eliminar(L2);
}
}
}
else{
L[i++] = L2[0];
L2 = eliminar(L2);
if (L2.length == 0) {
while (L1.length != 0) {
L[i++] = L1[0];
L1 = eliminar(L1);
}
}
}
}
return L;
}
public void generarNumeros(){
Random ran = new Random();
int x;
for(int i = 0; i < A.length; i++){
x = (int)(ran.nextDouble()*10000);
A[i] = x;
}
}
public void imprimir(){
for(int i = 0; i < A.length; i++){
System.out.println(A[i]);
}
}
public int[] getA(){
return A;
}
public void setA(int []A){
this.A = A;
}
}
viernes, 3 de septiembre de 2010
BUSQUEDA
La búsqueda consiste acceder a la raíz del árbol, si el elemento a localizar coincide con éste la búsqueda ha concluido con éxito, si el elemento es menor se busca en el subárbol izquierdo y si es mayor en el derecho. Si se alcanza un nodo hoja y el elemento no ha sido encontrado se supone que no existe en el árbol. Cabe destacar que la búsqueda en este tipo de árboles es muy eficiente, representa una función logarítmica. El maximo número de comparaciones que necesitaríamos para saber si un elemento se encuentra en un árbol binario de búsqueda estaría entre [log2(N+1)] y N, siendo N el número de nodos. La búsqueda de un elemento en un ABB (Árbol Binario de Búsqueda) se puede realizar de dos formas, iterativa o recursiva.
METODOS DE BUSQUEDA.
• Búsqueda secuencial: Este método sirve para cualquier tipo de array. Consiste en ir recorriendo el contenido del array hasta que se encuentre el dato buscado o se llegue al final. Este método no es muy efectivo, puesto que al enfrentarse a un alto numero de información, si el dato buscado no se encuentra al principio, resulta muy lento.
Ej:
PROGRAM Secuencial;
CONST
Max= 20;
TYPE
Rango= 1..max;
Vector= ARRAY [Rango] of integer;
VAR
V: vector;
Num: Integer;
Pos, cont: Rango;
BEGIN
Pos:=0;
Cont:=pos;
Repeat
Cont:=Cont+1;
If v[cont]=num then
Pos:=cont;
Until (cont=max) OR (pos<>0);
END.
• Búsqueda binária: Este método de búsqueda solo puede utilizarse con un array ordenado. Es más eficaz que la búsqueda secuencial. Consiste en un procedimiento recursivo que compara el elemento buscado con el elemento que ocupe la posición media de un rango comprendido entre el principio y el final de la estructura. Si el elemento buscado es mayor que el comparado se redefinirá el rango entre el elemento que ocupa la posición media y el elemento que ocupa el final del rango, sí no, hace lo mismo pero entre la mitad del rango y el principio. Y así hasta dar con el dato buscado o no encontrarlo.
Ej:
PROCEDURE Binaria (Ini, fin, num: Integer; V:Vector; Var pos:Integer);
Var
Med, Rango: Integer;
Begin
Rango:= (Fin-Ini)+1;
Med:=Rango DIV 2;
Med:=Ini+Med;
IF Rango > 1 Then
If V[Med]= num then
Pos:= med
Else
If num> V[Med] then
Binaria (med+1, fin, num, v, pos)
Else
Binaria (Ini, med-1, num, v, pos)
Else
IF num=V[med] then
Pos:=med
Else
Pos:=0;
End;
METODOS DE ORDENACIÓN.
• Método de la burbuja: Consiste en recorrer el array buscando el nº mayor y colocándolo en la última posición. Después la variable que indica la última posición del array decrementaría una posición y es en esta donde colocaríamos el siguiente nº que se considere mayor.
7
8
2
5
Mayor = 8
7
2
5
8
Mayor = 7
2
5
7
8
Ej:
PROCEDURE Burbuja (n:Integer; Var a: Datos);
Var
Aux, i, k:Integer;
Begin
For k:=1 to n-1 do
Begin
i:=1;
Repeat
If a > a then
Begin
Aux:= a;
A:=a;
A:=aux;
End;
I:= i+1;
Until i > n-k;
End;
End;
Una mejora sobre el algoritmo es hacer que salga del bule si no se ha hecho ninguna modificación al recorrer el array.
miércoles, 1 de septiembre de 2010
Suscribirse a:
Entradas (Atom)