viernes, 13 de febrero de 2009

Avances Tecnologicos dentro de 5 a;os

los principales avances tecnologicos son:

Se accederá a los servicios de salud de manera remota. Millones de personas con problemas crónicos de salud, como diabetes, corazón, riñón, problemas circulatorios, serán capaces de tener sus situaciones automáticamente monitoreadas mientras cuidan de su vida diariamente. Fabricantes de dispositivos y profesionales de servicios de salud tendrán un abordaje proactivo continuado en el monitoreo remoto de pacientes, hecho a través de sensores en la casa, utilizados en la ropa de las personas o en dispositivos y paquetes.

Avances en hardware y software en el campo de servicios de salud de control remoto, serán la mayor fuente de consumidores y de innovación corporativa hasta 2012.
Los Teléfonos móviles empezarán a leer nuestras mentes. La tecnología de “presencia” avanzada irá a conceder a los teléfonos móviles y PDAs la habilidad de aprender automáticamente sobre el ambiente y preferencias de sus usuarios al desplazarse, sea por trabajo o en viajes.

La tecnología de “presencia”, usada en mensajes instantáneos, ya posibilita identificar y localizar un usuario en cuanto el mismo se conecta a la red. En cinco años, la nueva infraestructura caracterizará fuertes capacidades de aprendizaje de máquinas y reconocimiento de patrones. Las nuevas redes permitirán que dispositivos aprendan a predecir las preferencias del usuario y a tornar disponible servicios a través de todas las bandas del espectro wireless de 3G y GSM hasta RFID y Wifi.

Las nuevas tecnologías que abordarán problemas relacionados al medio ambiente. Gobiernos y compañías buscan cada vez más encontrar formas de trabajo amigables con el medio ambiente, trabajando para asegurar la continuidad de recursos como agua y energía. La nanotecnología -habilidad de manejar átomos y moléculas individuales para formar nuevas estructuras minúsculas- finalmente tuvo un gran impacto en micro chips, haciendo que productos como ordenadores, teléfonos móviles y PDAs sean menores, mejores y más baratos.

En los próximos años, la nanotecnología generará formas totalmente nuevas de memorias, haciendo los sistemas aún mejores al permitir que almacenen una cantidad muy grande de información y suministrando capacidad de “conectar instantáneamente”. Pero el uso de la nanotecnología también se expandirá hacia otras aplicaciones más allá de las electrónicas. Una posibilidad fascinante es el uso de las nano partículas para la filtración del agua. Esto podría promover la ecología y la conservación, ayudando a tratar de la falta, mundialmente creciente, de provisiones de agua potable. Grandes soluciones que llegarán en paquetes muy pequeños.
La traducción de voz en tiempo real se volverá la norma. El movimiento hacia la globalización nos obligue a retomar aspectos básicos de la humanidad como diferencias de lenguaje. Por ejemplo las innovaciones de reconocimiento de voz de IBM permiten a los medios monitorear en inglés transmisiones de noticias en Chino o Árabe a través de la Web; permiten a viajeros con PDAs traducir sus menús del japonés y a los doctores que hablan inglés comunicarse con sus pacientes en español.

Las tecnologías de traducción en tiempo real estarán presentes en los teléfonos móviles, los coches, etc. Estas tecnologías estarán presentes en cada parte de los negocios y la sociedad, eliminando las barreras del lenguaje en la economía global y facilitando la interacción social.
Existirá como cotidiana, la Internet 3D. Los populares mundos en línea, tales como Second Life y World of Warcraft, involucrarán a la Internet 3D. En ese mundo en línea, se caminará por pasillos de supermercados, librerías y tiendas de DVDs, donde encontrará especialistas que usted raramente encontraría en su tienda. La Internet 3D posibilitará nuevas formas de e-learning, medicina a distancia y experiencias de consumidores interactivas, transformando la forma como interactuamos con nuestros amigos y familiares, así como negocios gubernamentales e instituciones de servicios de salud.

Tragame Tierra

Bueno aqui les dejo las verguenzas mas grandes que les han sucedidos a las chicas

Posada prendida

Organicé una posada en mi casa e invité a mis amigos. Le pedí a mi papá que encendiera las luces del adornado de la casa antes de que llegaran mis invitados, pero él me dijo que hasta que estuvieran todos lo prendería; quería presumir lo bien que habían quedado. Entonces, cuando mis friends y yo estábamos en el patio, mi papá se subió a la azotea para prender el switch de la luz. De pronto, se cayó una guía de luces que no sujetó bien, mi papá se espantó muchísimo porque pensó que se electrocutaría y brincó desde las alturas al patio para caer encima de mis invitados. Todos tuvimos que agarrarlo y terminamos tirados en el piso. Mi papá no bajó en toda la noche a la fiesta.

Anónima, México DF.


Loca de remate

Estaba en la escuela con mis amigas y todos los maestros tenían una junta, así que nos alargaron la hora del recreo. Como los profesores ya se habían tardado demasiado fuimos a buscarlos para ver dónde estaban, pero no los encontrábamos. Supusimos que estaban en el otro patio. Entonces, mientras caminábamos por los pasillos de la escuela, una de mis amigas me contó un chisme y yo empecé a gritar: "Me voy a suicidar, me voy a suicidar" (obvio, de broma) Cuando dije esas palabras se hizo un silencio enorme y, por curiosidad, volteé hacia mi izquierda y vi a todos los maestros en un salón y se me quedaron viendo como loca. Por supuesto, me fui corriendo queriendo que me tragara la tierra.

