Escolar Documentos
Profissional Documentos
Cultura Documentos
Muchas veces, la mitad del trabajo es saber exactamente qué problema hay que resolver.
Si al abordar un problema no se tiene una descripción simple y precisa de él, resulta complejo modelar, simular o
programar su solución en una computadora. En este punto, hay que destacar también la importancia de ciertos
aspectos relacionados con la resolución de problemas: notaciones de representación, estrategias, relaciones entre
problemas, etc.
En general, conviene expresar un problema utilizando algún modelo formal. Por ejemplo, un modelo aritmético
puede resultar adecuado para problemas de naturaleza numérica o un modelo basado en gramáticas formales puede
servir para problemas de procesamiento simbólico o de textos.
Una vez modelado el problema, puede buscarse una solución en forma de algoritmo. Un algoritmo es un conjunto
finito, y no ambiguo de etapas expresadas en un cierto orden que, para unas condiciones iniciales, permiten
resolver el problema en un tiempo finito. Al plantear una solución algorítmica es importante elegir una
representación adecuada de los datos para que dicha
solución resulte eficiente.
Para convertir un algoritmo, que puede estar expresado en una notación informal o seudolenguaje, en un programa
será necesario varias etapas de formalización o refinamiento progresivo. El objetivo final es describir una solución
algorítmica al problema inicialmente planteado mediante el uso de las construcciones formales de un lenguaje de
programación. Dicho programa se podrá ejecutar en una computadora, y para un conjunto de datos de entrada
producirá unos resultados.
Por ejemplo, supóngase que se desea construir una tabla con las distancias kilométricas por carretera entre un
conjunto de ciudades de un país. Para ello, se suministran como datos de entrada las distancias entre pares de
ciudades directamente conectadas. Este problema puede modelarse mediante un grafo. Se trata de una estructura de
datos (o manera de organizar la
información) no lineal, en la que existen unos elementos llamados nodos o vértices que contienen unos datos. Entre
pares de nodos se establecen unas relaciones que si son dirigidas se llaman arcos y si no lo son aristas. Los vértices
van a representar las ciudades y a las aristas que unen ciudades conectadas se les asocia la distancia
correspondiente. Para su resolución se puede utilizar un algoritmo que permita calcular caminos de distancia
mínima entre todos los pares de nodos de un grafo. La solución , en forma de programa, se puede obtener mediante
sucesivos refinamientos hasta conseguir describir cada una de las operaciones y datos del algoritmo mediante
sentencias de un lenguaje de programación de alto nivel.
- Aspectos de la resolución de problemas:
No existe un método universal que permita resolver cualquier problema. En general, la resolución de problemas es
un proceso creativo donde el conocimiento, la habilidad y la experiencia tienen un papel importante. El proceder de
manera sistemática (sobre todo si se trata de problemas complejos) puede ayudar en la resolución. Es muy
importante que el problema tratado esté perfectamente definido: se trata en este momento de saber qué es lo que
hay que resolver antes de averiguar cómo resolver el problema. Esta etapa de definición lleva consigo eliminar las
ambigüedades y la información irrelevante que aparezca en el enunciado de un problema, y saber exactamente qué
elementos constituyen una solución válida.
Al comenzar a abordar un problema hay que tener en cuenta que, para la mayoría de ellos, hay muchas maneras de
resolverlos y pueden existir muchas soluciones. Se plantean, sin embargo, algunos criterios o estrategias generales
que se deben tener en cuenta. En particular, son útiles las siguientes:
-Usar toda la información útil (no superflua) disponible en el enunciado del problema.
-Hacer explícitas las reglas y datos que parezcan implícitos (por ejemplo, en muchos problemas numéricos se
pueden usar reglas convencionales de la aritmética o el álgebra).
-Profundizar en el problema considerando (por ejemplo, empleando algún tipo de notación, utilizando
determinados símbolos o dibujando algún diagrama que nos permitan captar ciertos detalles del problema antes de
resolverlo).
-Dividir un problema complejo en subproblemas más simples, que se puedan resolver independientemente y
después combinar sus soluciones.
-Otra forma de abordar un problema consiste en trabajar “hacia atrás”; es decir, partir de la solución e intentar
llegar al estado inicial.
Existe otro aspecto muy importante, aún no mencionado, a tener en cuenta cuando se intenta resolver un problema.
Generalmente, los problemas no están aislados, sino que existen interrelaciones o afinidades. En estos casos resulta
muy práctico disponer de la solución de un problema afín para resolver el que nos ocupa. Existen diversos grados
de afinidad entre problemas. Así, se dice que dos problemas son isomorfos cuando se puede establecer una
aplicación biyectiva entre los estados y acciones de uno de ellos con los del otro. La similaridad es una relación
entre problemas más débil; sin embargo, el proceso seguido para encontrar la
solución a un problema puede ayudar a resolver otro similar. Otro tipo de afinidad entre dos problemas se da
cuando uno de ellos es un caso especial del otro; resolver el caso especial puede ayudar a encontrar la solución del
problema más general, o viceversa.
Las consideraciones mencionadas hasta ahora corresponden a la resolución general de problemas (no
necesariamente a problemas informáticos); sin embargo, estas ideas se pueden particularizar para resolver
problemas donde se use la computadora como herramienta. A veces, la situación más frecuente para mucha gente
es comenzar a programar la solución de un problema que no está completamente definido, o pensar en detalles de
implementación sin saber cómo abordar el problema independientemente de la computadora. Es mucho más
productivo conocer primero un problema lo suficiente y plantear una estrategia adecuada para su resolución, que
comenzar prematuramente a programar la solución a un problema incompleto, ambiguo o que no ha sido analizado
adecuadamente.
3.1.3.- Algoritmos
Uno de los ejemplos más sencillos de un algoritmo es una receta de cocina.
Tomemos una receta cualquiera, como las que podemos encontrar en diarios y revistas:
PLATO XX
Tiempo de ejecución: 1 hora
Dificultad: mínima
Ingredientes : A,B,C,D,E,F y 300 cc de Salsa roja
Elementos: Utensillos: batidor, espátula,....., 2 fuentes mediana, 1 olla
Preparación :
Masa:
1. Mezclar los ingredientes A , B y C
2. Batir enérgicamente durante 3 minutos
3. Dejar reposar
Pasta crema:
1. Desmenuzar los ingredientes D y E.
2. Ir agregando de a poco el ingrediente F, batiendo. repetir esta operación hasta alcanzar el PUNTO de HILO.
3. Dejar enfriar.
Armado:
1. Colocar una capa de masa sobre la fuente enharinada.
2. Respelgar la masa.
3. Cubrir con la pasta crema.
4. Adornar arriba con el resto de la masa.
5. Cocinar a horno suave 15 minutos.
6. Cubrir con SALSA ROJA y servir.
Podemos aquí identificar un conjunto finito, ordenado y preciso de acciones, para que la persona que desee cocinar
pueda llevar a cabo la preparación del plato XX (La persona que cocina es el resolutor o ejecutor, y preparar el
plato es el problema a resolver).
Hay entradas (ingredientes) y una salida (el plato). El ejecutor (cocinero) dispone de los medios (utensillos cocina)
para realizar las acciones y comprende (interpreta) las indicaciones de cada paso.
Se puede observar que el proceso está definido en secciones (módulos o partes) y que hay una parte principal (el
armado) que aplica (emplea) todas las anteriores. También emplea (cita) una sección (módulo) descripta fuera de la
receta, pues se entiende que es de carácter general y puede emplearse en varias recetas.
- Algoritmos computacionales
Para este tipo de algoritmos el ejecutor es la máquina, que puede realizar un conjunto limitado de operaciones
(instrucciones).
El algoritmo (receta) se constituye en un conjunto de instrucciones (programa), las que deben darse en un lenguaje
adecuado (lenguaje de programación) que la máquina comprenda y que ella almacena en su memoria con formato
digital (compilación).
Para llevar a cabo la tarea (resolver el problema) se debe dar una orden (ejecución).
Los elementos con los que trabajará el programa (ingredientes) son información (o también llamada datos) los que
se manejan en formatos especiales que pueden ser reconocidos por la máquina.
Los datos que se ingresan a la máquina desde dispositivos de entrada (medios de entrada) se denominan datos de
entrada; cuando están siendo tratados por la máquina durante el programa o son generados por el programa para
cumplir la tarea, se habla de datos en memoria y en particular datos auxiliares y cuando son entregados de cierta
forma al usuario (medios de salida)
se denominan datos de salida.
La información que dispone la máquina (programa y datos) siempre son almacenados internamente en la memoria
en formato digital (binario: bits, bytes, registros, direcciones).
Cuando los datos son ingresados por el usuario, desde dispositivos manipulados por él (teclado, scanner,
reconocedor de voz, lectoras láser, etc.) los datos se presentan en formatos que son accesibles al usuario (teclas,
páginas de papel, micrófono, códigos de barra, etc.). Lo mismo para la salida (caracteres lumínicos en la pantalla,
sonidos por parlantes, caracteres imprimibles por
impresoras , etc.).
Los programas (salvo que sean muy elementales) no se escriben como una extensa lista de instrucciones. Teniendo
en cuenta que los programas seguramente tendrán que ser corregidos, modificados o cuanto menos entendidos, es
indispensable pensar en una metodología para su diseño.
Una estrategia popular se basa en dividir los problemas (o procesos) en procesos más simples, para facilitar su
comprensión y resolución. Para ello es indispensable que se indique cómo el problema mayor se va a resolver
aplicando la resolución de los problemas más sencillos.
Este criterio puede continuar hasta que los problemas en que hemos dividido un proceso son de sencilla solución.
Esta metodología se denomina Diseño Modular Descendente, y en cada nivel de descomposición se identifica un
módulo principal (llamador) que invoca a otros módulos (llamados) para resolver los problemas en los cuales se
dividió al primero.
Al escribir el programa o proceso principal, los módulos que serán llamados pueden estar indicados como
porciones de ese programa (subprogramas internos) o haber sido escritos como módulos independientes
(subprogramas externos).
Observando el ejemplo de la receta en el punto anterior, se puede ver que el proceso principal es el armado, que
llama a procesos descriptos en la misma receta (masa, pasta crema), los cuales constituyen subprocesos internos
(propios de esta receta) y procesos externos (salsa roja) que constituyen subprocesos externos (generales para
varias recetas).
A su vez, para realizar la salsa roja (como podría haberse dado para la pasta crema) pueden encontrarse otros
subprocesos. Notar que nada se dijo sobre el punto de hilo, porque se puede entender que el resolutor reconoce por
propia capacidad (o experiencia) cuando se alcanzó tal punto. Pero bien podría darse el caso que sea necesario
definir cuando este punto es alcanzado.
Notar también que hay una diferencia entre el empleo de los diferentes subprocesos. La masa, la pasta crema, la
salsa roja, son productos que han dejado como resultado los subprocesos correspondientes; y en el armado los
utilizamos directamente en acciones concretas, a estos subprocesos se los denomina Funciones porque tienen como
finalidad producir un resultado que
se emplea en otra acción. En cambio, respelgar es un conjunto de acciones que constituyen un subproceso, el cual
se lleva a cabo cuando se lo invoca sin que deje un producto nuevo; a éstos se los denomina Procedimientos.
En general el formato interno de almacenamiento de los datos es transparentepara el usuario, aunqueun
programador debe
tener cierto conocimiento para poder tomar decisiones respecto al almacenamiento y utilizar racionalmente espacio
de memoria y
operaciones.
- Sintaxis y semántica de un lenguaje de programación:
Los lenguajes de programación permiten expresar nuestros algoritmos en una notación formal que pueda ser
reconocida y ejecutada por la computadora. Dicha especificación se llama programa.
La sintaxis de un lenguaje de programación especifica cómo se pueden construir los programas en él,
permitiéndose sólo el uso de determinadas combinaciones de símbolos seleccionados y palabras clave.
Sin embargo, los lenguajes de programación no sólo necesitan una sintaxis precisa, sino también una semántica
precisa. Es necesario asignar, de alguna forma, significado a cada tipo de construcción permitida en un lenguaje de
programación, para poder escribir programas en él e interpretar su significado. Por ejemplo, el siguiente tipo de
instrucción iterativa utilizada en el
lenguaje Visual Basic y descrita mediante la siguiente producción:
Significa exactamente que primero es preciso evaluar una expresión booleana y sí su significado es cierto, ejecutar
el grupo de sentencias asociado. A continuación, hay que volver a evaluar la expresión y repetir el proceso hasta
que el resultado de la expresión booleana deje de ser cierto.
Una descripción clara y completa de la sintaxis y semántica es necesaria para asegurar que todas las
implementaciones del lenguaje acepten exactamente los mismos programas.
- Paradigmas de programación:
Un paradigma de programación es una colección de patrones conceptuales que modelan la forma de razonar sobre
problemas, de formular algoritmos y, a la larga, de estructurar programas. A veces, un lenguaje contiene o soporta
los elementos de un determinado paradigma; por ejemplo, Visual Basic es un lenguaje diseñado según el paradigma
orientado a eventos. Por
supuesto, suele haber más de un lenguaje basado en un paradigma dado. También existen lenguajes que combinan
elementos de varios paradigmas. De todas formas, y aunque en la práctica muchas veces se confunden, conviene
distinguir ambos conceptos, paradigma y lenguaje de programación.
Los dos paradigmas más extendidos y estudiados desde un punto de vista algorítmico, quizá sean el imperativo y el
funcional. Entre los paradigmas más recientes, se encuentra el paradigma orientado a eventos, que es el que
estamos utilizando como marco conceptual en este curso de programación básica, y el cual se adapta perfectamente
a ambientes (como el sistema operativo Windows) que funcionan estrechamente relacionados al concepto de
eventos.
2) Desarrollo de la solución
Una vez definido el problema y teniendo cierta idea de cómo resolverlo, se puede utilizar alguna Tutoriales,
manuales
de referencia y descripciones formales son algunas de las distintas formas usadaspor los diseñadores y proveedores
para
representar la estructura y el significado de los distintos componentes de cada lenguaje de programación.
de las técnicas conocidas de diseño de algoritmos. Muchas veces, debido a la complejidad interna de los problemas
a resolver, se puede ir describiendo la solución como una secuencia de pasos bastante generales (esto puede hacerse
en lenguaje natural), que cada vez se van detallando o refinando más hasta obtener una solución. En esta etapa
también se empiezan a tomar decisiones
sobre las estructuras de datos que se utilizarán para representar los datos del problema.
3) Codificación de la solución
Considerando que la solución algorítmica ha sido bien definida, este proceso resulta casi completamente mecánico.
Utilizando las reglas sintácticas y semánticas de un lenguaje de programación, el algoritmo se escribe teniendo en
cuenta también ciertos criterios de estilo o estructura.
Divide y vencerás
Consiste en descomponer un problema en subproblemas, resolver independientemente los subproblemas para luego
combinar sus soluciones y obtener la solución del problema original. Esta técnica se puede aplicar con éxito a
problemas como la multiplicación de las matrices, la ordenación de vectores, la búsqueda en estructuras ordenadas,
etc.
Método voraz
Este método trata de producir algún tipo de mejor resultado a partir de un conjunto de opciones candidatas. Para
ello, se va procediendo paso a paso realizándose la mejor elección (usando una función objetivo que respeta un
conjunto de restricciones) de entre las posibles.
Puede emplearse en problemas de optimización, como el conocido de la mochila, en la búsqueda de caminos
mínimos sobre grafos, la planificación en el orden de la ejecución de unos programas en una computadora, etc.
- El estilo en la algorítmica:
Algunas consideraciones estilísticas pueden contribuir a mejorar la calidad de los algoritmos (y programas)
mediante la reducción del número de errores que aparecen al desarrollarlos. También influyen haciendo que
nuestros algoritmos resulten más fáciles de leer y entender para otras personas.
Los criterios de estilo pueden reflejarse en un conjunto de normas de estilo de codificación. Ello asegurará que
tanto algoritmos como programas resulten legibles y puedan modificarse fácilmente en caso de necesidad.
Generalmente, estas normas de estilo se dirigen hacia aspectos como la forma de construir los nombres de las
variables o tipos de datos que aparezcan; la tipografía seguida a la hora de escribir nombres de variables,
subprogramas, palabras clave, etc; el modo de encolumnar las distintas partes de un algoritmo para facilitar su
lectura y comprensión, y las normas sobre cómo y dónde deben de introducirse los comentarios.
Estilo y claridad de los programas van fuertemente unidos. Ante la pregunta: “¿Cuáles son las características de un
buen algoritmo?”, las siguientes respuestas reflejan, en cierta medida, los factores que identifican la calidad en
ellos:
- Corrección (eficacia): el algoritmo debe funcionar Nunca se debe olvidar que la característica más simple e
importante de un algoritmo es que funcione y resuelva el problema. Puede parecer obvio, pero resulta difícil de
asegurar en algoritmos complejos.
- Eficiencia: el algoritmo no debe desaprovechar recursos La eficiencia de un algoritmo se mide por los recursos
que éste consume. En particular, se habla de la memoria y del tiempo de ejecución. A pesar de que con la reducción
de los costes del
hardware es posible diseñar computadoras más rápidas y con más memoria, no hay que desperdiciar estos recursos
y tratar de desarrollar algoritmos más eficientes.
Cuando se habla de tiempo nos referimos a la cantidad de operaciones que realiza (no precisamente el tiempo-
milisegundos-que insuman). Un algoritmo será más eficiente que otro si resuelve la misma cuestión con menor
cantidad de operaciones.
- Claridad: el algoritmo debe estar bien documentado La documentación ayuda a comprender el funcionamiento de
los algoritmos. Ciertos detalles o algunas partes especiales de los mismos pueden olvidarse fácilmente o quedar
oscuras si no están adecuadamente documentadas.
En realidad, y de acuerdo con los puntos de vistas anteriores, la calidad de un algoritmo tiene muchas facetas y
todas ellas importantes. Resumiendo, lo ideal es que nuestros algoritmos resulten correctos, eficientes, claros,
fiables y fáciles de mantener.
- Diseño de Programas:
El diseño de programas es una tarea difícil y es un proceso creativo. No existe un conjunto completo de reglas, ni
algoritmos para indicar cómo escribir programas.
Las fases mencionadas anteriormente, disponen de una serie de pasos que enlazados convenientemente conducirán
a la solución del problema. Aunque el diseño de programas es un proceso esencialmente creativo, se pueden
considerar una serie de fases o pasos comunes que generalmente deben seguir todos los programadores.
La fase de compilación traduce el código fuente a código de máquina mediante el empleo de intérpretes o
compiladores y en la fase de ejecución se corre el programa sobre la computadora.
En las fases de verificación y depuración el programador busca errores de las etapas anteriores y los elimina. Podrá
comprobar que mientras más tiempo gaste en la fase de análisis y diseño menos tiempo invertirá en la fase de
verificación y depuración. Por último, se debe realizar la importante fase de documentación del programa, con el
objeto de que cualquier persona ajena al mismo
pueda entender qué hace y cómo lo hace.
Antes de profundizar sobre las tareas a realizar en cada fase, precisemos más el concepto y significado de la palabra
algoritmo.
Un algoritmo es un método para resolver un problema mediante la combinación de una serie de pasos
precisos, definidos y finitos. Un algoritmo es preciso en el sentido que los pasos que lo componen deben
realizarse en un determinado orden y no en otro. Que sea definido implica que si se ejecuta varias veces el
mismo algoritmo sobre el mismo conjunto de datos de entrada, siempre se obtienen los mismos datos de
salida, es decir, el algoritmo es unívoco. Finalmente, que sea finito implica que debe finalizar después de un
número finito de pasos.
Un algoritmo debe producir un resultado en un tiempo finito. Los métodos que utilizan algoritmos se denominan
métodos algorítmicos, en oposición a los métodos que implican algún juicio o interpretación que se denominan
métodos heurísticos. Los métodos algorítmicos se pueden implementar en computadoras; sin embargo, los procesos
heurísticos no han sido
convertidos fácilmente en las computadoras. En los últimos años las técnicas de inteligencia artificial han hecho
posible la implementación del proceso heurístico en computadoras.
Entre las herramientas de que dispone el programador para una representación gráfica de un algoritmo destacan los
ordinogramas, diagramas de flujo de Nassi-Schneiderman y últimamente se utiliza con más frecuencia la
herramienta del pseudocódigo.