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

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.
3. Un ejemplo
^
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?
4. Optimizando.

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.
5. Análisis del algoritmo.
  • 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.







Bases para llegar a ser un programador

****Tablas de multiplicar****


Programa para calcular los números pares e impares usando *DO WHILE*


Programa para calcular los números pares e impares usando *WHILE*