Pinkgirlpretty.


Amiga peligrosa

Estaba sentada en mi banca tomando clases. Ya que habíamos acabado el trabajo que nos puso el profesor, mi amiga y yo empezamos a jugar; ella empezó a aventarme y yo, como no soy nada dejada, la aventé y casi se cae. De repente, me distraje y cuando menos lo esperaba ella me empujó y me caí de la silla. Todos mis amigos y amigas se soltaron a reír.

Karen Marlen.

Espaldas planas

Fui a clases de basquetbol y estábamos haciendo ejercicios de ochos y me lanzaron la pelota y se me fue más atrás de donde estaba parada y, por tratar de agarrarla, me caí de espaldas al piso. Me vieron algunas amigas y ahora ellas saben que no soy buena en ese deporte. ¡Trágame canasta!

Prizi.


Chica Transparente

Estaba en la fiesta de fin de año de mi escuela y de lejos vi al chico más guapo de mi escuela y me fui a bailar con él; me sentía en las nubes. De repente sentí un movimiento raro en mi espalda y es que ¡mi bra se había desabrochado! Lo peor es que traía una blusa blanca y medio transparente. Me tapé y me fui corriendo al baño para arreglar el problema. Cuando regresé el niño me dijo…”¿qué le pasó a tu brasiere? ¡Quería que me tragara la tierra!
La del bra, Guadalajara, México.

Chisme caliente
Mis amigas y yo estamos en el taller de teatro. Un día, después de los ensayos de la obra que vamos a presentar a finales de año (Vaselina) nos quedamos en los camerinos hablando de los chavos más bombones de la clase. Yo dije: “Ay, a Sebastián si me lo comía a besos”. De pronto, escuchamos voces afuera del cuarto y cuando abrimos la puerta nos dimos cuenta que todos los niños de los que estábamos hablando estaban ahí, espiándonos.
Anita, Edo. de México.

Como manzana
Un día mi BFF y yo estábamos en el parque y en eso pasó el chavo de mis sueños, pero para que él me viera me subí a un árbol pero estaba haciendo mucho viento y me caí del árbol. En ese momento pensé…”trágame tierra”
Franciny, Costa Rica.

Declaración con testigos
Un día me decidí a decirle a mi amigo que me gustaba y se lo dije delante de una persona, pero para mi desgracia…resultó ser su novia. Yo, totalmente avergonzada, caminé hacia atrás y me desplomé. Fue el oso más grande de mi vida ya que nunca me le había declarado a alguien.
La desafortunada, Panamá.



Algoritmos y Pseudocodigos



1 Ordenamiento Burbuja (Bubblesort)

1. Descripción.

Este es el algoritmo más sencillo probablemente. Ideal para empezar. Consiste en ciclar repetidamente a través de la lista, comparando elementos adyacentes de dos en dos. Si un elemento es mayor que el que está en la siguiente posición se intercambian. ¿Sencillo no?

2. Pseudocódigo en C.

