Sei sulla pagina 1di 7

INTRODUCCION AL ANALISIS DE LOS

ALGORITMOS

¿Qué es un algoritmo?
Una definición informal (no se considera aquí una definición formal, aunque existe): conjunto finito de reglas
que dan una secuencia de operaciones para resolver todos los problemas de un tipo dado. De forma más
sencilla, podemos decir que un algoritmo es un conjunto de pasos que nos permite obtener un dato. Además
debe cumplir estas condiciones:

· Finitud: el algoritmo debe acabar tras un número finito de pasos. Es más, es casi fundamental que sea en un
número razonable de pasos.
· Definibilidad: el algoritmo debe definirse de forma precisa para cada paso, es decir, hay que evitar toda
ambigüedad al definir cada paso. Puesto que el lenguaje humano es impreciso, los algoritmos se expresan
mediante un lenguaje formal, ya sea matemático o de programación para un computador.
· Entrada: el algoritmo tendrá cero o más entradas, es decir, cantidades dadas antes de empezar el algoritmo.
Estas cantidades pertenecen además a conjuntos especificados de objetos. Por ejemplo, pueden ser cadenas de
caracteres, enteros, naturales, fraccionarios, etc. Se trata siempre de cantidades representativas del mundo real
expresadas de tal forma que sean aptas para su interpretación por el computador.
· Salida: el algoritmo tiene una o más salidas, en relación con las entradas.
· Efectividad: se entiende por esto que una persona sea capaz de realizar el algoritmo de modo exacto y sin
ayuda de una máquina en un lapso de tiempo finito.

A menudo los algoritmos requieren una organización bastante compleja de los datos, y es por tanto necesario un
estudio previo de las estructuras de datos fundamentales. Dichas estructuras pueden implementarse de diferentes
maneras, y es más, existen algoritmos para implementar dichas estructuras. El uso de estructuras de datos
adecuadas pueden hacer trivial el diseño de un algoritmo, o un algoritmo muy complejo puede usar estructuras
de datos muy simples.

Uno de los algoritmos más antiguos conocidos es el algoritmo de Euclides. El término algoritmo proviene del
matemático Muhammad ibn Musa al-Khwarizmi, que vivió aproximadamente entre los años 780 y 850 d.C. en
la actual nación Iraní. El describió la realización de operaciones elementales en el sistema de numeración
decimal. De al-Khwarizmi se obtuvo la derivación algoritmo.

- Clasificación de algoritmos

* Algoritmo determinista: en cada paso del algoritmo se determina de forma única el siguiente paso.
* Algoritmo no determinista: deben decidir en cada paso de la ejecución entre varias alternativas y agotarlas
todas antes de encontrar la solución.

Estructuras de Datos – Leccion 1 Página 1


Todo algoritmo tiene una serie de características, entre otras que requiere una serie de recursos, algo que es
fundamental considerar a la hora de implementarlos en una máquina. Estos recursos son principalmente:

· El tiempo: período transcurrido entre el inicio y la finalización del algoritmo.


· La memoria: la cantidad (la medida varía según la máquina) que necesita el algoritmo para su ejecución.

Obviamente, la capacidad y el diseño de la máquina pueden afectar al diseño del algoritmo.

En general, la mayoría de los problemas tienen un parámetro de entrada que es el número de datos que hay que
tratar, esto es, N. La cantidad de recursos del algoritmo es tratada como una función de N. De esta manera
puede establecerse un tiempo de ejecución del algoritmo que suele ser proporcional a una de las siguientes
funciones:

• 1 : Tiempo de ejecución constante. Significa que la mayoría de las instrucciones se ejecutan una vez o
muy pocas.

• logN : Tiempo de ejecución logarítmico. Se puede considerar como una gran constante. La base del
logaritmo (en informática la más común es la base 2) cambia la constante, pero no demasiado. El
programa es más lento cuanto más crezca N, pero es inapreciable, pues logN no se duplica hasta que N
llegue a N2.

• N : Tiempo de ejecución lineal. Un caso en el que N valga 40, tardará el doble que otro en que N valga
20. Un ejemplo sería un algoritmo que lee N números enteros y devuelve la media aritmética.

• N·logN : El tiempo de ejecución es N·logN. Es común encontrarlo en algoritmos como Quick Sort y
otros del estilo divide y vencerás. Si N se duplica, el tiempo de ejecución es ligeramente mayor del
doble.

• N2 : Tiempo de ejecución cuadrático. Suele ser habitual cuando se tratan pares de elementos de datos,
como por ejemplo un bucle anidado doble. Si N se duplica, el tiempo de ejecución aumenta cuatro
veces. El peor caso de entrada del algoritmo Quick Sort se ejecuta en este tiempo.