Para realizar los intercambios
1. for (i=1; i2. for j=0 ; j3. if (lista[j] > lista[j+1])
4. temp = lista[j];
5. lista[j] = lista[j+1];
6. lista[j+1] = temp;

3. Un ejemplo

Vamos a ver un ejemplo. Esta es nuestra lista:

4 - 3 - 5 - 2 - 1

Tenemos 5 elementos. Es decir, TAM toma el valor 5. Comenzamos comparando el primero con el segundo elemento. 4 es mayor que 3, así que intercambiamos. Ahora tenemos:

3 - 4 - 5 - 2 - 1

Ahora comparamos el segundo con el tercero: 4 es menor que 5, así que no hacemos nada. Continuamos con el tercero y el cuarto: 5 es mayor que 2. Intercambiamos y obtenemos:

3 - 4 - 2 - 5 - 1

Comparamos el cuarto y el quinto: 5 es mayor que 1. Intercambiamos nuevamente:

3 - 4 - 2 - 1 - 5

Repitiendo este proceso vamos obteniendo los siguientes resultados:

3 - 2 - 1 - 4 - 5
2 - 1 - 3 - 4 - 5
1 - 2 - 3 - 4 - 5

4. Optimizando.

Se pueden realizar algunos cambios en este algoritmo que pueden mejorar su rendimiento.
Si observas bien, te darás cuenta que en cada pasada a través de la lista un elemento va quedando en su posición final. Si no te queda claro mira el ejemplo de arriba. En la primera pasada el 5 (elemento mayor) quedó en la última posición, en la segunda el 4 (el segundo mayor elemento) quedó en la penúltima posición. Podemos evitar hacer comparaciones innecesarias si disminuimos el número de éstas en cada pasada. Tan sólo hay que cambiar el ciclo interno de esta manera:

for (j=0; jPuede ser que los datos queden ordenados antes de completar el ciclo externo. Podemos modificar el algoritmo para que verifique si se han realizado intercambios. Si no se han hecho entonces terminamos con la ejecución, pues eso significa que los datos ya están ordenados. Te dejo como tarea que modifiques el algoritmo para hacer esto :-).
Otra forma es ir guardando la última posición en que se hizo un intercambio, y en la siguiente pasada sólo comparar hasta antes de esa posición.

5. Análisis del algoritmo.

Éste es el análisis para la versión no optimizada del algoritmo:

Estabilidad: Este algoritmo nunca intercambia registros con claves iguales. Por lo tanto es estable.

Requerimientos de Memoria: Este algoritmo sólo requiere de una variable adicional para realizar los intercambios.

Tiempo de Ejecución: El ciclo interno se ejecuta n veces para una lista de n elementos. El ciclo externo también se ejecuta n veces. Es decir, la complejidad es n * n = O(n2). El comportamiento del caso promedio depende del orden de entrada de los datos, pero es sólo un poco mejor que el del peor caso, y sigue siendo O(n2).

Ventajas:
Fácil implementación.
No requiere memoria adicional.
Desventajas:
Muy lento.
Realiza numerosas comparaciones.
Realiza numerosos intercambios.
Este algoritmo es uno de los más pobres en rendimiento. Si miras la
demostración te darás cuenta de ello. No es recomendable usarlo. Tan sólo está aquí para que lo conozcas, y porque su sencillez lo hace bueno para empezar. Ya veremos otros mucho mejores. Ahora te recomiendo que hagas un programa y lo pruebes. Si tienes dudas mira el programa de ejemplo.
2 Ordenamiento por Selección.

1. Descripción.

Este algoritmo también es sencillo. Consiste en lo siguiente:

Buscas el elemento más pequeño de la lista.
Lo intercambias con el elemento ubicado en la primera posición de la lista.
Buscas el segundo elemento más pequeño de la lista.
Lo intercambias con el elemento que ocupa la segunda posición en la lista.
Repites este proceso hasta que hayas ordenado toda la lista.

2. Pseudocódigo en C.

El mismo que los elementos de la lista
Para realizar los intercambios
1. for (i=0; i2. pos_men = Menor(lista, TAM, i);
3. temp = lista[i];
4. lista[i] = lista [pos_men];
5. lista [pos_men] = temp;

Nota:
Menor(lista, TAM, i) es una función que busca el menor elemento entre las posiciones i y TAM-1. La búsqueda es lineal (elemento por elemento). No lo incluyo en el pseudocódigo porque es bastante simple.

3. Un ejemplo.

Vamos a ordenar la siguiente lista (la misma del ejemplo anterior :-) ):
4 - 3 - 5 - 2 - 1
Comenzamos buscando el elemento menor entre la primera y última posición. Es el 1. Lo intercambiamos con el 4 y la lista queda así:
1 - 3 - 5 - 2 - 4
Ahora buscamos el menor elemento entre la segunda y la última posición. Es el 2. Lo intercambiamos con el elemento en la segunda posición, es decir el 3. La lista queda así:
1 - 2 - 5 - 3 - 4
Buscamos el menor elemento entre la tercera posición (sí, adivinaste :-D) y la última. Es el 3, que intercambiamos con el 5:
1 - 2 - 3 - 5 - 4
El menor elemento entre la cuarta y quinta posición es el 4, que intercambiamos con el 5:
1 - 2 - 3 - 4 - 5
¡Y terminamos! Ya tenemos nuestra lista ordenada. ¿Fue fácil no?

4. Análisis del algoritmo.

Estabilidad: Aquí discrepo con un libro de la bibliografía que dice que no es estable. Yo lo veo así: si tengo dos registros con claves iguales, el que ocupe la posición más baja será el primero que sea identificado como menor. Es decir que será el primero en ser desplazado. El segundo registro será el menor en el siguiente ciclo y quedará en la posición adyacente. Por lo tanto se mantendrá el orden relativo. Lo que podría hacerlo inestable sería que el ciclo que busca el elemento menor revisara la lista desde la última posición hacia atrás. ¿Qué opinas tú? Yo digo que es estable, pero para hacerle caso al libro (el autor debe sabe más que yo ¿cierto?:-)) vamos a decir que no es estable.

Requerimientos de Memoria: Al igual que el ordenamiento burbuja, este algoritmo sólo necesita una variable adicional para realizar los intercambios.

Tiempo de Ejecución: El ciclo externo se ejecuta n veces para una lista de n elementos. Cada búsqueda requiere comparar todos los elementos no clasificados. Luego la complejidad es O(n2). Este algoritmo presenta un comportamiento constante independiente del orden de los datos. Luego la complejidad promedio es también O(n2).

Ventajas:
Fácil implementación.
No requiere memoria adicional.
Realiza pocos intercambios.
Rendimiento constante: poca diferencia entre el peor y el mejor caso.

Desventajas:
Lento.
Realiza numerosas comparaciones.
Este es un algoritmo lento. No obstante, ya que sólo realiza un intercambio en cada ejecución del ciclo externo, puede ser una buena opción para listas con
registros grandes y claves pequeñas. Si miras el programa de demostración notarás que es el más rápido en la parte gráfica (por lo menos en un PC lento y con una tarjeta gráfica mala como el mío x-). La razón es que es mucho más lento dibujar las barras que comparar sus largos (el desplazamiento es más costoso que la comparación), por lo que en este caso especial puede vencer a algoritmos como Quicksort.
Bien, ya terminamos con éste. Otra vez te recomiendo que hagas un programa y trates de implementar este algoritmo, de preferencia sin mirar el
código ni el pseudocódigo otra vez.
3 Ordenamiento por Inserción

1. Descripción.

Este algoritmo también es bastante sencillo. ¿Has jugado cartas?. ¿Cómo 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 (también me fijo en el color, pero omitiré esa parte para concentrarme en la idea principal). Después tomo la tercera y la comparo con las que tengo en la mano, desplazándola hasta que quede en su posición final. Continúo haciendo esto, insertando cada carta en la posición que le corresponde, hasta que las tengo todas en orden. ¿Lo haces así tu también? Bueno, pues si es así entonces comprenderás fácilmente 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 sería como la carta que tomamos) y desplazar todos los elementos mayores hacia la derecha. Luego copiamos el elemento guardado en la posición del último elemento que se desplazó.

2. Pseudocódigo en C.

El mismo que los elementos de la lista
Para realizar los intercambios
1. for (i=1; i2. 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;

Nota:
Observa que en cada iteración del ciclo externo los elementos 0 a i forman una lista ordenada.

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 posición a la derecha y después 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 posición a la derecha:
3 - 4 - 5 - 5 - 1
Comparamos con 4: es menor, así que desplazamos el 4 una posición a la derecha:
3 - 4 - 4 - 5 - 1
Comparamos con 3. Desplazamos el 3 una posición a la derecha:
3 - 3 - 4 - 5 - 1
Finalmente copiamos el 2 en su posición final:
2 - 3 - 4 - 5 - 1
El último elemento a ordenar es el 1. Cinco es menor que 1, así que lo desplazamos una posición 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
Espero que te haya quedado claro.

4. Análisis 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 Ejecución: Para una lista de n elementos el ciclo externo se ejecuta n-1 veces. El ciclo interno se ejecuta como máximo una vez en la primera iteración, 2 veces en la segunda, 3 veces en la tercera, etc. Esto produce una complejidad O(n2).

Ventajas:
Fácil implementación.
Requerimientos mínimos de memoria.
Desventajas:
Lento.
Realiza numerosas comparaciones.
Este también es un algoritmo lento, pero puede ser de utilidad para listas que están ordenadas o semiordenadas, porque en ese caso realiza muy pocos desplazamientos.
4 Ordenamiento Rápido (Quicksort)
1. Descripción.

Esta es probablemente la técnica más rápida conocida. Fue desarrollada por C.A.R. Hoare en 1960. El algoritmo original es recursivo, pero se utilizan versiones iterativas para mejorar su rendimiento (los algoritmos recursivos son en general más lentos que los iterativos, y consumen más recursos). El algoritmo fundamental es el siguiente:
Eliges un elemento de la lista. Puede ser cualquiera (en
Optimizando veremos una forma más efectiva). Lo llamaremos elemento de división.
Buscas la posición que le corresponde en la lista ordenada (explicado más abajo).
Acomodas los elementos de la lista a cada lado del elemento de división, de manera que a un lado queden todos los menores que él y al otro los mayores (explicado más abajo también). En este momento el elemento de división separa la lista en dos sublistas (de ahí su nombre).
Realizas esto de forma recursiva para cada sublista mientras éstas tengan un largo mayor que 1. Una vez terminado este proceso todos los elementos estarán ordenados.
Una idea preliminar para ubicar el elemento de división en su posición final sería contar la cantidad de elementos menores y colocarlo un lugar más arriba. Pero luego habría que mover todos estos elementos a la izquierda del elemento, para que se cumpla la condición y pueda aplicarse la recursividad. Reflexionando un poco más se obtiene un procedimiento mucho más efectivo. Se utilizan dos índices: i, al que llamaremos contador por la izquierda, y j, al que llamaremos contador por la derecha. El algoritmo es éste:
Recorres la lista simultáneamente con i y j: por la izquierda con i (desde el primer elemento), y por la derecha con j (desde el último elemento).
Cuando lista[i] sea mayor que el elemento de división y lista[j] sea menor los intercambias.
Repites esto hasta que se crucen los índices.
El punto en que se cruzan los índices es la posición adecuada para colocar el elemento de división, porque sabemos que a un lado los elementos son todos menores y al otro son todos mayores (o habrían sido intercambiados).
Al finalizar este procedimiento el elemento de división queda en una posición en que todos los elementos a su izquierda son menores que él, y los que están a su derecha son mayores.

2. Pseudocódigo en C.

// 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.

Algoritmos de Ordenamiento

1. Introducción.

El ordenamiento es una labor común que realizamos continuamente. ¿Pero te has preguntado qué es ordenar? ¿No? Es que es algo tan corriente en nuestras vidas que no nos detenemos a pensar en ello. Ordenar es simplemente colocar información de una manera especial basándonos en un criterio de ordenamiento.
En la computación el ordenamiento de datos también cumple un rol muy importante, ya sea como un fin en sí o como parte de otros procedimientos más complejos. Se han desarrollado muchas técnicas en este ámbito, cada una con características específicas, y con ventajas y desventajas sobre las demás. Aquí voy a mostrarte algunas de las más comunes, tratando de hacerlo de una manera sencilla y comprensible.

2. Conceptos Preliminares.

Antes de comenzar a ver cada algoritmo vamos a ponernos de acuerdo en algunos conceptos, para que no haya confusiones:

Clave: La parte de un registro por la cual se ordena la lista. Por ejemplo, una lista de registros con campos nombre, direccion y telefono se puede ordenar alfabéticamente de acuerdo a la clave nombre. En este caso los campos direccion y telefono no se toman en cuenta en el ordenamiento.
Criterio de ordenamiento (o de comparación): EL criterio que utilizamos para asignar valores a los registros con base en una o más claves. De esta manera decidimos si un registro es mayor o menor que otro. En el pseudocódigo presentado más adelante simplemente se utilizarán los símbolos <>, para mayor simplicidad.

Registro: Un grupo de datos que forman la lista. Pueden ser datos atómicos (enteros, caracteres, reales, etc.) o grupos de ellos, que en C equivalen a las estructuras.
Cuando se estudian algoritmos de todo tipo, no sólo de ordenamiento, es bueno tener una forma de evaluarlos antes de pasarlos a código, que se base en aspectos independientes de la plataforma o el lenguaje. De esta manera podremos decidir cuál se adapta mejor a los requerimientos de nuestro programa. Así que veamos estos aspectos:

Estabilidad: Cómo se comporta con registros que tienen claves iguales. Algunos algoritmos mantienen el orden relativo entre éstos y otros no. Veamos un ejemplo. Si tenemos la siguiente lista de datos (nombre, edad): "Pedro 19, Juan 23, Felipe 15, Marcela 20, Juan 18, Marcela 17", y la ordenamos alfabéticamente por el nombre con un algoritmo estable quedaría así: "Felipe 15, Marcela 20, Marcela 17, Juan 23, Juan 18, Pedro 19". Un algoritmo no estable podría dejar a Juan 18 antes de Juan 23, o a Marcela 20 después de Marcela 17.

Tiempo de ejecución: La complejidad del algoritmo, que no tiene que ver con dificultad, sino con rendimiento. Es una función independiente de la implementación. Te la voy a explicar brevemente: tenemos que identificar una operación fundamental que realice nuestro algoritmo, que en este caso es comparar. Ahora contamos cuántas veces el algoritmo necesita comparar. Si en una lista de n términos realiza n comparaciones la complejidad es O(n). (En realidad es un poco más complicado que eso, pero lo vamos a hacer así: recuerda que dije que te iba a explicar brevemente). Algunos ejemplos de complejidades comunes son:

O(1) : Complejidad constante.
O(n2) : Complejidad cuadrática.
O(n log(n)) : Complejidad logarítmica. Ahora podemos decir que un algoritmo de complejidad O(n) es más rápido que uno de complejidad O(n2). Otro aspecto a considerar es la diferencia entre el peor y el mejor caso. Cada algoritmo se comporta de modo diferente de acuerdo a cómo se le entregue la información; por eso es conveniente estudiar su comportamiento en casos extremos, como cuando los datos están prácticamente ordenados o muy desordenados.
Requerimientos de memoria: El algoritmo puede necesitar memoria adicional para realizar su labor. En general es preferible que no sea así, pero es común en la programación tener que sacrificar memoria por rendimiento.
Hay bastantes otros aspectos que se pueden tener en cuenta, pero nosotros nos vamos a quedar con ésos.
Por último estableceremos algunas convenciones sobre el pseudocódigo:
Vamos a ordenar la lista en forma ascendiente, es decir, de menor a mayor. Obviamente es esencialmente lo mismo que hacerlo en forma inversa.
La forma de intercambiar los elementos depende de la estructura de datos: si es un arreglo (dinámico o estático) es necesario guardar una copia del primer elemento, asignarle el segundo al primero y el temporal al segundo. La variable temporal es necesaria, porque de lo contrario se perdería uno de los elementos. Si la estructura es una lista dinámica el procedimiento es parecido, pero se utilizan las direcciones de los elementos. En el pseudocódigo se utilizará el primer método.

La lista se manejará como un arreglo de C: si tiene TAM elementos, el primer elemento es lista[0] y el último es lista[TAM-1]. Esto será así para todo el pseudocódigo presentado en este artículo.
Bien, ahora que ya tenemos todo claro vamos a lo que nos interesa...

3. Algoritmos más comunes.

La siguiente es una tabla comparativa de algunos algoritmos de ordenamiento. Si quieres saber más sobre alguno en particular haz un click sobre su nombre. En cada página encontrarás una descripción, pseudocódigo y un análisis sobre su rendimiento, ventajas y desventajas.
(Quizás quieras bajar ahora la
demostración para ir observándola a medida que vayas leyendo)

Tabla comparativa de algoritmos

Nombre Complejidad Estabilidad Memoria adicional

Ordenamiento por Selección O(n2) No Estable No

Ordenamiento Rápido (Quicksort) O(n * log2(n)) No Estable No

4. Eligiendo el más adecuado.

Ahora ya conoces una buena cantidad de algoritmos, pero... ¿cómo saber cuál es el que necesitas? ¿cuál es EL algoritmo?
Cada algoritmo se comporta de modo diferente de acuerdo a la cantidad y la forma en que se le presenten los datos, entre otras cosas. No existe EL algoritmo de ordenamiento. Sólo existe el mejor para cada caso particular. Debes conocer a fondo el problema que quieres resolver, y aplicar el más adecuado. Aunque hay algunas preguntas que te pueden ayudar a elegir:

¿Qué grado de orden tendrá la información que vas a manejar? Si la información va a estar casi ordenada y no quieres complicarte, un algoritmo sencillo como el ordenamiento burbuja será suficiente. Si por el contrario los datos van a estar muy desordenados, un algoritmo poderoso como Quicksort puede ser el más indicado. Y si no puedes hacer una presunción sobre el grado de orden de la información, lo mejor será elegir un algoritmo que se comporte de manera similar en cualquiera de estos dos casos extremos.

¿Qué cantidad de datos vas a manipular? Si la cantidad es pequeña, no es necesario utilizar un algoritmo complejo, y es preferible uno de fácil implementación. Una cantidad muy grande puede hacer prohibitivo utilizar un algoritmo que requiera de mucha memoria adicional.

¿Qué tipo de datos quieres ordenar? Algunos algoritmos sólo funcionan con un tipo específico de datos (enteros, enteros positivos, etc.) y otros son generales, es decir, aplicables a cualquier tipo de dato.

¿Qué tamaño tienen los registros de tu lista? Algunos algoritmos realizan múltiples intercambios (burbuja, inserción). Si los registros son de gran tamaño estos intercambios son más lentos.

5. Demostración y Código Fuente.

Puedes descargar dos programas de demostración con los algoritmos presentados en este artículo:

OrdWin: En este programa puedes ver una demostración gráfica de cada algoritmo. También puedes experimentar ordenando listas de la longitud que quieras, observando el tiempo que demoran, la cantidad de comparaciones y de intercambios que realizan. Fue creado utilizando el compilador LccWin32 de Jacob Navia, pero el fichero descargable es un proyecto para Dev-C++. Incluye el ejecutable, el código fuente y este artículo completo.

Ordenar: Este programa es más indicado si lo que quieres es mirar código. No hay funciones gráficas ni nada del API de Windows. Debería funcionar en cualquier otro compilador sin mayores cambios, pues está hecho en ANSI C. Fue probado con éxito en Turbo C++, DJGPP, LccWin32, y Dev-C++. Quedó bastante feo, pero es el precio que hay que pagar por la portabilidad ;-). Sólo incluye el código.