• N3 : Tiempo de ejecución cúbico. Como ejemplo se puede dar el de un bucle anidado triple. Si N se
duplica, el tiempo de ejecución se multiplica por ocho.

• 2N : Tiempo de ejecución exponencial. No suelen ser muy útiles en la práctica por el elevadísimo tiempo
de ejecución. El problema de la mochila resuelto por un algoritmo de fuerza bruta -simple vuelta atrás-
es un ejemplo. Si N se duplica, el tiempo de ejecución se eleva al cuadrado.

* Algoritmos polinomiales: aquellos que son proporcionales a Nk. Son en general factibles.
* Algoritmos exponenciales: aquellos que son proporcionales a kN. En general son infactibles salvo un tamaño
de entrada muy reducido.

- Notación O-grande

En general, el tiempo de ejecución es proporcional, esto es, multiplica por una constante a alguno de los
tiempos de ejecución anteriormente propuestos, además de la suma de algunos términos más pequeños. Así, un
algoritmo cuyo tiempo de ejecución sea T = 3N2 + 6N se puede considerar proporcional a N2. En este caso se

Estructuras de Datos – Leccion 1 Página 2


diría que el algoritmo es del orden de N2, y se escribe O(N2)
Los grafos definidos por matriz de adyacencia ocupan un espacio O(N2), siendo N el número de vértices de éste.

La notación O-grande ignora los factores constantes, es decir, ignora si se hace una mejor o peor
implementación del algoritmo, además de ser independiente de los datos de entrada del algoritmo. Es decir, la
utilidad de aplicar esta notación a un algoritmo es encontrar un límite superior del tiempo de ejecución, es decir,
el peor caso.

A veces ocurre que no hay que prestar demasiada atención a esto. Conviene diferenciar entre el peor caso y el
esperado. Por ejemplo, el tiempo de ejecución del algoritmo Quick Sort es de O(N2). Sin embargo, en la
práctica este caso no se da casi nunca y la mayoría de los casos son proporcionales a N·logN. Es por ello que se
utiliza esta última expresión para este método de ordenación.

Una definición rigurosa de esta notación es la siguiente:


Una función g(N) pertenece a O(f(N)) si y sólo si existen las constantes c0 y N0 tales que:
|g(N)| <= |c0·f(N)| , para todo N >= N0.

- Clasificación de problemas

Los problemas matemáticos se pueden dividir en primera instancia en dos grupos:

* Problemas indecidibles: aquellos que no se pueden resolver mediante un algoritmo.


* Problemas decidibles: aquellos que cuentan al menos con un algoritmo para su cómputo.

Sin embargo, que un problema sea decidible no implica que se pueda encontrar su solución, pues muchos
problemas que disponen de algoritmos para su resolución son inabordables para un computador por el elevado
número de operaciones que hay que realizar para resolverlos. Esto permite separar los problemas decidibles en
dos:

* intratables: aquellos para los que no es factible obtener su solución.


* tratables: aquellos para los que existe al menos un algoritmo capaz de resolverlo en un tiempo razonable.

Los problemas pueden clasificarse también atendiendo a su complejidad. Aquellos problemas para los que se
conoce un algoritmo polinómico que los resuelve se denominan clase P. Los algoritmos que los resuelven son
deterministas. Para otros problemas, sus mejores algoritmos conocidos son no deterministas. Esta clase de
problemas se denomina clase NP. Por tanto, los problemas de la clase P son un subconjunto de los de la clase
NP, pues sólo cuentan con una alternativa en cada paso.

GENERALIDADES

¿Qué se necesita para escribir un programa eficiente?


Para diseñar programas eficientes se necesitan dos cosas primordialmente:

1. Una estructura de datos: que no es otra cosa más que una forma de representar y almacenar información
en una computadora.
2. Un algorítmo: es un método para resolver un problema.

Estructuras de Datos – Leccion 1 Página 3


Por lo tanto:
Eficiencia = Buen Algoritmo + Buena Estructura de Datos

Pero en definitiva nunca hay que olvidar que la mejor estructura de datos y el mejor algoritmo deben ser
codificados por un buen desarrollador "Una de las metas de este curso es que usted se convierta en un buen
desarrollador"

ALGORITMO

(Mo hammed al-Khowarizmi) Secuencia de pasos ordenados sin ambiguedades que resuelve un problema.

Metas de un algorítmo
Un algorítmo debe tener tres metas fundamentales:

1. Debe ser fácil de implementar.


2. Debe ser eficiente.
3. Debe ser correcto.

¿Porqué y para qué analizar algorítmos?


Las razones por las cuales se analizan algorítmos son las siguientes:

1. Conocer el tiempo estimado de ejecución de un programa.


2. Reducir el tiempo de ejecución.
3. Criterio de diseño de algorítmos y estructuras de datos.
4. Evaluación y crítica de algorítmos.
5. Uso de matemática avenzada.
6. Resolver problemas para proporcionar soluciones.