6. Algunas palabras para terminar.

No sabía si escribir este artículo o no. Probablemente no sea yo el indicado para hacerlo. Después de todo no soy ningún experto ni mucho menos, pero creo que puede ayudar a alguien que sepa menos que yo (no deben ser muchos :-)). Por eso pido tu colaboración para mejorar este documento y hacerlo algo útil. Si tienes sugerencias, comentarios o correcciones por favor házmelo saber.

Como solucionar un Subalgoritmo


Para solucionar un problema complejo la mejor opción es dividirlo en subproblemas - problemas mas sencillos- y a continuación dividir estos subproblemas en otros mas simples hasta que los problemas mas pequeños sean faciles de resolver.
Se llama Subalgoritmo a cada una de las partes de un algoritmo más general que resuelve cada una de las tareas particulares necesarias para que dicho algoritmo general alcance el objetivo para el que fue diseñado, es decir resolver un problema. Este concepto está vinculado al Diseño estructurado de algoritmos, en el cual un problema se divide en partes que posteriormente son resueltas por un módulo. Cada módulo coincidirá pon un subalgoritmo.

¿Cómo se diseña un subalgoritmo?

El proceso de diseño de un subalgoritmo es, en síntesis, el mismo que se sigue para un algoritmo, pero tiene una característica que lo diferencia del algoritmo principal, como realiza una función para otro algoritmo o subalgoritmo, recibe datos de entrada y devuelve resultados al mismo, esta comunicación entre subalgoritmo llamado y algoritmo o subalgoritmo llamante se realiza mediante las variables de enlace o parámetros y al proceso de emisión y recepción de datos y resultados mediante variables de enlace se denomina paso de parámetros.

La característica de este conjunto de acciones es que realizan tareas comunes que pueden utilizarse para resolver distintos tipos de problemas o bien, dentro de un mismo problema, con distintos datos.

Estos subalgoritmos se escriben una vez y, luego, son usados por todos aquéllos que requieran de ellos. Por ejemplo: ordenar datos en orden ascendente/descendente.
Cuando se hace una llamada a un subalgoritmo, se le pueden pasar parámetros (o argumentos) para determinar ciertas condiciones en su funcionamiento.

Subalgoritmos


Se llama Subalgoritmo a cada una de las partes de un algoritmo más general que resuelve cada una de las tareas particulares necesarias para que dicho algoritmo general alcance el objetivo para el que fue diseñado, es decir resolver un problema. Este concepto está vinculado al Diseño estructurado de algoritmos, en el cual un problema se divide en partes que posteriormente son resueltas por un módulo. Cada módulo coincidirá pon un subalgoritmo.

Tipos de Subalgoritmos
Funciones: Tienen un valor de retorno.
Procedimientos: No tienen un valor de retorno.

Función (programación)

En el ámbito de la programación, una función es un tipo subalgoritmo, es el término para describir una secuencia de órdenes que hacen una tarea específica de una aplicación más grande.Las declaraciones de funciones generalmente son especificadas por:Un nombre único en el ámbito.- Nombre de la función con el que se identifica y se distingue de otras. No podrá haber otra función ni procedimiento con ese nombre (salvo sobrecarga o polimorfismo en programación orientada a objetos). Una lista de parámetros.- Especificación del conjunto de argumentos (pueden ser cero, uno o más) que la función debe recibir para realizar su tarea. El código u órdenes de procesamiento.- Conjunto de ordenes y sentencias que debe ejecutar la función. Un tipo de dato de retorno.- Tipo de dato del valor que la función devolverá al terminar su ejecución. La diferencia entre funciones y los procedimientos (otro tipo de subalgotitmos) radica en que estos últimos no devuelven un resultado.
Las funciones en programación generalmente son las que realizan los cálculos para retornar el valor correspondiente a una función matemática más o menos compleja.
Ej: La siguiente función en
C es la analogía al cálculo del promedio matemático. El nombre "Promedio", retorna un valor decimal correspondiente a la suma de 2 valores enteros de entrada (A,B):
float Promedio(int A, int B){
float r;
r=(A+B)/2.0;
return r;
}
Procedimiento (Programación)