Técnicas de diseño de algorítmos


Algunas técnicas conocidas en la implementación de algorítmos son las siguientes:

1. Proceso de información sobre estructuras de datos.


2. La técnica de dividir y conquistar.
3. La técnica de barrido.
4. La técnica de acumulados.

Aplicaciones prácticas de los algoritmos

A primera vista, se puede pensar que el conocimiento de estos algoritmos y estructuras de datos no tienen una
aplicación práctica inmediata. Sin embargo, su conocimiento y correcta aplicación sirven para producir
programas mejores, en el sentido de que aprovechan mejor la memoria del sistema, son más rápidos, eficientes,
robustos y tolerantes a fallos.

Estructuras de Datos – Leccion 1 Página 4


Las aplicaciones de estos algoritmos en algunos casos son inmediatas; por ejemplo, hallar el trayecto más corto
entre dos estaciones es algo que interesa a muchos viajeros del metro y se pueden obtener aproximaciones
bastante buenas del mundo real utilizando algunos de los algoritmos que obtienen distancias mínimas. Otros
algoritmos sirven para procesar cadenas, lo cual sirve de base para analizadores léxicos o algoritmos
criptográficos, por ejemplo.

Además, tener conocimientos adecuados de algoritmia y estructuras de datos facilita el poder pasar de un
lenguaje de programación a otro con mucha mayor facilidad: puesto que ya se tiene la base, sólo hace falta
superar las dificultades técnicas particulares de cada lenguaje.

Lenguajes de programación

Para poder crear un programa debemos utilizar un determinado lenguaje de programación. Nos encontramos
con varios tipos de lenguaje, que se distinguen por su proximidad al lenguaje humano o al lenguaje máquina.

Lenguajes de bajo nivel: Son muy parecidos al código máquina (el que entiende el ordenador), por lo que son
muy difíciles de aprender y usar, pero tienen como gran ventaja la posibilidad de utilizar al máximo las
prestaciones de la máquina.

Lenguajes de alto nivel: Están más alejados del código máquina pero son más parecidos al lenguaje humano.
Son, por tanto, más fáciles de aprender y usar, pero no permiten acceder a ciertas operaciones que sí permiten
los de bajo nivel. No todos los lenguajes pertenecientes a este grupo tienen el mismo nivel. Así, podríamos
considerar el BASIC como el de más nivel y el C el de menos nivel (pero siempre dentro de los cercanos al
lenguaje humano).

Al primer grupo pertenece el ensamblador, que sólo se usa para casos muy concretos que necesiten la
manipulación de bits o para crear virus. Al segundo grupo pertenecen la mayoría de los lenguajes existentes,
entre los que podemos destacar los siguientes:

C: Fue creado por Brian Kernighan y Dennis Ritchie y es uno de los más utilizados en la actualidad. El sistema
operativo UNIX fue escrito en este lenguaje. Posteriormente a la aparición de C, se diseñó C++, ampliación del
anterior y que está dirigido a la OOP (Programación Orientada a Objetos).

PASCAL: Fue creado por Niklaus Wirth, que también creó Modula-2. Está pensado para crear programas de
tipo matemático. Delphi, entorno creado para desarrollar programas en 32 bits bajo interfaz gráfica, está basado
en este lenguaje.

FORTRAN: (Acrónimo de FORmula TRANslator). Es el lenguaje de programación más antiguo, aunque aún
se sigue utilizando.

BASIC: Su nombre es debido a que es una simplificación del FORTRAN. Fue un lenguaje muy utilizado en la
década de los ochenta, aunque ha perdido terreno. Actualmente, es muy utilizado Visual Basic, que es la versión
creada por Microsoft para desarrollar programas con interfaz gráfica en BASIC.

COBOL (COmmon Business Oriented Language): Se utilizaba hace años para la creación de aplicaciones
comerciales. Fue uno de los lenguajes de programación más populares y aún se usa.

Estructuras de Datos – Leccion 1 Página 5


LOGO: Este lenguaje no se caracterizaba por su eficiencia, sino porque era muy fácil de aprender. Fue
diseñado con el objetivo de facilitar el aprendizaje de la programación a los niños, que en el futuro podrían
adaptarse fácilmente otro lenguaje más completo. Apenas se usa hoy en día.

LISP (LISt Processing): El nombre es debido a que sus estructuras de datos fundamentales son las listas. Está
dirigido a la creación de sistemas que simulen la inteligencia humana.

Desde que se inició la programación de ordenadores, los lenguajes han ido evolucionando, hasta el punto de que
podemos diferenciarlos en cinco generaciones:

• Primera generación: Al principio los ordenadores sólo podían ser programados en código binario, es
decir, secuencias de ceros y unos. Los programadores debían adaptarse al lenguaje de la máquina
(lenguaje máquina), que era distinto en cada modelo de ordenador.
• Segunda generación: Dado que la programación en código binario era extremadamente difícil, se
crearon los primeros lenguajes simbólicos o ensambladores. También dependían del ordenador que se
estaba utilizando, aunque el código era más legible.
• Tercera generación: Se crearon los primeros lenguajes de alto nivel. Los códigos utilizados ya no
dependían de la máquina y además eran muy parecidos al lenguaje humano y el lenguaje matemático.
• Cuarta generación: Corresponde a los lenguajes que pertenecen a la OOP (Object Oriented
Programming o Programación Orientada a Objetos). En este tipo de lenguajes se pretende que las
aplicaciones consten de diversos segmentos de programa, los cuales se pueden reutilizar para otros
programas.
• Quinta generación: Esta generación se refiere a los lenguajes dirigidos a la Inteligencia Artificial (IA).
Aún están muy poco desarrollados.

Diseño de programas
Un programa es un conjunto de líneas de código escritas en un lenguaje de programación determinado. Pero el
código escrito en un lenguaje de alto nivel no puede ser entendido por el ordenador, por lo que es necesaria la
traducción a código máquina. En este proceso tienen lugar dos fases. En la primera fase (compilación) el
compilador traduce cada uno de las partes del programa y crea módulos objeto, que posteriormente serán unidos
por el linker (enlazado), creando el módulo ejecutable .exe. Como la compilación y el enlazado son dos
procesos dependientes, a menudo se suele denominar a todo el proceso compilación.

En el diseño de un programa tenemos diferentes pasos:

1. Análisis del problema. Este paso es fundamental. La correcta resolución de un problema viene
determinada en gran medida por el planteamiento inicial. Un planteamiento correcto nos evitará perder
tiempo en la implementación de algoritmos que posteriormente nos demos cuenta que son incorrectos.
En este paso nos debemos hacer tres preguntas: ¿Qué entradas se nos ofrece?, ¿Qué salida debemos
generar? y ¿Cuál es el método que debemos usar para llegar hacia la solución deseada?
2. Diseño del algoritmo. Si en el análisis determinamos qué hace el programa aquí determinamos cómo lo
hace. Para ello se divide el problema en varios subproblemas que se solucionan de forma independiente
(divide y vencerás), lo que se denomina diseño modular. En este paso puede ser conveniente la
utilización de diagramas de flujo o pseudocódigo.
3. Codificación. Es la escritura del código según el algoritmo decidido en las etapas anteriores.

Estructuras de Datos – Leccion 1 Página 6


4. Compilación y ejecución. Una vez escrito el código, se compila. Si el código contiene errores el
compilador nos los mostrará: son los llamados errores de compilación, que suelen estar relacionados con
incoherencias en la sintaxis, conversión incorrecta de tipos, etc. Una vez solucionados estos errores, se
creará el programa ejecutable.
5. Verificación. Al ejecutar el programa puede ocurrir que realice lo que queríamos o que, por el contrario,
produzca un resultado indeseado. Nos encontramos aquí con dos tipos de errores:
- Errores de ejecución: Se producen cuando el programa llega a un punto en el que el ordenador no
puede realizar la operación que se le solicita: división por cero, desbordamiento, etc.
- Errores del algoritmo: Son los más difíciles de detectar, se producen cuando el algoritmo está mal
implementado. Nos conduce al siguiente paso.
6. Depuración. Esta es una parte importante. Se utilizan las herramientas de depuración del compilador
que usamos, lo que en gran medida determina si el compilador es mejor o peor. En general, todos los
compiladores incluyen entre sus herramientas de depuración las siguientes:
- Ejecución paso a paso: En lugar de ejecutar todo el programa hasta su finalización, se ejecuta línea a
línea, lo que permite observar el comportamiento del programa en cada momento.
- Watches (inspecciones): permiten seguir el valor de una variable y comprobar que cambia su valor en
su momento y modo deseado.
- Debug Inspector: similar a las watches pero especialmente útil para la visualización de arrays, listas,
etc.
- Breakpoints: si la ejecución es demasiado larga, podemos definir un breakpoint (punto de ruptura) en
una o varias líneas. El programa se ejecutará normalmente hasta que llegue a una de esas líneas. En ese
momento la ejecución se detendrá y podremos consultar valores de variables o ejecutar paso a paso
desde ese punto.
- Evaluar/modificar: permite obtener el valor de una variable en un punto en el que la ejecución del
programa se ha pausado. Se puede modificar el valor de dicha variable para comprobar, por ejemplo,
que si tuviera otro valor el comportamiento también sería el esperado.

Estructuras de Datos – Leccion 1 Página 7

Potrebbero piacerti anche