En el ámbito de la programación, un procedimiento es un tipo subalgoritmo, es el término para describir una secuencia de órdenes que hacen una tarea específica de una aplicación más grande.
Las declaraciones de procedimientos generalmente son especificadas por:
Un nombre único en el
ámbito.- Nombre del procedimiento con el que se identifica y se distingue de otros. No podrá haber otro procedimiento ni función con ese nombre (salvo sobrecarga o polimorfismo en programación orientada a objetos). Una lista de parámetros.- Especificación del conjunto de argumentos (pueden ser cero, uno o más) que el procedimiento debe recibir para realizar su tarea. El código u órdenes de procesamiento.- Conjunto de ordenes y sentencias que debe ejecutar el procedimiento. La diferencia entre un procedimiento y una función (el otro tipo de subalgoritmos) radica en que estos últimos devuelven un resultado.
Los procedimientos en programación generalmente son los que realizan operaciones de entrada/salida, en general, cualquier operación más o menos compleja que no requiera devolver un valor.

Ej: El siguiente procedimiento en
C(1) muestra un mensaje en pantalla indicando el resultado de calcular un promedio, índica cual es el valor decimal correspondiente a la suma de 2 valores enteros de entrada (A,B):
void Promedio(int A, int B){
float r;
r=(A+B)/2.0;
printf("Promedio de %d y %d = %f",A,B,r);
}
Así una llamada a Promedio(3,5) da como resultado que se muestre en pantalla el mensaje Promedio de 3 y 5 = 4.0.

Ámbito de las variables

Desde el punto de un subalgoritmo las variables pueden ser locales o globales:Las variables locales se declaran dentro de un módulo o subalgoritmo y sólo tienen utilidad dentro de ese módulo, no se podrá acceder a ellas desde otros módulos. Pueden existir variables locales con el mismo nombre siempre que estén en módulos diferentes. Las variables globales son declaradas de forma que puedan ser utilizadas (consultada y/o modificada) desde cualquiera de los módulos que forman el programa. En este caso, no puede haber dos variables globales con el mismo nombre, ya que esto produciría una ambigüedad que el compilador no podría resolver. En el diseño estructurado de algoritmos se desaconseja el uso de variables globales ya que este produciría acoplamiento común.

Paso de parámetros
Cuando se hace una llamada a un subalgoritmo, se le pueden pasar parámetros (o argumentos) para determinar ciertas condiciones en su funcionamiento. este paso de argumentos se puede hacer por valor o por referencia.

Algoritmos Complejos


Por hacer una similitud acerca de lo complicado que es este concepto, la dificultad de la complejidad es -salvando las distancias- como la de la predicción meteorológica: todos intuimos lo complicado que es hacer una predicción meteorológica, miles de datos, fórmulas, modelos y cálculos... sin embargo, cuando un meteorólogo nos explica con algo de gracia la predicción del tiempo, la podemos entender bastante bien. Ya estamos muy acostumbrados a cosas como borrasca, anticiclón, marejadilla, cota de nieve... Lo mismo pasa en cierto modo con la complejidad: enfrentarnos a un algoritmo para hacer un estudio de su complejidad requiere de un gran esfuerzo. Sin embargo, cuando alguien estudia un algoritmo y nos habla de su complejidad, entender el concepto no es tan complicado.
Entender la complejidad es importante porque a la hora de resolver muchos problemas, utilizamos algoritmos ya diseñados. Saber valorar su valor de complejidad puede ayudarnos mucho a conocer cómo se va a comportar el algoritmo e incluso a escoger uno u otro.
Así que en este artículo, nos vamos a dedicar a intentar exponer qué es la complejidad de un algoritmo desde un punto de vista sencillo y sin pretensiones, intentado distinguir qué impacto tiene el que un algoritmo tenga una u otra complejidad. Y, como de costumbre, adoptamos grandes simplificaciones, con el único ánimo de obtener una visión general de los conceptos. En cuanto a cómo obtener la complejidad de un algoritmo, no nos vamos a meter mucho: los formalismos necesarios quedan totalmente fuera del alcance de éste breve artículo divulgativo.
Entonces podemos decir que un Algoritmo complejo es aquel donde se resuelve un problema a través de árboles de decisiones.


Los algoritmos de ordenación básicos se dividen en:
  • Algoritmos de Ordenacion por seleccion.
  • Ordenacion por Inserción.
  • Oedancion por Burbuja.


Algoritmos de ordenación por selección:
Este método se basa en buscar el elemento menos del vector y colocarlo en primera posición. Luego se busca el segundo elemento más pequeño y se coloca en la segunda posición y así sucesivamente.


Ordenación por inserción:
Este método consiste en insertar un elemento en el vector en una parte ya ordenada de este vector y comenzar de nuevo con los elementos restantes. Por ser utilizado generalmente por los jugadores de cartas se le conoce también por el nombre del método de la baraja.

Ordenación por Burbuja

Se basa en el principio de comparar pares de elementos adyacentes e intercambiar entre si hasta que estén todos ordenados.


Algoritmo de búsqueda: Un algoritmo de búsqueda es aquel que está diseñado para localizar un elemento concreto dentro de una estructura de datos. Consiste en solucionar un problema booleano de existencia o no de un elemento determinado en un conjunto finito de elementos, es decir al finalizar el algoritmo este debe decir si el elemento en cuestión existe o no en ese conjunto (si pertenece o no a él), además, en caso de existir, el algoritmo podría proporcionar la localización del elemento dentro del conjunto. se dividen en:

  • Secuencial.
  • Binario.


Algoritmo de búsqueda Secuencial

Cuando el contenido del Vector no está o no puede ser ordenado, necesitaremos realizar una búsqueda completa, ya que, en principio, la existencia se puede asegurar desde el momento que el elemento es localizado, pero no podemos asegurar la no existencia hasta pasar por el último elemento.
La idea sería recorrer todos los elementos secuencialmente y, si el elemento es localizado, devolver verdadero (o su posición dentro del vector). Si el elemento no es localizado se sigue recorriendo todo el vector hasta llegar al último elemento y si llegamos al final y no lo hemos encontrado se devuelve falso.

Algoritmo de búsqueda binaria:


Cuando el Vector en el que queremos determinar la existencia o no de un elemento está ordenado, o puede estarlo, puede ser conveniente utilizar un algoritmo de Búsqueda específico. La utilización de éste permitirá reducir considerablemente el tiempo de proceso, ya que lo reduce exponencialmente

Que son Algoritmos


En matemáticas, ciencias de la computación, y disciplinas relacionadas, un algoritmo (del latín, dixit algorithmus y éste a su vez del matemático persa al-Jwarizmi) es una lista bien definida, ordenada y finita de operaciones que permite hallar la solución a un problema. Dado un estado inicial y una entrada, a través de pasos sucesivos y bien definidos se llega a un estado final, obteniendo una solución. Los algoritmos son objeto de estudio de la algoritmia. En la vida cotidiana se emplean algoritmos en multitud de ocasiones para resolver diversos problemas. Algunos ejemplos se encuentran en los instructivos (manuales de usuario), los cuales muestran algoritmos para usar el aparato en cuestión o inclusive en las instrucciones que recibe un trabajador por parte de su patrón. También existen ejemplos de índole matemático, como el algoritmo de la división para calcular el cociente de dos números, el algoritmo de Euclides para calcular el máximo común divisor de dos enteros positivos, o el método de Gauss para resolver un Sistema lineal de ecuaciones.


CARACTERISTICAS DE LOS ALGORTMOS

El científico de computación Donald Knuth ofreció una lista de cinco propiedades, que son ampliamente aceptadas como requisitos para un algoritmo:
Carácter finito. "Un algoritmo siempre debe terminar después de un número finito de pasos".
Precisión. "Cada paso de un algoritmo debe estar precisamente definido; las operaciones a llevar a cabo deben ser especificadas de manera rigurosa y no ambigua para cada caso".
Entrada. "Un algoritmo tiene cero o más entradas: cantidades que le son dadas antes de que el algoritmo comience, o dinámicamente mientras el algoritmo corre. Estas entradas son tomadas de conjuntos específicos de objetos".
Salida. "Un algoritmo tiene una o más salidas: cantidades que tienen una relación específica con las entradas".
Eficacia. "También se espera que un algoritmo sea eficaz, en el sentido de que todas las operaciones a realizar en un algoritmo deben ser suficientemente básicas como para que en principio puedan ser hechas de manera exacta y en un tiempo finito por un hombre usando lápiz y papel".
Knuth admite que, aunque su descripción pueda ser intuitivamente clara, carece de rigor formal, puesto que no está exactamente claro qué significa "precisamente definido", "de manera rigurosa y no ambigua", o "suficientemente básicas", y así sucesivamente..
A partir del carácter finito y de la salida se deduce que ante una misma situación inicial (o valores de entrada) un algoritmo debe proporcionar siempre el mismo resultado (o salida), con excepción de los
algoritmos probabilistas.