Está en la página 1de 121

Programación y

Algoritmia

Un enfoque práctico y didáctico


para el diseño de algoritmos

Lic. Oscar Ricardo Bruno, MDU


Agradecimientos
Para Cristi, Anto, Meli,
Euge, Gustavo, Nahuel, Esteban, Ornella, Yamila y
todos los estudiantes de UTN FRBA, USAL y el KRAUSE.

A mis amigos Carlos Tomassino, Jorge Muchnik, Marcelo Zanitti y Alicia Giorgetti y
Zulma Cataldi

A mis maestros Leopoldo Carranza,


Roberto Laborero,
Carlos Cullen
PROLOGO
Quien este prólogo escribe, lleva más de cuarenta años dedicado a la actividad
informática – cuando aún ni siquiera se llamaba informática! – habiéndose iniciado
como programador y vivido lidiando en todos los órdenes con los proyectos de estas
tecnologías, tanto desde la docencia como desde la gestión, en la actividad de campo y
la consultoría.

En aquellos lejanos tiempos, la programación era desarrollada con criterios más basados
en la intuición y la creatividad que en las metodologías.

Cuando con el devenir de las décadas las tecnologías fueron miniaturizándose y con
ello, consecuentemente, debieron bajarse los costos de los proyectos informáticos, los
programas de computación debieron a su vez volverse más cercanos a las realidades de
las épocas, y hubieron métodos que acercaron los costos de la programación a los
nuevos tiempos y esfuerzos.

Y si bien esto fue llevándose a la práctica con la aparición de las nuevas formas de la
Programación Estructurada durante los años ochenta, recién con la visión de Objetos,
sobre finales del milenio, puede aseverarse que estamos en el camino correcto, cual es el
de mezclar método con creatividad.

El libro “Programación y Algoritmia”que hoy se presenta describe con claridad de


conceptos todo lo que debe ser tenido en cuenta para que un programa de cualquier
índole y con independencia del lenguaje, termine exitoso.

Su autor, un estudioso y entrañable amigo, el Magister en Docencia Universitaria y


Licenciado Oscar Ricardo Bruno, vuelca en él su larga experiencia en este campo, tanto
en la Universidad Tecnológica Nacional, como en la Universidad del Salvador o la
Escuela Técnica Número 1 Otto Krause, y permite al lector alcanzar un alto nivel de
aprendizaje del manejo metodológico de la programación con las mejores técnicas.

Pero, tanto Bruno como quien esto escribe, sabemos la verdad revelada sobre el tema y
la debemos transmitir a los jóvenes lectores: “la programación solo se aprende en
gerundio: esto es, programando”. Por lo que debemos decirle que cuando Ud. se
encuentre ante el problema, sentado frente a la PC, recién allí sabrá cabalmente cómo
llevar el programa adelante, ya que las experiencias – a veces muy ricas en contenido -
no son traspasables.

En “Programación y Algoritmia” solo le suministramos las reglas: Ud deberá ver cómo


las aplica para llevar su programa a buen puerto. Buena suerte!
________________
Lic Carlos Tomassino
Presidente de Fundesco y
Director de la Cátedra Proyecto en la UTN - Facultad Regional Buenos Aires
Contenido
Conceptos básicos _____________________________________________________ 8
Introducción:_______________________________________________________ 8
Informática ________________________________________________________ 8
Programación ______________________________________________________ 8
Partes de un programa_______________________________________________ 9
Dato ______________________________________________________________ 9
Abstracción _______________________________________________________ 10
Modelizacion ______________________________________________________ 10
Precondición ______________________________________________________ 10
Poscondición ______________________________________________________ 10
Especificación _____________________________________________________ 10
Lenguaje de programación __________________________________________ 10
Del problema real a su solución por computadoras ______________________ 10
Características de un algoritmo ______________________________________ 13
Propiedades de los algoritmos ________________________________________ 14
Eficiencia de un algoritmo ___________________________________________ 14
Complejidades más comunes_________________________________________ 15
Léxico y algoritmo _________________________________________________ 15
Estructura de un algoritmo __________________________________________ 15
Proceso Computacional _____________________________________________ 16
Representaciones gráficas de algoritmos__________________________________ 21
Diagrama de Nassi-Sneiderman ______________________________________ 21
Diagramas de Jackson ______________________________________________ 21
Diagramas de Lindsay.______________________________________________ 22
Llaves de Warniel __________________________________________________ 23
Notación Algoritmica _______________________________________________ 23
Asignación - Control – Iteración ________________________________________ 24
Introducción:______________________________________________________ 24
Asignación, secuenciación y análisis de casos ___________________________ 24
Asignación. _______________________________________________________ 24
Análisis de casos ___________________________________________________ 25
La necesidad de iterar ______________________________________________ 29
Composiciones iterativas ____________________________________________ 30
Composiciones iterativas No Exactas __________________________________ 31
Composiciones iterativas Exactas _____________________________________ 31
Recursividad ______________________________________________________ 33
Iteración vs. Recursion______________________________________________ 34
Algoritmos que utilizan secuencias ____________________________________ 35
Estilos de Indentación ______________________________________________ 40
Acciones y Funciones _________________________________________________ 42
Introducción ______________________________________________________ 42
Modularizacion ____________________________________________________ 42
Módulos __________________________________________________________ 42
Alcance de los datos ________________________________________________ 43
Datos locales y globales _____________________________________________ 43
Ocultamiento y protección de datos ___________________________________ 43
Parámetros _______________________________________________________ 43
Integridad de los datos ______________________________________________ 43
Protección de datos_________________________________________________ 44
Uso de parámetros para retornar valores ______________________________ 44
Utilidad del uso de parámetros _______________________________________ 44
Reusabilidad ______________________________________________________ 44
Acciones __________________________________________________________ 44
Utilización de acciones ______________________________________________ 44
Acciones con parámetros ____________________________________________ 45
Abstracción y acciones ______________________________________________ 45
Tipos de Parámetros________________________________________________ 46
Beneficios del uso de acciones ________________________________________ 47
Funciones_________________________________________________________ 47
Estructuras Enlazadas_________________________________________________ 49
Introducción ______________________________________________________ 49
Estructuras enlazadas vs. estructuras indexadas ________________________ 49
Estructuras enlazadas con asignación dinámica en memoria ______________ 49
El tipo de dato Puntero______________________________________________ 51
Acceso a datos mediante apuntadores _________________________________ 53
Tipos de datos autorreferenciados o recursivos__________________________ 54
Estructuras de datos dinámicas lineales________________________________ 55
El tipo pila ________________________________________________________ 55
Insertar elemento en una pila:________________________________________ 57
Desapilar: leer y eliminar un elemento ________________________________ 57
El tipo cola________________________________________________________ 58
Añadir un elemento Encolar: ________________________________________ 58
Leer un elemento de una cola Eliminar primero: ________________________ 59
El tipo lista________________________________________________________ 59
Listas simplemente enlazadas ________________________________________ 59
Eliminar elementos en una lista ______________________________________ 60
Algoritmo de inserción ______________________________________________ 62
Listas circulares ___________________________________________________ 64
Operaciones básicas con listas circulares _______________________________ 65
Añadir un elemento ________________________________________________ 65
Eliminar un elemento de una lista circular _____________________________ 66
Listas doblemente enlazadas _________________________________________ 70
Operaciones básicas con listas doblemente enlazadas ____________________ 70
Añadir un elemento ________________________________________________ 70
Eliminar un elemento de una lista doblemente enlazada __________________ 73
A modo de síntesis con estructuras enlazadas ___________________________ 76
ALGORITMOS PUNTUALES __________________________________________ 77
Acciones y funciones para vectores____________________________________ 77
Acciones y funciones para archivos ___________________________________ 86
Acciones y funciones para pilas_______________________________________ 90
Acciones y funciones para Colas ______________________________________ 91
Acciones y funciones para Listas Ordenadas enlazadas ___________________ 92
Acciones y funciones para arboles ___________________________________ 101
Inserciones en arboles AVL _________________________________________ 106
Funciones recursivas ______________________________________________ 106
Archivos en pascal ________________________________________________ 109
Ejemplo en C con aplicaciones de estructuras enlzadas __________________ 114
ANEXO 1 Representaciones gráficas de algoritmos________________________ 116
Diagrama de Nassi-Sneiderman _____________________________________ 116
Diagramas de Jackson _____________________________________________ 116
Diagramas de Lindsay._____________________________________________ 117
Llaves de Warniel _________________________________________________ 118
Notación Algoritmica ______________________________________________ 118
Equivalencias entre notación algorítmica y lenguajes de programación ____ 119
Estilos de Indentación _____________________________________________ 119
BIBLIOGRAFIA ____________________________________________________ 121
Conceptos básicos
Objetivos de aprendizaje
Dominando los temas del presente capitulo Usted podrá.
1. Conocer la terminología propia de la disciplina.
2. Definir y comprender claramente conceptos específicos muchas veces mal
definidos
3. Comprender el valor de la abstracción.
4. Dar valor a la eficiencia en las soluciones
5. Introducirse en la notación algorítmica y a la forma e encarar los problemas de
programación

Introducción:
Se introducen conceptos fundamentales de algoritmia y programación, los que servirán
de base para el desarrollo de los temas a trataren materias de algoritmos y estructurad e
datos.

Informática
Disciplina del estudio sistematizado de los procesos algorítmicos que describen y
transforman información, su teoría, análisis, diseño, eficiencia, implementación y
aplicación.
La informática es una disciplina científica, matemática y una ingeniería; tiene tres
formas de pensar propias: Teoría, abstracción y diseño.
Las tres se complementan para la resolución de la mayoría de los problemas.
 Teoría: Con el pensamiento teórico se describen y prueban relaciones.
 Abstracción: Recolección de datos y formulación de un modelo, se eliminan los
detalles irrelevantes.
 Diseño: se tienen en cuenta requisitos, especificaciones y se diseñan o analizan
mecanismos para resolver problemas. Supone llevar a la práctica los resultados
teóricos.

Programación
La programación es una actividad transversal asociada a cualquier área de la
informática, aunque es la ingeniería del software el área específica que se ocupa de la
creación del software.
En principio la programación se veía como un arte, solo era cuestión de dominar un
lenguaje de programación y aplicar habilidades personales a la resolución de problemas,
casi en forma artesanal. El software era visto como algo desarrollado a través de la
intuición sin la utilización de métodos de diseño con técnicas para proceder en forma
sistemática y sin ningún control de su desarrollo. Con el reconocimiento de la
complejidad del desarrollo del software nació la ingeniería del software.
Se considero que al igual que cualquier otra disciplina la creación de software debía ser
reconocida como una actividad de ingeniería que requería la aplicación de sólidos
principios científicos.
La ingeniería del software es la disciplina que se ocupa de la aplicación del
conocimiento científico al diseño y construcción de programas de computación y a
todas las actividades asociadas de documentación, operación y mantenimiento, lo que
proporciona un enfoque sistemático.
La programación es una actividad en la que la creatividad juega un rol primordial
Programa:
Conjunto de instrucciones, ejecutables sobre una computadora, que permite cumplir una
función especifica. Se asocia al programa con una determinada función o requerimiento
a satisfacer por la ejecución del conjunto de instrucciones que lo forman. En general
alcanzan su objetivo en tiempo finito, aunque hay excepciones, por ejemplo los
programas de control de un sistema de alarma poseen requerimiento de tiempo infinito.
Un programa sin errores que se ejecuta puede no ser correcto si no cumple con los
requerimientos.

Definición
Programa: conjunto de instrucciones no activas almacenadas en un computador, se
vuelve tarea a partir de que se selecciona para su ejecución y permite cumplir una
función específica. Un proceso es un programa en ejecución.

En principio las tareas más importantes a la que se enfrenta quien debe escribir
programas en computadoras son:
1. Definir el conjunto de instrucciones cuya ejecución ordenada conduce a la
solución.
2. Elegir la representación adecuada de los datos del problema.
La función esencial del especialista informático es explotar el potencial de las
computadoras para resolver situaciones del mundo real. Para esto debe analizar los
problemas del mundo real, ser capaz de sintetizar sus aspectos principales y poder
especificar la función objetivo que se desee. Posteriormente debe expresar la solución
en forma de programa, manejando los datos del mundo real mediante una
representación valida para una computadora.

Partes de un programa
Los componentes básicos son las instrucciones y los datos. Las instrucciones o
sentencias representan las operaciones que se ejecutaran al interpretar el programa.
Todos los lenguajes de programación tienen un conjunto mínimo de operaciones que
son las de asignación, selección e iteración. Un lenguaje con solo estas tres
instrucciones permite escribir cualquier algoritmo.
Los datos son valores de información de los que se necesita disponer, en ocasiones
transformar para ejecutar la función del programa.
Los datos están representados simbólicamente por un nombre que se asocia con una
dirección única de memoria.
El contenido de la dirección de memoria correspondiente a un dato constante se asigna
solo una vez y solo puede ser modificado en una nueva compilación. En cambio el
contenido o valor de la dirección de memoria correspondiente a un dato variable puede
ser asignado o modificado en tiempo de ejecución.
Un programa se corresponde con una transformación de datos. A partir de un contexto
determinado por las precondiciones.
El programa transforma la información debiendo llegar al resultado esperado
produciendo el nuevo contexto caracterizado por las poscondiciones.

Dato
Representación de un objeto el mundo real mediante el cual se pueden modelizar
aspectos de un problema que se desea resolver con un programa en una computadora.
Definición
Dato representación de un objeto el mundo real mediante el cual se pueden modelizar
aspectos de un problema que se desea resolver con un programa en una computadora.
<dato> -> <objeto><atributo><valor>

Abstracción
Proceso de análisis del mundo real con el propósito de interpretar los aspectos
esenciales de un problema y expresarlo en términos precisos.

Modelizacion
Abstraer un problema del mundo real y simplificar su expresión, tratando de encontrar
los aspectos principales que se pueden resolver, requerimientos, los datos que se han de
procesar y el contexto del problema.

Precondición
Información conocida como verdadera antes de iniciar el programa.

Poscondición
Información que debiera ser verdadera al cumplir un programa, si se cumple
adecuadamente el requerimiento pedido.

Especificación
Proceso de analizar problemas del mundo real y determinar en forma clara y concreta el
objetivo que se desea. Especificar un problema significa establecer en forma univoca el
contexto, las precondiciones el resultado esperado, del cual se derivan las
poscondiciones.

Lenguaje de programación
Conjunto de instrucciones permitidas y definidas por sus reglas sintácticas y su valor
semántico para la expresión de soluciones de problemas.

Del problema real a su solución por computadoras


Analizando un problema del mundo real se llega a la modelización del problema por
medio de la abstracción.
A partir del modelo se debe elaborar el análisis de la solución como sistema, esto
significa la descomposición en módulos. Estos módulos deben tener una función bien
definida.
La modularización es muy importante y no solo se refiere a los procesos a cumplir, sino
también a la distribución de los datos de entrada, salida y los datos intermedios
necesarios para alcanzar la solución.

Estudio de los datos del problema.


Cada módulo debe tener un proceso de refinamiento para expresar su solución en forma
ordenada, lo que llevara a la construcción del algoritmo correspondiente.
A partir de los algoritmos se pueden escribir y probar programas en un lenguaje
determinado y con un conjunto de datos significativos.

Etapas de resolución de problemas con computadoras.


1. Análisis del problema: en su contexto del mundo real.
2. Diseño de la solución: Lo primero es la modularización del problema, es decir la
descomposición en partes con funciones bien definidas y datos propios
estableciendo la comunicación entre los módulos.
3. Especificación del algoritmo: La elección adecuada del algoritmo para la
función de cada modulo es vital para la eficiencia posterior.
4. Escritura del programa: Un algoritmo es una especificación simbólica que debe
convertirse en un programa real sobre un lenguaje de programación concreto.
5. Verificación: una vez escrito el programa en un lenguaje real y depurado los
errores sintácticos se debe verificar que su ejecución conduzca al resultado
deseado con datos representativos del problema real.

Programación modular – programación estructurada


Se dice modular porque permite la descomposición del problema en módulos y
estructurada solo permite la utilización de tres estructuras: Asignación, selección,
repetición.

Algoritmo
El termino algoritmo es en honor del matemático árabe del siglo IX, Abu Jafar
Mohamed ibn Musa Al Khowârizmî. Refiere conjunto de reglas, ordenadas de forma
lógica, finito y preciso para la solución de un problema, con utilización o no de un
computador.
En la actualidad al término se lo vincula fuertemente con la programación, como paso
previo a la realización de un programa de computación aunque en realidad es una
metodología de resolución presente en muchas de las actividades que se desarrolla a lo
largo de la vida.
Desde los primeros años de escuela se trabaja con algoritmos, en especial en el campo
de las matemáticas. Los métodos utilizados para sumar, restar, multiplicar y dividir son
algoritmos que cumplen perfectamente las características de precisión, finitud,
definición y eficiencia.
Para que el algoritmo pueda ser fácilmente traducido a un lenguaje de programación y
luego ser ejecutado la especificación debe ser clara, precisa, que pueda ser interpretada
con precisión y corresponda a pocas acciones, si esto no ocurre será necesario acudir a
desarrollar un mayor nivel de refinamiento.
La utilización de refinamientos sucesivos es lo que permite alcanzar la solución modular
que se propone.
Diseño modular, entonces, es la aplicación del criterio de refinamientos sucesivos,
partiendo de un plan de acción, determinando que hacer, por aplicación de los
conocimientos estratégicos de resolución pasando luego al como hacerlo con los
conocimientos tácticos para la realización del algoritmo.
La programación de algoritmos representa un caso de resolución de problemas que
requiere representación mental del mundo real, adaptación para tener una solución
computable y criterio para elegir una alternativa eficiente de implementación.
Cuando se analiza un problema, particularmente de programación, y éste es difícil de
describir, el plan de acción recomendable para alcanzar la solución es comenzar
trazando un esbozo de las formas más gruesas, para que sirvan de andamio a las demás;
aunque algunas de ellas se deban cambiar posteriormente. Después, se agregan los
detalles, (obteniéndose el algoritmo refinado), para dotar a estos esqueletos de una
estructura más realista.
Durante la tarea de integración final, se descartan aquellas primeras ideas provisionales
que ya no encajan en la solución. Por lo que, hasta que no se haya visto el conjunto
global es imposible encontrarle sentido a ninguna de las partes por sí solas.
Siempre es mejor explicar un misterio en términos de lo que se conoce, pero cuando
esto resulta difícil de hacer, se debe elegir entre seguir tratando de aplicar las antiguas
teorías, o de descartarlas y probar con otras nuevas. Siguiendo este análisis, se define
como reduccionistas a aquellas personas que prefieren trabajar sobre la base de ideas
existentes, y como renovadores a los que les gusta impulsar nuevas hipótesis. En
programación debe encontrarse un equilibrio entre ambas posturas.
La programación como toda actividad que requiere creatividad necesita que se produzca
un salto mental que se puede sintetizar como señala David Perkins en:
1. Larga búsqueda, se requiere esfuerzo en analizar y buscar.
2. Escaso avance aparente: el salto mental sobreviene tras un avance que parece
escaso o no muy evidente, pero sobreviene.
3. Acontecimiento desencadenante: El típico proceso de hacer clic comienza con
un acontecimiento que lo desencadena.
4. Chasquido cognitivo: De pronto aparece la solución la que sobreviene con
rapidez que hace que las piezas encajen con precisión, aun cuando sea necesario
todavía ajustar algunos detalles. Pero la idea generadora apareció.
5. Transformación. Este avance nos va modificando nuestro mundo mental.
En síntesis, la practica del salto de pensamiento requiere en primer lugar de buscar
analogías, en segundo lugar juegan un papel importante las conexiones lógicas,
formulación de una pregunta crucial ocupa un papel decisivo. El repertorio de acciones
tras el salto del pensamiento se expande para incluir no solo la analogía sino una
extrapolación lógica y la formulación de la pregunta adecuada
Para encontrar una solución muchas veces se necesita desplazarse bastante por el
entorno adecuado. Conforme a esto Thomas Edison declaro que la invención significa
99% de transpiración y 1% de inspiración, en contraposición con Platón que sostenía
que las soluciones aparecen por inspiración divina.
Muchos problemas son razonables, cabe razonarlos paso a paso para alcanzar la
solución. Otros son irrazonables no se prestan a un a reflexión por etapas.

Definición
Algoritmo
Especificación rigurosa (debe expresarse en forma univoca) de la secuencia de pasos,
instrucciones, a realizar sobre un autómata para alcanzar un resultado deseado en un
tiempo finito. Esto último supone que el algoritmo empieza y termina, en el caso de los
que no son de tiempo finito (ej. Sistemas en tiempo real) deben ser de número finito de
instrucciones.

En definitiva un algoritmo es una especificación ordenada de la solución a un problema


de la vida real. Son el fundamento de la programación de computadores en el paradigma
de programación imperativo.
Bajo este paradigma desarrollar un programa significa indicarle al computador, con
precisión, sin ambigüedad y en un lenguaje que este pueda entender, todos y cada uno
de los pasos que debe ejecutar para lograr el objetivo propuesto.
Previo a la traducción en un lenguaje de programación es necesario poder entender el
problema, conocer las pre condiciones, establecer cual debe ser la pos condición, o
aquello que debe ser cierto al finalizar la ejecución del algoritmo, en definitiva entender
claramente Que es lo que se debe hacer para luego avanzar en Como hacerlo. Aquí
debe utilizarse todas las herramientas al alcance de la mano para el desarrollo del
algoritmo como paso previo a la solución del problema por el computador.
Existen varias técnicas para representar formalmente un algoritmo, una descriptiva
llamada pseudo código, y otras graficas como los diagrama de flujo, diagrama Nassi
Sneiderman, Diagramas de Lindsay, diagramas de Jackson, entre otros, en este caso se
presentara una notación algorítmica similar a la presentada por Piere Scholl en el texto
Esquemas algorítmicos fundamentales: Secuencia e iteración.

Definición
Algoritmo:
Secuencia finita de instrucciones, reglas o pasos que describen en forma precisa las
operaciones que una computadora debe realizar para llevar a cabo una tarea en tiempo
finito [Knuth, 1968].
Descripción de un esquema de comportamiento expresado mediante un repertorio finito
de acciones y de informaciones elementales, identificadas, bien comprendidas y
realizables a priori. Este repertorio se denomina léxico[Scholl, 1988].
Esta formado por reglas, pasos e instrucciones.
Las reglas especifican operaciones.
La computadora es el agente ejecutor.
La secuencia de reglas y la duración de la ejecución son finitas.

Características de un algoritmo
Un algoritmo debe tener al menos las siguientes características:
1. Ser preciso: esto significa que las operaciones o pasos del algoritmo deben
desarrollarse en un orden estricto, ya que el desarrollo de cada paso debe
obedecer a un orden lógico.
2. Ser definido. Ya que en el área de programación, el algoritmo es el paso
previo fundamental para desarrollar un programa, es necesario tener en cuenta
que el computador solo desarrollará las tareas programadas y con los datos
suministrados; es decir, no puede improvisar y tampoco inventará o adivinará el
dato que necesite para realizar un proceso. Por eso, el algoritmo debe estar
plenamente definido; esto es, que cuantas veces se ejecute, el resultado depende
estrictamente de los datos suministrados. Si se ejecuta con un mismo conjunto
de datos de entrada, el resultado deberá ser siempre el mismo.
3. Ser finito: esta característica implica que el número de pasos de un algoritmo,
por grande y complicado que sea el problema que soluciona, debe ser limitado.
Todo algoritmo, sin importar el número de pasos que incluya, debe llegar a un
final. Para hacer evidente esta característica, en la representación de un
algoritmo siempre se incluyen los pasos inicio y fin.
4. Presentación formal: para que el algoritmo sea entendido por cualquier persona
interesada es necesario que se exprese en alguna de las formas comúnmente
aceptadas; pues, si se describe de cualquier forma puede no ser muy útil ya que
solo lo entenderá quien lo diseñó. Las formas de presentación de algoritmos
son: el pseudo código, diagrama de flujo y diagramas de Nassi/Schneiderman,
entre otras. En esta publicación se propondrá una notación algorítmica y se
darán las equivalencias entre la propuesta y las existentes y también con las
sentencias de los lenguajes de programación, en particular Pascal y C.
5. Corrección: el algoritmo debe ser correcto, es decir debe satisfacer la necesidad
o solucionar el problema para el cual fue diseñado. Para garantizar que el
algoritmo logre el objetivo, es necesario ponerlo a prueba; a esto se le llama
verificación o prueba de escritorio.
6. Eficiencia: hablar de eficiencia o complejidad de un algoritmo es evaluar los
recursos de cómputo que requiere para almacenar datos y para ejecutar
operaciones frente al beneficio que ofrece. En cuanto menos recursos requiere
será más eficiente el algoritmo.
La vida cotidiana está llena de soluciones algorítmicas, algunas de ellas son tan
comunes que no se requiere pensar en los pasos que incluye la solución. La mayoría de
las actividades que se realizan diariamente están compuestas por tareas más simples que
se ejecutan en un orden determinado, lo cual genera un algoritmo. Muchos de los
procedimientos utilizados para desarrollar tareas cotidianas son algorítmicos, sin
embargo, esto no significa que todo lo que se hace está determinado por un algoritmo.
El primer paso en el diseño de un algoritmo es conocer la temática a tratar, el segundo
será pensar en las actividades a realizar y el orden en que deben ejecutarse para lograr el
objetivo, el tercero y no menos importante es la presentación formal.

Propiedades de los algoritmos


1. Especificación precisa de la entrada: El algoritmo debe dejar claro el número y
tipo de datos de entrada y las condiciones iniciales que deben cumplir esos
valores de entrada para conseguir que las operaciones tengan éxito.
2. Especificación precisa de cada instrucción: cada etapa del algoritmo debe estar
definida con precisión, no debe haber ambigüedades sobre las acciones que se
deben ejecutar en cada momento.
3. Un algoritmo debe ser exacto y correcto: Un algoritmo se espera que resuelva un
problema y se debe poder demostrar que eso ocurre. Si las condiciones de
entrada se cumplen y se ejecutan todos los pasos el algoritmo entonces debe
producir la salida deseada.
4. Un algoritmo debe tener etapas bien definidas y concretas, un número finito de
pasos, debe terminar y debe estar claro la tarea que el algoritmo debe ejecutar.
5. Debe ser fácil de entender, codificar y depurar.
6. Debe hacer uso eficiente de los recursos de la computadora

Finitud: en longitud y duración.


Precisión: Determinar sin ambigüedad las operaciones que se deben ejecutar.
Efectividad: las reglas pueden ejecutarse sin el ordenador obteniéndose el mismo
resultado.
Generalidad: Resolver una clase de problema y no un problema particular.
Entradas y salidas: puede tener varias entradas pero una sola salida, el resultado que se
debe obtener.

Eficiencia de un algoritmo
Se pueden tener varias soluciones algorítmicas para un mismo problema, sin embargo el
uso de recursos y la complejidad para cada una de las soluciones puede ser muy
diferente.
La eficiencia puede definirse como una métrica de calidad de los algoritmos asociada
con la utilización optima de los recursos del sistema de cómputo donde se ejecutara el
algoritmo, su claridad y el menor grado de complejidad que se pueda alcanzar. Hacer
todo tan simple como se pueda, no más (Albert Einstein).
La eficiencia como factor espacio temporal debe estar estrechamente relacionada con la
buena calidad, el funcionamiento y la facilidad del mantenimiento.
Medidas de eficiencia para N = 10.0000
Eficiencia Iteraciones Tiempo estimado
Logarítmica Log 2 N 14 Microsegundos
Lineal N 10.000 0.1 segundo
Logarítmica lineal N * Log 2 N 140.000 2 segundos
Cuadrática N2 10.000 2 15-20 minutos
Poli nómica Nk 10.000 K Horas
Exponencial 2N 2 10.000 Inmedible

Complejidades más comunes


1. Complejidad constante: se expresa como O(1). Se encuentra en algoritmos sin
ciclos, por ejemplo en un intercambio de variables.
2. Complejidad logarítmica: Es una complejidad eficiente, la búsqueda binaria
tiene esta complejidad.
3. Complejidad lineal: se encuentra en los ciclos simples.
4. Complejidad logarítmica lineal: Los mejores algoritmos de ordenamiento tienen
esta complejidad.
5. Complejidad cuadrática: Aparece en el manejo de matrices de dos dimensiones,
generalmente con dos ciclos anidados.
6. Complejidad cúbica: Aparece en el manejo de matrices de tres dimensiones,
generalmente con tres ciclos anidados.
7. Complejidad exponencial: es la complejidad de algoritmos recursivos.

Léxico y algoritmo
Para escribir un algoritmo deben seguirse un conjunto de pasos básicos
1. Comprender el problema
2. Identificar los elementos a incluir en el léxico: constantes, tipos, variables y
acciones.
3. Encontrar la forma de secuenciar las acciones para obtener el resultado, esto es,
alcanzar las poscondiciones a partir de un estado inicial que cumple con la
precondición. Para establecer el orden de las acciones los lenguajes de
programación proporcionan mecanismos de composición: Secuenciación,
análisis de casos, iteración y recursion.
4. Al organizar las acciones en el tercer paso puede ocurrir que se detecte que
faltan elementos en el léxico o que algún aspecto del problema no ha sido bien
comprendido lo cual requeriría volver a los pasos anteriores.
5. Nunca la solución aparece en el primer intento, en general aparece en un proceso
cíclico, entonces se debe:
6. Escribir el léxico,
a. escribir la primera versión,
b. incluir en el léxico nuevos elementos que faltaban,
c. escribir la nueva versión del algoritmo y así sucesivamente

Estructura de un algoritmo
LEXICO {Léxico Global del algoritmo}
{Declaración de tipos, constantes, variables y acciones}
Acción 1
PRE {Precondición de la acción 1}
POS {Poscondición de la acción 1}
LEXICO {Léxico local, propio de la acción 1}
Declaraciones locales
ALGORITMO {Implementación de la acción 1}
{Secuencia de instrucciones de la acción 1}
FIN {Fin implementación algoritmo de la acción 1}

ALGORITMO
PRE {Precondición del algoritmo principal}
POS {Poscondición del algoritmo principal}
{Secuencia de instrucciones del algoritmo principal}
FIN {Fin del algoritmo principal}

Proceso Computacional
Se refiere a un algoritmo en ejecución. La ejecución de las instrucciones origina una
serie de acciones sobre elementos de memoria que representan información manejada
por el algoritmo. A nivel algorítmico se asigna un nombre a cada información de modo
de manejar un par nombre-valor para cada información.
Una variable representa alguna entidad del mundo real, relevante para el problema que
se quiere resolver. El efecto que producen las acciones del proceso sobre las variables
produce cambio de estados o de sus valores.

Definiciones

Programa: Algoritmo escrito en un lenguaje cuyas instrucciones son ejecutables por


una computadora y que están almacenados en un disco.
Tarea: Un programa se vuelve tarea a partir del momento que se lo selecciona para su
ejecución y hasta que esta termina.
Proceso: programa en ejecución, se ha iniciado pero aún no ha finalizado.
Lenguajes de programación: notación que permite escribir programas a mayor nivel
de abstracción que los lenguajes de máquina. Sus instrucciones deben ser traducidas a
lenguaje de máquina.
Lenguaje de máquina: Instrucciones que son ejecutables por el hardware de una
computadora.
Paradigmas de programación
Paradigma: Colección de conceptos que guían el proceso de construcción de un
programa. Estos conceptos controlan la forma en que se piensan y formulan los
programas.
Imperativo – Procedural – Objetos.
Declarativo – Funcional – Lógico.
Dato Información Conocimiento
Dato: <objeto><atributo><valor> sin interpretar.
Información: añade significado al dato.
Conocimiento: Añade propósito y capacidad a la información. Potencial para generar
acciones.
Problema
Enunciado con una incógnita, la solución es encontrar el valor de esa incógnita.
Problema computacional o algorítmico: tarea ejecutada por una computadora con una
especificación precisa de los datos de entrada y de los resultados requeridos en función
de estos.
Clase de problemas
No computables: No existe un algoritmo.
Computables
Tratables: Existe un algoritmo eficiente.
Intratable: No existe algoritmo eficiente.
Expresiones Sentencias Léxico
Expresiones: secuencia de operadores y operandos que se reduce a un solo valor.
Sentencias: acción produce un efecto, puede ser primitiva o no primitiva.
Léxico: Descripción del conjunto de acciones e informaciones a partir de la cual se
expresa el esquema de comportamiento del algoritmo.

Pasos para resolver un algoritmo


Comprender el problema.
Identificar información y acciones a incluir en el léxico (constantes, tipos, variables y
acciones).
Encontrar un camino de secuenciar las acciones para obtener el resultado, es decir para
alcanzar la poscondición a partir del estado inicial que cumple con la precondición.
Acciones primitivas y derivadas
Acciones primitivas: Incorporadas por el lenguaje.
Acciones derivadas: realizadas mediante la combinación de acciones primitivas con el
objeto de desarrollar una tarea en particular. Son complementarias y pueden ser
desarrolladas por el programador.

Estructura de un algoritmo
LEXICO {Léxico Global del algoritmo}
{Declaración de tipos, constantes, variables y acciones}
Acción 1
PRE {Precondición de la acción 1}
POS {Poscondición de la acción 1}
LEXICO {Léxico local, propio de la acción 1}
Declaraciones locales
ALGORITMO {Implementación de la acción 1}
{Secuencia de instrucciones de la acción 1}
FIN {Fin implementación algoritmo de la acción 1}

ALGORITMO
PRE {Precondición del algoritmo principal}
POS {Poscondición del algoritmo principal}
{Secuencia de instrucciones del algoritmo principal}
FIN {Fin del algoritmo principal}
Resumen:
En el presente capitulo se introdujeron términos y frases de la disciplina en estudio.
Se abordo el problema desde un punto de vista conceptual definiendo con precisión
términos y frases para evitar ambigüedades. Se puso especial énfasis en la necesidad de
pensar las soluciones antes de escribir código. Se establecieron cuales son los pasos que
deben seguirse para una solución correcta de problemas y cuales son los problemas que
pueden tratarse en forma algorítmica. Se definió cuales son las características deseables
de los algoritmos y se introdujo el concepto de eficiencia de modo de hacer, tal como
recomendaba Albert Enstein, las cosas tan simple como se pueda.
Se introdujo, además una representación sem. formal para la descripción de los
algoritmos
Representaciones gráficas de algoritmos
Diagrama de Nassi-Sneiderman

Condición 1

T F

Acción 1 Acción 5
Acción 2 Mientras condición 3
Condición 2 Acción 6
T F
Acción 7
Acción 3
Acción 8
Acción 4 Acción 9
Acción 10
Acción 11
Acción 12

Repetir hasta condición 4

Diagramas de Jackson
Diagramas de Lindsay.

PASCAL DIAGRAMA DE DETALLE

Variable = expresión Variable ← expresión

READ (var1, var2,....var n) var1, var2,....

WRITELN var 1 var 2 var 1 var 2


(ó ó , ..... ) ó ó ,....
WRITE liter1 liter2 liter1 liter2

IF condición
THEN Condición
sentencia 1
ELSE Instrucción 1 Instrucción 2
sentencia 2

WHILE condición Condición


DO
sentencia Instrucción

REPEAT
sentencia; Instrucción 1
: :
: :
sentencia n Instrucción n
Condición
UNTIL condición

FOR variable: expres1 TO expres2


ó Instrucción
Var: exp1, exp2
DOWNTO
DO sentencia

CASE expresión
OF Expresión
const1....... const n : instrucción1
Const1... Const n Const1... Const p
:
: Instrucción1 Instrucción m
const1...... const p : instrucción m
END
Cualquier sentencia puede ser reemplazada por Correspondiendo en el diagrama de detalle
un bloque: BEGIN la secuencia:
sentencias 1; instrucción 1;
: :
: :
sentencias n instrucción n
END
Llaves de Warniel

HacerUnaCosa)
Si HacerOtraCosa

Condición Exclusión

No Vacio
Algoritmo 1
Case
Ordinal 2
HacerUnaCosa;
Mientras HacerOtraCosa;
Condición HacerAlgoMas

Notación Algoritmica
LEXICO {Léxico Global del algoritmo}
{Declaración de tipos, constantes, variables y acciones}
Acción 1
PRE {Precondición de la acción 1}
POS {Poscondición de la acción 1}
LEXICO {Léxico local, propio de la acción 1}
Declaraciones locales
ALGORITMO {Implementación de la acción 1}
{Secuencia de instrucciones de la acción 1}
FIN {Fin implementación algoritmo de la acción 1}

ALGORITMO
PRE {Precondición del algoritmo principal}
POS {Poscondición del algoritmo principal}
{Secuencia de instrucciones del algoritmo principal}
FIN {Fin del algoritmo principal}
Asignación - Control – Iteración

Objetivos de aprendizaje
Dominando los temas del presente capitulo Usted podrá.
1. Conocer las acciones simples que permiten capturar o mostrar los datos.
2. Encontrar en la secuenciación el camino simple para la resolución de problemas
3. Dividir el dominio de los datos en subdominios excluyentes y abarcativos.
4. Descubrir la necesidad de la repetición.
5. Verificar que es posible repetir acciones en formas diferentes y para distintos
conjunto de secuencias.

Introducción:
Se presenta en este trabajo un primer criterio de descomposición del problema para
poder alcanzar la solución del mismo. Se establece la secuenciación y el análisis de
casos como primer mecanismo correcto para la solución de problemas.
Habitualmente se observa que aquellos jóvenes que se acercan por primera vez a la
resolución de problemas de programación encuentran muchas dificultades para
organizar su pensamiento y encontrar una solución algorítmica.
No es simple comprender como se razona cuando se diseña un algoritmo o cual es el
mecanismo que permite extraer de nuestro conocimiento la técnica que nos guíe a la
solución de los mismos.
Una de las técnicas que se dispone para dominar la complejidad de los problemas es la
descomposición en subproblemas que pueden abordarse por separado, utilizando una de
las premisas básicas en la programación que es “dividir para vencer”. Cada problema
puede entonces verse como un conjunto de módulos, vinculados y relacionados
adecuadamente. Estos módulos utilizan mecanismos como la secuenciación, análisis de
casos, composiciones iterativas exactas, condicionales y recursivas para alcanzar la
solución.

Asignación, secuenciación y análisis de casos


Las instrucciones o sentencias representan las operaciones que ejecuta la computadora
al implementar un algoritmo. Estas instrucciones utilizan cierta información en forma de
expresiones que se resumen en un valor y que pueden ser constantes o variables.
Todos los lenguajes de programación tienen un conjunto mínimo de instrucciones que
son asignación, análisis de casos y repeticiones.

Asignación.
Asignar significa almacenar valores, constantes o variables, en una determinada
dirección de memoria, este valor puede ser almacenado desde una instrucción del
programa u obtenido o derivado hacia algún dispositivo externo.

Asignación Interna. Almacenar un valor desde una instrucción del programa.


NombreDelIdentificador  Valor;
Almacena en NombreDelIdentificador el valor. Valor puede corresponder a un dato
simple o a una expresión (operadores y operandos) la precondición es que el tipo de
dato de valor debe corresponder al del identificador.

Asignación Externa de entrada.


Almacena en una dirección de memoria un valor obtenido desde un dispositivo o flujo
de datos externo, el dispositivo estándar es el teclado pero es posible obtener datos
almacenados en archivos, en general esta acción recibe el nombre de leer.

Agnación externa de salida.


Obtiene el valor contenido en una dirección de memoria y lo envía o deriva a algún
dispositivo o flujo externo. El dispositivo estándar es la pantalla pero la salida puede ser
direccionada a la impresora o un archivo (esta acción se llama grabar en un archivo).

Análisis de casos
Al no ser posible resolver problemas con instrucciones secuenciales puras, muchas
veces es necesario tener que tomar decisiones en función de los datos del problema,
para ello se cuentan con instrucciones que permiten analizar alternativas y decidir que
camino seguir en cada caso.

Estructura de decisión Simple. Es la estructura básica de decisión entre dos


alternativas. Evalúa una expresión condicional o condición. Entendiéndose por
expresión condicional aquella expresión en la que tiene sentido preguntar por su valor
de verdad. Es una afirmación que puede ser verdadera o falsa y se establecen con
identificadores vinculados con valores o expresiones a través de operadores de relación
con igual, mayor, menor, menor o igual, mayor o igual o distinto.

Estructura de decisión simple Incompleta. Solo procesa acciones en el caso de ser


verdadero el resultado de la expresión, no procesa instrucciones en el caso de ser falsa.

Formato Efecto
SI Condición Si la expresión toma el valor verdadero entonces se ejecuta
ENTONCES la secuencia S si es falso ejecuta la acción siguiente a la
S instrucción en caso de existir.
FIN_SI

Estructura de decisión simple completa. Procesa acciones por la condición de


verdadera y acciones distintas en caso de ser falso.

Formato Efecto
SI Condición Si la expresión toma el valor verdadero entonces se ejecuta
ENTONCES la secuencia S si es falso se ejecuta la secuencia R.
S
SI_NO
R
FIN_SI

Estructura de decisión Múltiple. Es una estructura de selección entre varios valores,


estos valores deben corresponder a variables de tipo ordinal y se pueden determinar
acciones distintas según los valores del ordinal. Pueden reemplazar en forma eficiente a
estructuras de decisión simple que evalúan expresiones booleanas anidadas que con
tipos de datos ordinales (caracteres o enteros).

Estructuras de decisión múltiple Incompleta. Solo realiza acciones para la lista de


valores determinada. No realiza acción en caso de que el ordinal no corresponda a un
valor definido.
Formato Efecto
SEGÚN expr Según el valor Vi de la expresión ordinal expr, se ejecuta la
V1 : S1 secuencia Si(i = 1 ..n). Cualquier valor no especificado no
V2 : S2 tiene acción asociada
FIN_SEGÚN

Estructura de decisión múltiple Completa. Agrega una cláusula para realizar acciones
particulares en caso de que el ordinal no se corresponda con ninguno de los valores
determinados.

Formato Efecto
SEGÚN expr Según el valor Vi de la expresión ordinal expr, se ejecuta la
V1 : S1 secuencia Si(i = 1 ..n). Cualquier valor no especificado
V2 : S2 realiza la secuencia Sn.
EN_OTRO_CASO : Sn
FIN_SEGÚN

Ejemplos con uso de acciones primitivas de asignación, entrada- salida y


declaraciones de acciones y léxico

Calculo de la nota final de una materia


LEXICO
NotaPrimerParcial : Real
NotaSegundoParcial: Real
NotaTrabajoPractico: Real
NotaFinal: Real
ALGORITMO
Leer(NotaPrimerParcial, NotaSegundoParcial, NotaTrabajoPractico)
NotaFinal  (NotaPrimerParcial + NotaSegundo Parcial) / 2
Mostrar(NotaFinal, NotaTrabajoPractico)
FIN

Conversión de grados Fahrenheit en grados Celcius


LEXICO
TempFahrenheit : Real {dato la temperatura en grados Fahrenheit}
TempCelcius: Real {Resultado, temperatura en grados celsius}
CERO_ABSOLUTO = -459.58 {Constante el cero absoluto de temperatura}
ConvertirFahrenheitCelcius : UnaAccion
PRE {TempFaherenheit >= CERO_ABSOLUTO}
POS {Convierte a grados Celsius la Temperatura TempFahrenheit}
ALGORITMO
TempCelcius  (5.0 /9.0) * TempFahrenheit – 32.0)
FIN.
ALGORITMO
Ler(TempFahrenheit)
ConvertirFahrenheitCelcius
Escribir(“La temperatura es :”, TempCelcius
FIN
Ejemplos con análisis de casos
PROBLEMA: Desarrollar un programa que simule una calculadora simple. Que
ingrese dos operandos y un operador. Según el operador que muestre la suma, resta,
multiplicación o división
El analisis de caso no evalua la posibilidad de
LEXICO en otro caso, por lo tanto se deber cumplir
Operando1, Operando2 : Entero; con la precondición que el operador debe
Operador : Carácter; estar entre uno de los caracteres validos. El
operador de division que se utiliza s el
ALGORITMO operador div que retorna la parte entera de la
Leer (Operando1, Operando2, Operador); division de dos enteros
SEGÚN Operador
Operador = ´+´ : Escribir (Operando1 + Operando2)
Operador = ´-´ : Escribir (Operando1 - Operando2)
Operador = ´*´ : Escribir (Operando1 * Operando2)
Operador = ´/´ : Escribir (Operando1 Div Operando2)
FIN_SEGUN
FIN

Solución alternativa utilizando acción en otro caso


LEXICO En este caso se realizan acciones en caso
Operando1, Operando2 : Entero; que el operador sea distinto a los
Operador : Carácter; permitidos, por lo que si no se cumple con
la precondición es el programa quien
ALGORITMO informa de una situación irregular o no
Leer (Operando1, Obrando, Operador); deseada
SEGÚN Operador
Operador = ´+´ : Escribir (Operando1 + Operando2)
Operador = ´-´ : Escribir (Operando1 - Operando2)
Operador = ´*´ : Escribir (Operando1 * Operando2)
Operador = ´/´ : Escribir (Operando1 Div Operando2)
EN_OTRO_CASO : Escribir(“Operador no valido”)
FIN_SEGUN
FIN.

PROBLEMA: Comprobar si una fecha es correcta

LEXICO
dia, mes, año : Entero >0 ;
EsBisiesto, FechaValida : Booleano ;
AñoBisiesto : una acción
POST {AñoBisiesto V si año es bisiesto F en caso contrario}
ALGORITMO
EsBisiesto  (año Mod 400 = 0) o ((año Mod = 0)y(año mod 100<>0))
FIN AñoBisiesto
ALGORITMO
Leer (dia, mes, año);
SI (dia < 1 )
ENTONCES FechaValida  Falso
SI_NO
SEGÚN mes
mes = 1,3,5,7,8,10,12 : FechaValida  dia <= 31
// si los meses son los que se enumeran y el dia menor o igual a 31 es valida//
mes = 4,6,9,11 : FechaValida  dia <= 30
//en estos meses para ser valida el dia debe ser menor o igual a 30//
mes = 2 : AñoBisiesto; FechaValida dia <=28 o (AñoBisiesto y
dia<=29)
// en febrero debe verificar si el año es o no bisiesto//
EN_OTRO_CASO : FechaValida  Falso
// de no ocurrir nada de lo anterior, la fecha es falsa, no es una fecha valida//
FIN_SEGUN
FIN_SI
Escribir (´La fecha ´, dia, ´/´, mes,´/´.año, ´ : ´);
SI FechaValida
ENTONCES Escribir (“Es Valida”)
SI_NO Escribir(“No es valida”)
FIN_SI
FIN

A los efectos de simplificar la notación de los análisis de casos en una única forma de
escritura se podría utilizar la notación SI, con las variantes que correspondan y con la
sentencia equivalente según el lenguaje de programación.[J.D. Muchnik]

Formato Propuesta JDM


SI Condición Si Condición
ENTONCES S
S FIN_SI
FIN_SI

Formato Propuesta JDM


SI Condición SI
ENTONCES Condicion1 S;
S Condicion2 R;
SI_NO FIN_SI
R
FIN_SI

Formato Propuesta JDM


SEGÚN expr SI
V1 : S1 Condicion1 S1;
V2 : S2 Condicion2 S2;
FIN_SEGÚN FIN_SI

Formato Propuesta JDM


SEGÚN expr SI
V1 : S1 Condicion1 S1;
V2 : S2 Condicion2 S2;
EN_OTRO_CASO : Sn CondicionB Sn;
FIN_SEGÚN FIN_SI

Solución alternativa utilizando la propuesta Jorge Muchnik [JDM]


LEXICO
Operando1, Operando2 : Entero;
Operador : Carácter;
ALGORITMO
Leer (Operando1, Oprando, Operador);
SI
(Operador = ´+´) Escribir (Operando1 + Operando2);
(Operador = ´-´) Escribir (Operando1 - Operando2);
(Operador = ´*´) Escribir (Operando1 * Operando2)
(Operador = ´/´) Escribir (Operando1 Div Operando2)
FIN_SI
FIN.

La necesidad de iterar
Supongamos que de un determinado curso se dispone de cada uno de los alumnos de su
nota y se requiere conocer la nota promedio del curso.
Para ello será necesario conocer la nota de cada estudiante, se debe saber además la
suma de todas las notas de los estudiantes y, para calcular el promedio, es
imprescindible conocer la cantidad de estudiantes.
Podríamos pensar en un algoritmo con una estructura como la siguiente
LÉXICO
V : Real //Contiene la nota leída
S : Real //Contiene la sumatoria de las notas
N : Entero //Contiene el numero de alumnos
ALGORITMO
S <- 0 ;
N <- 0 ;
Leer (V) ;
S <- S + V ; //Suma las notas
N <- N + 1 ; // Cuenta los alumnos
Este bloque debe repetirse una cantidad de veces que no se puede determinar con
precisión, seria necesario escribir un texto diferente para cada caso particular, hasta
podría llegarse al extremo de tener que escribir un texto infinito, cosa imposible en la
implementación. El infinito se lo puede pensar desde un punto de vista teórico pero no
es posible implementarlo. Habíamos mencionado entre las características de los
algoritmos su finitud en tiempo y en instrucciones.
La necesidad de un mecanismo de iteración es clara si pensamos en computadoras como
maquinas de gran utilidad porque automatizan tareas, si solo se dispusiera de
composición secuencial o análisis de casos estaríamos realmente limitados y los
programas deberían tener una gran extensión para ejecutar muy pocas acciones si estas
se repiten.

Secuencias
Algunas operaciones tienen que ver con secuencia de datos. Una secuencia es una
colección de elementos del mismo tipo. En ella se puede aplicar algún tratamiento a
cada uno de los elementos que componen la secuencia o buscar alguno que cumpla con
cierta propiedad.
Las secuencias pueden representarse de diferentes formas y se caracteriza por el acceso
secuencial a cada elemento. Esto es, para acceder al elemento de la posición p, hay que
recorrer los p-1 elementos anteriores.
La secuencia debe contar con un elemento característico que indique que se ha
alcanzado el final de la misma en forma correcta. Esta marca puede determinarse según
una especificación precisa de la cantidad de elementos o por un valor particular que
indique la finalización. Las secuencias están vinculadas con las composiciones iterativas
y la reursion

Composiciones iterativas
Los componentes de una iteración son
1. Inicialización: instrucciones que se ejecutan para inicializar las variables que
participan de la iteración.
2. Condición de terminación: expresión booleana que determina cuando acaba la
iteración.
3. Cuerpo: conjunto de instrucciones que se ejecutan mientras no se cumple la
condición de terminación.
4. Finalización: conjunto de instrucciones que deben ejecutarse cuando la iteración
termina.
Se presentan dos composiciones iterativas en las que la finalización viene determinada
por una condición. Estas son la composición MIENTRAS, REPETIR. Lo que las
diferencia es el lugar donde se comprueba la condición: al principio o al final. Y
también si es una condición de terminación o de continuación. Existe además
composiciones iterativas en la que la finalización esta dada por la cantidad de elementos
que se deben evaluar

Diseño iterativo: noción de invariante


El invariante de un ciclo, INV, es una condición que se cumple al inicio y a cada paso de
la iteración. Cuando finaliza la iteración, el hecho de que se satisfaga el invariante y la
condición de terminación implica que se alcanzó la solución.
Dada una especificación de un problema de recorrido de secuencias, la estrategia de una
solución iterativa consta de los siguientes pasos:
1. Identificar qué variables son necesarias a partir de la poscondición.
2. Establecer el invariante del ciclo.
3. Aplicar un razonamiento inductivo.
4. Escribir el algoritmo iterativo.
La composición iterativa es el medio que permite escribir programas cortos que
involucran gran cantidad de acciones.
Existen varios formatos de iteración que varían entre lenguajes pero que, en general
responden a tres modelos de repetición: repetir mientras se cumpla una condición,
repetir hasta que se cumpla una condición y repetir una determinada cantidad de veces
Repetir mientras se cumpla una condición
MIENTRAS condición HACER
Acción
FIN_MIENTRAS
Repetir hasta que se cumpla una condición
REPETIR
acción
HASTA_QUE Condición
Repetir N veces
PARA i [1..n] HACER
acción
FIN_PARA
Composiciones iterativas No Exactas
No exacta o condicionales. Como vimos con las composiciones mientras y repetir,
puede ocurrir que un bloque de instrucciones se deba ejecutar desconociendo el numero
exacto de veces, en estos casos los lenguajes ofrecen estructuras de control iterativas
condicionales en las que las acciones se ejecutan dependiendo de la evaluación de una
condición.
Precondicionales

Formato Efecto
Mientras Cond. Hacer Ejecutar la secuencia S mientras la condición Cond tenga
S el valor de verdadero
FIN_MIENTRAS

Pre-condicionales. Estas evalúan la condición y si es verdadera se ejecuta el bloque de


acciones. Esto hace que dicho bloque pueda ejecutarse 0, 1, o varias veces. Es necesario
una asignación previa a la variable de la expresión lógica para poder evaluarla y una
asignación dentro del ciclo para evitar ciclos infinitos. Debe haber una asignación que
permita hacer falsa a la expresión lógica para salir del ciclo.

Poscondicionales

Formato Efecto
REPETIR Ejecutar la secuencia S hasta que la expresión Cond tome
S el valor de verdadero
HASTA Cond

Pos-condicionales. Primero se ejecuta el bloque de acciones y luego se evalúa la


condición, si es falsa se ejecuta nuevamente el bloque de acciones el ciclo finaliza
cuando la condición toma el valor de verdadero. A diferencia de la pre-condicional este
ciclo se ejecuta siempre, al menos una vez.

Composiciones iterativas Exactas

Formato Efecto
PARA i [Vi..Vf] HACER Ejecutar la secuencia S (Vf – Vi + 1) veces.
S
FIN_PARA

Exacta. Una forma natural de esta estructura consiste en repetir un bloque de acciones
una cantidad fija de veces o conocido de antemano.
Tiene definido un contador o índice como una variable de tipo ordinal que se
incrementa en una cantidad constante con cada iteración y permite controlar el numero
de veces que se ejecutara el ciclo.
En cada iteración el índice toma el valor siguiente de acuerdo al tipo de valor asociado
al ordinal. Hay lenguajes que solo permiten que la variación (que puede ser positiva o
negativa) sea solamente 1, y otros lenguajes que pueden modificar ese incremento. De
todas formas la variable índice se actualiza con cada iteración y se testea en cada ciclo
respecto del valor final deseado.
Si el incremento es uno la cantidad de repeticiones esta dada por:
Cantidad de repeticiones = Valor final del Índice – Valor inicial del Índice + 1.
En el caso de que valor inicial y valor final coincidan se ejecuta 1 vez, en el caso de que
el valor inicial es mayor que el final y por cada iteración se incrementa el índice el ciclo
no se ejecutara y no producirá errores en tiempo de ejecución.

El ejemplo planteado utilizando composición iterativa


LÉXICO
V : Real //Contiene la nota leída
S : Real //Contiene la sumatoria de las notas
N : Entero //Contiene el numero de alumnos
ALGORITMO // Composición iterativa mientras
S0;
N <- 0 ;
Leer (V) // asignación previa del dato de la expresión lógica
MIENTRAS V > 0 HACER
S  S + V ; //Suma las notas
N  N + 1 ; // Cuenta los alumnos
Leer (V) ;
FIN_MIENTRAS
SI N > 0
ENTONCES
Escribir (¨Promedio de las notas ¨, S/N)
SI_NO
Escribir (“No hay valores para procesar”)
FIN.

La composición iterativa mientras puede no ejecutarse por lo que es necesario al final del
proceso verificar si hubieron valores, el valor de n se puede utilizar para verificar esa condición.
ALGORITMO // Composición iterativa repetir hasta
S0;
N0;
Leer (v) // El primer valor leído debe ser valido ya que se evalúa
REPETIR
S  S + V ; //Suma las notas
‘ N  N + 1 ; // Cuenta los alumnos
Leer (V) ;
HASTA_QUE V = 0 //Cundo esto es verdadero finaliza la iteración
Escribir (¨Promedio de las notas ¨, S/N)
No requiere validar ya que al menos hay un valor
ALGORITMO // Composición iterativa para
S0;
N0;
Leer (N) // Lectura de la cantidad de elementos que contiene el lote de datos
PARA I [1..N] HACER
Leer (V)
S  S + V ; //Suma las notas
‘ N  N + 1 ; // Cuenta los alumnos
FIN_PARA
SI N > 0
ENTONCES
Escribir (¨Promedio de las notas ¨, S/N)
SI_NO
Escribir (¨No hay valores para procesar¨)
La composición iterativa para puede no ejecutarse ya que el valor leído de N puede ser
cero, en ese caso no corresponde la iteración por lo que es necesario al final del proceso
verificar si hubieron valores, el valor de n se puede utilizar para verificar esa condición.

Recursividad
La repetición puede relacionarse con el concepto de inducción matemática, este tipo de
razonamiento permite demostrar una proposición que depende de cierto parámetro N,
normalmente en el rango de los números naturales, una forma de demostrar si una
proposición P es cierta para todo natural N es:
Se demuestra que es cierta para N=0, inicio de la inducción o caso base
Se asume que P es cierto para n-1, hipótesis de inducción
Entonces se demuestra que también lo es para n, relación de inducción
También se puede utilizar la inducción para realizar definiciones matemáticas de
funciones y sucesiones.
Por ejemplo se puede definir el factorial introduciendo el valor cuando n = 0 e
introduciendo una relación para n > 0 a partir del factorial de n-1
0! = 1
N! = N * (N – 1)!
La primera igualdad corresponde al caso base, la siguiente es la relación d inducción
Otro ejemplo Es la conocida sucesión de Fibonacci
Fibo(0) = 1
Fibo(1) = 1
Fibo(N) = Fibo(n-1) + Fibo(N-2) para N>1
Los primeros valores de la serie son 1, 1, 2, 3, 5, 8, 11, 19, 21,......
Una función con sentencias entre las cuales se encuentra una llamada a si misma se dice
que es recursiva. Existen muchas aplicaciones matemáticas y computacionales de la
recursividad. Numerosas circunstancias de la vida común tiene naturaleza recursiva
Se debe tener en cuenta
1. Define el problema en términos de un problema más simple de la misma
naturaleza.
2. Debe disminuir el espacio del problema en cada llamada recursiva
Hay una instancia particular que se conoce como caso base o caso degenerado
3. Divide el problema original en subproblemas más pequeños. Cuando es lo
suficientemente chico se resuelve directamente y se combinan soluciones del
subproblema hasta que queda resuelto el problema

HANOI
Este es un juego que tiene su origen en la cultura oriental y en una leyenda sobre el
templo de Brama, cuya estructura simulaba una plataforma metálica con tres varillas y
discos en su interior. El problema suponía tres varillas Inicial, Central y Final en la que
se alojaban discos que podían trasladarse de una varilla a otra con la condición que cada
disco era ligeramente inferior en diámetro al que estaba justo debajo de el. Los discos
originalmente están en la varilla Inicial y se los desea trasladar a la final cumpliendo en
todos los pasos la condición del tamaño de los discos, el superior ligeramente menor al
inferior.
El analisis es simple desde el punto de vista
recursuivo es simple, si solo queda un disco en
Si n = 1 ENTONCES el poste inicial este puede ser movido
Mover n de I a F directamente al disco final. Si quedaran mas
SI_NO de uno habria que mover los n-1 anteriores
del inicio al medio para poder mover el ultimo
Mov n-1 de I a C usando F al fina. Después habra que colocar todos los
del medio en el fina, esto recursivamentel
Mover n de I a F
Mover n-1 de C a F usando I
FIN_SI

El flujo de control de una función recursiva requiere tres condiciones para una
terminación normal:
1. Un test para detener o continuar con la recursion.
2. una llamada recursiva para continuar la recursion, con un problema de la misma
naturaleza pero de menor complejidad.
3. un caso base para terminar la recursion

ALGORITMO
SI Es el caso base
ENTONCES
Ejecutar la acción final
Terminar con la recursion
SI_NO
Disminuir el espacio del problema
Volver a invocar a la función
FIN_SI

Iteración vs. Recursion


Considerar solución recursiva solo si una solución iterativa sencilla no es posible.
Solo utilice recursividad dentro de limites aceptables de ejecución y uso de memoria.
Si son posibles las soluciones iterativas y recursivas esta ultima requerirá mas tiempo y
mas recursos de memoria.
En ciertos problemas la recursion produce soluciones mas simples de leer. Los
beneficios de la claridad compensan el costo extra
Ambas implican repetición. Iteración explícitamente y recursion con llamadas repetidas.
Ambas consideran un test de salida. Iteración en la condición, recursividad en el caso
base.

Muchas veces la resolución de problemas exige probar sistemáticamente todas las


posibilidades que pueden existir para encontrar la solución.
En este caso se utilizan algoritmos de vuelta atrás o backtraking, que utilizan la
recursividad para probar cada una de las posibilidades hasta encontrar la solución.
Una de las características principales de estos algoritmos es la búsqueda exhaustiva con
todas las posibilidades de soluciones parciales que conducen a la solución del problema,
otra característica es la vuelta atrás, en el sentido que si una solución parcial no conduce
a la solución total del problema se vuelve atrás para ensayar con otra solución posible
de solución.
El esquema general de estos algoritmos responden a

acción EnsayarSolucion
ALGORITMO
<Inicializar cantidad de posibles soluciones>
REPETIR
<tomar la siguiente selección>
<determinar si es selección valida>
SI Valido
ENTONCES
<anotar selección>
SI Problema Solucionado
ENTONCES
Éxito = Verdadero
SINO
EnsayarSolucion llamada para realizar otra tarea
SINO Éxito
ENTONCES
<Borrar anotación y probar otra solución>
FINSI
FINSI
FINSI
HASTA Éxito O <No mas posibilidades>
Si sale por éxito habrá encontrado la solución, si agota las posibilidades sin éxito, el
problema no tiene solución
FIN.

Algoritmos que utilizan secuencias


Algoritmos de búsqueda.
Dada una colección de elementos es posible extraer dos tipos diferentes de información:
Información relativa al conjunto de los datos que forman la colección
Información detallada de algún ítem particular
En el caso en que se requiera información particular de un determinado ítem de la
colección este debe ser ubicado y, eventualmente extraído de la misma para su
tratamiento particular.
El proceso de ubicar información particular en una colección de datos es conocido como
algoritmo de búsqueda.
Los procesos de búsqueda que consisten en ubicar un elemento particular deben
suministrar alguna información del resultado de la búsqueda. Existen búsquedas con
eficiencia optima (Ef =1), cuando se conoce el lugar preciso donde el dato se encuentra
y se denomina búsqueda directa, otras búsquedas de eficiencia logarítmica las que
reducen el espacio del problema a la mitad con cada intento llamada búsqueda binaria o
dicotomica, y existe una búsqueda menos eficiente de orden N donde n representa la
cantidad de elementos de la lista. El desarrollo de estos procesos será visto en capítulos
posteriores.

Máximos y mínimos
En lo que hace a la información relativa a un conjunto de datos puede ser necesario
encontrar cual o cuales de los elementos de ese conjunto cumplen con ciertas
características. Por ejemplo si se tiene información de los nombres de los estudiantes y
sus calificaciones puede ser posible conocer el nombre del mejor estudiante, según el
valor de sus notas, o conociendo el nombre de los atletas y el tiempo empleado en una
carrera de velocidad puede requerirse conocer el ganador. En el primer caso se busca al
estudiante cuyo promedio es el mayor, en el otro caso se busca el atleta cuyo tiempo es
el menor. Existen algoritmos puntuales que permiten buscar máximos y mínimos.

Buscar un máximo
Datos e entrada L1 ... L n Lista de n elementos
Datos de salida M identificador que contendrá al valor máximo
N pertenece a los números Naturales
N > 0 Por lo menos hay un elemento en la lista
Li pertenece a los números racionales para todo 1<= i <= n
Poscondición
M pertenece a los números racionales
m>=li para todo 1<=i<=n
LÉXICO
Valor : Entero // Identificador que contendrá las lecturas
Máximo : Entero // Identificador que contendrá el máximo del conjunto
Esta acción le asigna el primer valor al máximo que puede ser el primer valor
leído, si es que se tiene o un valor arbitrario. El valor arbitrario puede ser un valor
razonablemente bajo para que cualquier dato valido lo pueda desplazar o un valor
utilizado como valor centinela para indicar que corresponde a la primer lectura.
FIN Para inicializar el identificador que contendra el maximo se
ALGORITMO puede hacer con el primer valor leido o con un valor
Leer(Valor) ; razonablemente alto dentro del contexto delprpblema
Máximo,valor ;
MIENTRAS haya datos HACER
SI Valor > Máximo
ENTONCES
Máximo  valor
FIN_SI
FIN_MIENTRAS
SI hubodatos
ENTONCES
Escribir(¨El máximo del conjunto es ¨, máximo)
SI_NO
Escribir(¨No hubo datos para procesar¨)
FIN_SI
FIN
La búsqueda de un máximo requiere:
1. Determinar el conjunto de datos para poder definir que tipo de composición
iterativa es la mas adecuada para el problema planteado
2. Definir al menos dos identificadores del mismo tipo de dato, uno para las
sucesivas lecturas y el otro para contener el máximo del conjunto.
3. Se debe inicializar el máximo esto puede ser con un valor arbitrario,
razonablemente bajo o un valor particular que pueda ser utilizado como valor
centinela o con el valor de la primer lectura.
4. A continuación se compara la nueva entrada con el valor máximo, cada vez que
la nueva entrada lo supera, se conserva ese valor como el nuevo máximo.
La búsqueda de un mínimo utiliza el mismo criterio solamente que requiere :
1. La inicialización del mínimo si se hace con un valor arbitrario este debe ser lo
suficientemente alto coma para que cualquier dato del conjunto lo reemplace
2. Las comparaciones posteriores requieren simplemente cambia el operador de
relación. Si en el máximo se compra por mayor, en el mínimo debe hacerse por
menor.

Dado 100 valores buscar el máximo del conjunto y su posición relativa dentro del
mismo
//Búsqueda con una cantidad conocida de datos
LÉXICO
TAMAÑO_LOTE = 100;
I : Entero // variable para la iteración
V : Entero // para las distintas lecturas
Máximo : Entero // Contiene el máximo del conjunto
PosRel : Entero // Contiene la pos del máximo dentro del conjunto
ALGORITMO
Leer(V);
Máximo = V ;//Asigna al máximo la primer lectura
PosRel = 1
PARA i [2,TAMAÑO_LOTE] HACER
Leer(V);
SI (V > Máximo)
ENTONCES
Máximo  v;
PosRel  i
FIN_SI;
FIN_PARA;
Escribir(“Máximo es : “,Máximo. “ y su posición relativa “,PosRel);
FIN.

Dado 100 valores buscar el máximo del conjunto y su posición relativa dentro del
mismo
//Búsqueda con una cantidad conocida de datos con valor centinela
LÉXICO
TAMAÑO_LOTE = 100;
I : Entero // variable para la iteración
V : Entero // para las distintas lecturas
Máximo : Entero // Contiene el máximo del conjunto
PosRel : Entero // Contiene la pos del máximo dentro del conjunto
ALGORITMO
PARA i [1,TAMAÑO_LOTE] HACER
Leer(V); El maximo lo asigna cuando es la primer lectura, es
SI ( i = 1 o V > Máximo) decir cuando i es igual a uno, cosa que ocurre solo
ENTONCES una vez o cuando el valor leido reemplaza al
maximo. Los compiladores evaluan las expresiones
Máximo  v; logicas de izquierda a derecha, al ser verdadera la
PosRel  i primera proposicion por ser una disyuncion no
FIN_SI; necesita evaluar la segunda para saber su valor de
verdadero
FIN_PARA;
Escribir(“Máximo es : “,Máximo. “ y su posición relativa “,PosRel);
FIN.
Dado un conjunto de valores, que finalizan con un valor igual a 0 buscar el máximo del
conjunto y su posición relativa dentro del mismo
//Búsqueda con una cantidad indefinida de datos
LÉXICO
I : Entero // variable para la iteración
V : Entero // para las distintas lecturas
Máximo : Entero // Contiene el máximo del conjunto
PosRel : Entero // Contiene la pos del máximo dentro del conjunto
ALGORITMO
Leer(V);
Máximo = V ;//Asigna al máximo la primer lectura
PosRel = 1
MIENTRAS (V <> 0) HACER
SI (V > Máximo)
ENTONCES
Máximo  v;
PosRel  i
FIN_SI;
Leer(v);
FIN_MIENTRAS;
SI (Máximo <> 0)
ENTONCES
Escribir(“Máximo es : “,Máximo. “ y su posición relativa “,PosRel);
SI_NO
Escribir(“No se ingresaron valores”);
FN_SI;
FIN.

Dado un conjunto de valores, que finalizan con un valor igual a 0 buscar el máximo del
conjunto y su posición relativa dentro del mismo
//Búsqueda con una cantidad indefinida de datos
LÉXICO
I : Entero // variable para la iteración
V : Entero // para las distintas lecturas
Máximo : Entero // Contiene el máximo del conjunto
PosRel : Entero // Contiene la pos del máximo dentro del conjunto
ALGORITMO
Leer(V);
Máximo = 0; PosRel = 0;
MIENTRAS (PosRel = 0 o V <> 0) HACER
Leer(V);
SI (V > Máximo)
ENTONCES
Máximo  v;
PosRel  i
FIN_SI;
Leer(v);
FIN_MIENTRAS;
SI (Máximo <> 0)
ENTONCES
Escribir(“Máximo es : “,Máximo. “ y su posición relativa “,PosRel);
SI_NO
Escribir(“No se ingresaron valores”);

FIN.
Alternativa de solución reemplazando el análisis de casos con la notación [JDM]
ALGORITMO
Leer(V);
Máximo = 0; PosRel = 0;
MIENTRAS (PosRel = 0 o V <> 0) HACER
Leer(V);
SI
(V > Máximo)
Máximo  v;
PosRel  i
FIN_SI;
Leer(v);
FIN_MIENTRAS;
SI
(Máximo <> 0)
Escribir(“Máximo es : “,Máximo. “ y su posición relativa “,PosRel);
(Máximo = 0) Escribir(“No se ingresaron valores”);
FN_SI;
FIN.

Corte de control
La utilización de este algoritmo puntual permite resolver el análisis de una secuencia de
datos que cumplen con la precondición de tener una clave que se repite, están ordenados
o agrupados por esta clave y se requiere información de cada subconjunto formado por
todos los valores de la misma clave y además información sobre la totalidad de los
datos. Debe garantizarse que se evaluaran todos los datos y que los que corresponden al
mismo subgrupo serán evaluados agrupados.

LÉXICO
Importe,Suma : Entero;
NumeroCliente, Anterior : Entero;
AGORITMO
Leer(NumeroCliente)
// hace una lectura anticipada del dato de la expresión lógica//
MIENTRAS (NumeroCliente > 0) HACER
//garantiza la secuencia de lectura de todos los datos//
Suma = 0; //inicializa acumuladores//
Anterior = NumeroCliente; //guarda e valor a controlar//
MIENTRAS (NumeroCliente > 0 y Anterior = NumeroCliente;) HACER
//ciclo que garantiza estar en el mismo subgrupo y que aun haya datos//
Leer(Importe); // lectura del resto de los datos//
Suma = Suma + Importe;
Leer(NumeroCliente)//lectura del nuevo s es igual al anterior
Continua, sino sale del ciclo.
FIN_MIENTRAS
Escribir(“El Cliente : “,Anterior, “ Compro : “,Suma);
FIN_MIENTRAS
FIN.
Equivalencias entre notación algorítmica y lenguajes de programación
CONDICIONAL
Formato Pascal C
SI Condicion If expresion condicional If (expresion)
ENTONCES Then S;
S S Else
SI_NO Else R;
R R;
FIN_SI

Formato Pascal C
SEGÚN expr Case selector of switch (selector) {
V1 : S1 Valor1 : S1; case etiqueta:S; break;
V2 : S2 ......................... ..............................
EN_OTRO_CASO : Sn else Ve: Se; default: R;
FIN_SEGÚN end; }

ITERACION
Formato Pascal C
Mientras Cond. Hacer While Expresion logica do while(expresion)
S S; S;
FIN_MIENTRAS

Formato Efecto
REPETIR Repeat do
S S S;
HASTA Cond Until expresion logica while(expresion)

Formto Efecto C
PARA i [Vi..Vf] HACER For i:=Vi to vf do for(i=0;i<vf;i++)
S S; S;
FIN_PARA

Estilos de Indentación

Recomendacion de estilos de indentacion para desarrollos más claros y legibles.(Ing. J.


M. Sola)

Estilo The One True Brace Style


while( SeaVerdad() ) {
HacerUnaCosa();
HacerOtraCosa();
}
HacerUnaUltimaCosaMas();

BSD/Allman.
while( SeaVerdad() )
{
HacerUnaCosa();
HacerOtraCosa();
}
HacerUnaUltimaCosaMas();
Estilo Whitesmiths
while( SeaVerdad() )
{
HacerUnaCosa();
HacerOtraCosa();
}
HacerUnaUltimaCosaMas();

Estilo GNU
while( SeaVerdad() )
{
HacerUnaCosa();
HacerOtraCosa();
}
HacerUnaUltimaCosaMas();

Estilo Pico
while( SeaVerdad()
{ HacerUnaCosa();
HacerOtraCosa(); }
HacerUnaUltimaCosaMas();

Estilo Banner
while( SeaVerdad() ) {
HacerUnaCosa();
HacerOtraCosa();
}
HacerUnaUltimaCosaMas();
Acciones y Funciones
Objetivos de aprendizaje
Dominando los temas del presente capitulo Usted podrá.
1. Entender la descomposición como forma de resolución de problemas.
2. Dar valor a la reusabilidad en búsqueda de la eficiencia en la escritura el código.
3. Establecer comunicación entre módulos.
4. Comprender las ventajas de la descomposición
5. Diferenciar acciones de funciones y los distintos tipos de parámetros

Introducción
En este capitulo se analiza la descomposición como forma de alcanzar la solución de
problemas. Una regla básica de la programación indica que si existe un programa de
longitud L tal que L = L1 + L2, se dice que el esfuerzo de resolver L es mayor que la
suma de los esfuerzos de resolución de L1 y L2, aun cuando haya que derivar esfuerzo
para la integración de los módulos.
SI L = L 1 + L 2
Entonces
Esfuerzo(L) > Esfuerzo(L1) + Esfuerzo (L2)
Antes de analizar las particularidades de las acciones y funciones es necesaria la
definición de los términos que se utilizan.

Modularizacion
En general los problemas a resolver son complejos y extensos, puede incluso
presentarse situaciones en que una parte del problema deba ser modificada para
adaptarse a nuevos requerimientos. Se hace necesario conocer algunas herramientas que
permitan facilitar la solución de estos problemas, la abstracción y la descomposición
pueden ayudar a ello. La abstracción permitirá encontrar y representar lo relevante del
problema y la descomposición se basa en el paradigma de ¨ dividir para vencer ¨. La
descomposición tiene como objetivo dividir cada problema en subproblemas cada uno
de los cuales será de más simple solución.
Es conveniente, e importante descomponer por varias razones:
Una persona entiende un problema de características complejas partiendo la
información. Por esto para comprender un problema complejo del mundo real es
necesario dividirlo o modularizar.
Favorece el trabajo en equipo, cada programador recibe las especificaciones la tarea a
realizar y las restricciones con las que debe manejarse.
Favorece el mantenimiento. Las tareas involucradas en este mantenimiento, corregir
errores y modificar código, se hace mucho mas simple el análisis y control de una
porción o modulo que de la totalidad del problema.
Permite la reusabilidad del código. Siempre es deseable, de ser posible, hacer uso de
código ya escrito.

Módulos
Un problema debe ser descompuesto en subproblemas que se denominan módulos en
los que cada uno tendrá una tarea especifica, bien definida y se comunicaran entre si
adecuadamente para conseguir un objetivo común. Un modulo es un conjunto de
instrucciones mas un conjunto de datos que realizan una tarea lógica.
Alcance de los datos
El desarrollo de un programa complejo con muchos módulos en los que en cada uno de
ellos se deben definir los propios tipos de datos puede ocasionar algunos de los
inconvenientes siguientes:
Demasiados identificadores.
Conflictos entre los nombres de los identificadores de cada modulo.
Integridad de los datos, lo que implica que puedan usarse datos que tengan igual
identificador pero que realicen tareas diferentes.
La solución a estos problemas se logra con una combinación entre ocultamiento de
datos y uso de parámetros.

Datos locales y globales


Unos se declaran en la sección de declaración del programa principal, los otros en la
sección de declaración de cada modulo.
Local y global ha sido utilizado hasta ahora de manera absoluta pero los módulos
pueden anidarse las reglas que gobiernan el alcance de los identificadores son:
El alcance de un identificador es el bloque del programa donde se lo declara.
Si un identificador declarado en un bloque es declarado nuevamente en un bloque
interno al primero el segundo bloque es excluido del alcance de la primera sección.

Ocultamiento y protección de datos


Todo lo relevante para un modulo debe ocultarse a los otros módulos. De este modo se
evita que en el programa principal se declaren datos que solo son relevantes para un
modulo en particular y se protege la integridad de los datos.

Parámetros
Son variables cuya característica principal es que se utilizan para transferir información
entre módulos. En programas bien organizados toda información que viaja hacia o
desde módulos se hace a través de parámetros.
Hay dos tipos de parámetros, los pasados por valor y los pasados por referencia o
dirección.
Cuando existen datos compartidos entre módulos una solución es que un modulo pase
una copia de esos datos al otro. En este caso el pasaje se denomina pasaje por valor. El
modulo que recibe esta copia no puede efectuar ningún cambio sobre el dato original; el
dato original se encuentra de este modo protegido de modificación.
Los parámetros pasados por referencia o dirección no envían una copia del dato sino
envían la dirección de memoria donde el dato se encuentra por lo que tanto el proceso
que lo llama como el proceso llamado pueden acceder a dicho dato para modificarlo.
Razones por la que es conveniente la utilización de parámetros sobre las variables
globales.

Integridad de los datos


Es necesario conocer que datos utiliza con exclusividad cada modulo para declararlos
como locales al modulo ocultándolo de los otros, si los datos pueden ser compartidos
por ambos módulos debería conocerse cuales son, si el modulo los utiliza solo de lectura
o puede modificarlos y es aquí donde se utilizan los parámetros.
Protección de datos
Si una variable es local a un modulo se asegura que cualquier otro modulo fuera del
alcance de la variable no la pueda ver y por lo tanto no la pueda modificar. Dado que las
variables globales pueden ser accedidas desde distintos módulos, la solución para evitar
modificaciones no deseadas es el pasaje como parámetros valor.

Uso de parámetros para retornar valores


Si bien el pasaje por valor es útil para proteger a los datos, existen situaciones en las que
se requiere hacer modificaciones sobre los datos y se necesitan conocer esas
modificaciones. Para esto se deben utilizar parámetros pasados por referencia. Los
parámetros enviados por referencia son aptos además para enviar datos en ambos
sentidos.

Utilidad del uso de parámetros


El uso de parámetros independiza a cada modulo del nombre de los identificadores que
utilizan los demás. En el caso de lenguajes fuertemente tipiados solo importa la
correspondencia en cantidad tipo y orden entre los actuales del llamado y los formales
de la implementación con independencia del nombre del identificador.

Reusabilidad
El uso de parámetros permite separar el nombre del dato, del dato en si mismo, lo que
permite que el mismo código sea utilizado en distintas partes del programa simplemente
cambiando la lista de parámetros actuales.

Acciones
El léxico establece el nivel de abstracción de un algoritmo. Es decir, introduce las
variables, las constantes, los tipos de datos y las acciones con que se construye el
algoritmo. Ahora se profundizara sobre el estudio de las acciones.
El concepto de acción está muy ligado al concepto de abstracción. Se analiza como
abstracción por parametrización y abstracción por especificación.

Utilización de acciones
Una acción es una secuencia de instrucciones que se identifica por un nombre y que
puede ser invocada desde un algoritmo principal o desde otra acción. Cuando una
acción es invocada desde algún punto de un algoritmo, el flujo de ejecución se traslada a
la primera instrucción de la acción, entonces la acción se ejecuta hasta el final y cuando
acaba, el flujo se traslada de nuevo a la instrucción del algoritmo que sigue a aquella
que origino la invocación.
Una acción debe tener un efecto bien definido, lo que significa que debe ser cohesiva.
El nombre de la acción es conveniente que evoque la tarea que realiza. Hay que definir
acciones que sean aplicables a cualquier posible conjunto de valores de entrada y no a
un valor concreto.
Entre una acción y el algoritmo que la invoca se debe producir una comunicación de
valores: el algoritmo debe proporcionar los valores de entrada y la acción puede retornar
el resultado, o puede modificar el estado de alguno de ellos.
Puede haber acciones en las que la comunicación se realice mediante variables globales
definidas en el ámbito del algoritmo principal, que pueden ser manejadas por la acción.
Pero esta no es la forma mas apropiada. Una acción, en principio, nunca debería acceder
a variables globales.
Los parámetros son el mecanismo que posibilita escribir acciones generales, aplicables
a cualquier valor de la entrada, e independientes del léxico del algoritmo.

Acciones con parámetros


Un parámetro es un tipo especial de variable que permite la comunicación entre una
acción y el algoritmo que la invoca, ya sea que este pase a la acción un valor de entrada
o bien que la acción devuelva el resultado al algoritmo, o que pasen ambas cosas
simultáneamente.
A los parámetros que proporcionan un valor de entrada se los llaman Parámetros dato,
y a los que, además de recoger un valor, retornan un resultado, se los llama dato-
resultado. En la declaración de una acción, la lista de los parámetros se indica después
del nombre de la acción entre paréntesis y separados por punto y coma.
Nombre(dato p1 : TipoDato; dato-resultado p2 : TipoDto) : una acción
Un parámetro también cuenta con una característica: la dirección de memoria en la que
se realiza la transmisión de la información.
Se denomina paso de parámetros al modo en que se establece la comunicación entre los
argumentos pasados a la acción desde el algoritmo y los parámetros de la acción; en la
llamada se pasan los datos de entrada, y en el retorno se devuelven los resultados. Cada
argumento se liga con el parámetro que ocupa la misma posición en la declaración de la
acción y ambos deben coincidir en tipo.
En la invocación a una acción, el algoritmo debe proporcionar un valor para cada
parámetro dato, mientras que debe indicar para cada parámetro dato-resultado qué
variable de su léxico recogerá el valor.

Abstracción y acciones
El término abstracción se refiere al proceso de eliminar detalles innecesarios en el
dominio del problema y quedarse con aquello que es esencial para encontrar la solución.
Como resultado de aplicar la abstracción, se obtiene un modelo que representa la
realidad que nos ocupa. Este modelo no es la realidad, es una simplificación de esa
realidad que establece un nivel de abstracción mas apropiado para razonar sobre el
problema y encontrar la solución.
La abstracción también está relacionada con los lenguajes de programación. Estos
ofrecen mecanismos de abstracción que determinan la forma de razonar de un
programador.
El concepto de acción conjuga dos técnicas de abstracción que son la parametrización y
la especificación. La parametrización es un mecanismo por el cual se generaliza una
declaración para que no sea aplicado a un único caso, sino que sirva para cualquier valor
que pueda tomar cierto parámetro.
La abstracción por especificación es la separación entre la especificación (el Qué) y la
implementación (el cómo). En el caso de acciones, se refiere a distinguir entre la
descripción de qué hace la acción y el cómo se la implementa. Una vez que se define
una nueva acción, se las utiliza del mismo modo que si se tratase de una acción
primitiva.
Del mismo modo que el algoritmo, las acciones se especifican mediante una
precondición y una poscondición. La precondición establece las restricciones que
satisfacen los parámetros (datos de entrada) para que se pueda ejecutar la acción, y la
postcondición describe el resultado.
Cada acción debe ir siempre acompañada de una descripción textual de su efecto y de su
precondición y postcondición. De esta forma, cualquier programador podría conocer
qué hace y podría utilizarla sin conocer cómo lo hace.
El programador solo debe preocuparse por que se cumpla la precondición al invocar la
acción y tendrá la certeza de que la acción cumplirá su objetivo.

Tipos de Parámetros
Una acción se comunica con el algoritmo que lo invoca a través de los parámetros. Es
necesaria una comunicación en dos sentidos. El algoritmo debe proporcionar los datos
de entrada que manipulará durante su ejecución y la acción debe retornar los resultados
que obtiene.
El tipo de parámetro indica cómo los valores de los argumentos son ligados a los
parámetros.
El tipo de parámetro dato solo permite que el parámetro pueda recibir el valor de un
argumento mientras que el tipo de parámetro dato-resultado permite que el parámetro
pueda recibir un valor y pueda retornar un resultado. En la declaración de una acción
hay que indicar el tipo de cada parámetro. Si hay varios parámetros del mismo tipo y del
mismo tipo de dato, se pueden poner en la misma declaración, separados por comas. La
declaración de una acción se la denomina cabecera.
Se denomina paso por valor al paso de parámetros que corresponda al tipo de parámetro
dato y paso por referencia al que corresponda al tipo de parámetro dato-resultado.

Parámetro dato (o parámetro de entrada)


El valor del argumento es asignado al parámetro en el momento de la llamada. El
argumento puede ser una expresión del mismo tipo de dato que el parámetro. Se trata de
una comunicación unidireccional: solamente se transmite información desde el punto
del llamado hacia la acción.
Una regla de buen estilo de programación es no modificar el valor de parámetros tipo
dato, aunque ello no tenga efecto fuera de la acción.

Parámetro dato-resultado (o parámetro de entrada y salida)


El valor del argumento es asignado al parámetro en el momento de la llamada y al final
de la ejecución el valor del parámetro es asignado al argumento. Se trata de una
comunicación bidireccional. Si la ejecución de la acción provoca un cambio en el valor
del parámetro, en el momento del retorno el argumento tendrá el valor del parámetro al
finalizar la ejecución.
Un argumento para un parámetro dato-resultado debe ser una variable del mismo tipo de
dato que el parámetro y no puede ser una expresión.

Acción para el intercambio de dos variables: La acción recibe dos identificadores con
dos valores y debe retornar los identificadores con los valores cambiados

Intercambiar(dato-resultado a, b : Entero) : una acción


PRE { a, b : Entero, a = A, b = B }
POST { a = B, b = A }
LÉXICO Estos son los parámetros, que como
t : Entero deber ser modificados sus valores
Este identificador se por la accion se definen como Dato-
ALGORITMO necesita como variable Resultado, son las variables que
t = a; auxiliar para poder hacer el intercambian informacion entre el
a = b; intercambio. Su valor no lo programa principal y el modulo. Son
necesita el programa que parámetros variables
b = t invoca a la accion, solo
FIN interesa su visibilidad en el
modulo por tanto no es
parámetro, es una variable
local al modulo
Beneficios del uso de acciones
En la actualidad, las clases de los lenguajes orientados a objetos son los mecanismos
mas adecuados para estructurar los programas. No obstante, las acciones no desaparecen
con estos nuevos mecanismos porque dentro de cada clase se encuentran acciones.
Una acción tiene cuatro propiedades esenciales. Ellas son:
1. Generalidad
2. Ocultamiento de información
3. Localidad
4. Modularidad
De estas propiedades, se deducen una serie de beneficios muy importantes para el
desarrollo de algoritmos.
1. Dominar la complejidad
2. Evitar repetir código
3. Mejorar la legibilidad
4. Facilitar el mantenimiento
5. Favorecer la corrección
6. Favorecer la reutilización

Funciones
Si el propósito es calcular un valor a partir de otros que se pasan con argumentos y se
utilizan acciones, habrá que definir un parámetro dato-resultado para que retorne el
valor calculado. Las acciones que retornan un único valor no pueden ser utilizadas en
una expresión.
Para resolver este problema, los lenguajes de programación incorporan el concepto de
función. Las funciones devuelven un único valor. La función supone extender el
conjunto de operadores primitivos.
En cada declaración se especifica el nombre de la función, la lista de los parámetros y
finalmente el tipo de valor que retorna la función.
Nombre_funcion (par1 : td1 ; ... ; parn : tdn) : tr : una función
Una función no debe tener efectos laterales. Es decir, debe limitarse a calcular un valor
y no modificar ninguno de los que se describen en el momento de la invocación.
Las acciones se utilizan para extender el conjunto de acciones primitivas. Las funciones
permiten extender el conjunto de funciones u operadores primitivos. Siempre deben
utilizarse dentro de una expresión.

Función que obtenga el mayor de tres números

Max(a, b, c : Entero)  Entero : una función


ALGORITMO
SI (a >= b) y (a >= c)
ENTONCES Las funciones siempre retornan un unico
valor. Es imprescindible asignarle valor
Max = a al nombre e la funcion. El identificador
SINO SI (b >= a) y (b >= c) del nombre de la funcion se puede utilizar
ENTONCES en una expresión como cualquier
identificador del tipo que retorna. Las
Max = b funciones pueden retornar un escalar un
SINO apuntadoro un registro
Max = c
FIN_SI
FIN_SI
FIN.

Resumen:
En este capitulo se avanza sobre la necesidad de mayor abstracción procedural
introduciendo conceptos claves de programación como acciones y funciones como la
forma mas adecuada de estructurar problemas en el paradigma procedural. Es una
introducción a la abstracción procedural y de datos que servirá de base para sustentar
futuros conocimientos de estructuración de programas en clases cuando se aborde, en
otra instancia, la programación orientada a objetos.
Se dio valor a términos como reusabilidad, ocultamiento de datos y cohesión
Estructuras Enlazadas
Objetivos de aprendizaje
Dominando los temas del presente capitulo Usted podrá.
1. Manejar estructuras complejas.
2. Introducirse a la semántica de direcciones
3. Comprender como se asigna memoria dinámicamente en tiempo de ejecución.
4. Conocer estructuras enlazadas lineales
5. Diferenciar entre estructuras indexadas y estructuras enlazadas

Introducción:
En el presente trabajo se incorpora el concepto de asignación dinámica en memoria.
Esto permite romper con la limitación de tamaño fijo que proporcionan las tablas
cuando es necesario trabajar con colección de datos el mismo tipo en memoria.
Para esto se incorporan los conceptos de estructuras enlazadas, punteros y asignación
dinámica en memoria.

Estructuras enlazadas vs. estructuras indexadas


Como vimos una tabla es una secuencia de datos del mismo tipo donde a cada elemento
se puede acceder a través de un índice. En esta estructura las posiciones de memoria son
contiguas y se las puede ir recorriendo con solo incrementar el índice. En estas
estructuras el primer elemento lógico coincide con el primero físico, es decir se
comienza desde la primera posición, y el siguiente lógico coincide con el siguiente
físico, es decir al próximo elemento se accede incrementando en uno el índice. Estas
estructuras, con esta organización son estructuras indexadas. Las estructuras pueden
organizarse de forma diferente. El primer elemento lógico puede no coincidir con el
primero físico, en ese caso, para conocer donde comienza lógicamente se debe saber la
posición de ese primero. El siguiente elemento lógico no necesariamente debe estar en
la posición contigua, para saber donde esta será necesario tener algo que referencie la
posición del siguiente elemento. Una estructura con esta organización es una estructura
enlazada. Las estructuras enlazadas tienen la particularidad que se necesita conocer la
posición del primer elemento y en cada posición se tiene un registro, llamado nodo, con
al menos dos campos, uno que contenga la información y otro que indique o referencie
donde se encuentra el siguiente que no necesariamente debe ser el contiguo.
Por otro lado vimos que si se quiere definir en memoria una colección de datos del
mismo tipo mediante una tabla esta requiere establecer una capacidad máxima. Estas
son estructuras con tamaño fijo, el mismo no puede ser modificado en tiempo de
ejecución. Existe entonces riesgo que la cantidad de posiciones definidas en tiempo de
declaración no alcancen, o, que se utilicen muy pocas de las posiciones definidas
haciendo un uso poco eficiente de los recursos.

Estructuras enlazadas con asignación dinámica en memoria


Una estructura con asignación dinámica es un conjunto de elementos de tipo
homogéneo donde los mismos no ocupan posiciones contiguas de memoria, pueden
aparecer físicamente dispersos manteniendo un orden lógico y son instanciados y/o
liberados en tiempo de ejecución.

Operaciones con listas


1. Crear una estructura
2. Recorrerla, parcial o totalmente
3. Agregar o insertar nuevos elementos o nodos en distintos lugres y con criterio
variado.
4. Localizar un elemento en particular en la estructura
5. Borrar un elemento de posicion particular o previamente desconocida
La mayor facilidad de las listas es el “enlace dinámico” a través de punteros que
permiten intercalar o eliminar valores sin un movimiento masivo de memoria, con solo
pedir memoria o liberarla y hacer simplemente los enlaces de los nodos involucraos.
Punteros
Es posible definir estructuras de datos complejas cuyo tamaño puede cambiar en tiempo
de ejecución, por lo que son denominadas estructuras de datos dinámicas. Se instancias
a través de punteros.
Mediante la utilización de tablas se puede definir una secuencia de valores como:
TipoSecuencia = TIPO Tabla [1, LongitudMaxima] de elemento;
Con esta definición se reserva espacio en tiempo de ejecución para una cantidad fija de
elementos. Esta cantidad esta dada por el valor de LongitudMaxima.
Otra forma de definir una secuencia de valores seria por inducción o recursion:
La secuencia vacía es una secuencia
Un elemento concatenado a una secuencia es otra secuencia
De esta forma se declara el tipo sin especificar ninguna capacidad máxima, se define en
forma recursiva.
En esta definición es necesario que cada elemento referencie con precisión el siguiente
elemento si es que este existe.
Una secuencia, con esta organización, como ya dijimos es una concatenación de
registros llamados nodos de dos campos: uno para la información y otro para un
indicador al siguiente elemento. El siguiente elemento al que se referencia es un registro
del mismo tipo del actual, por referenciar a una estructura de su mismo tipo estas
estructuras se conocen como estructuras autoreferenciadas.
Para la asignación dinámica en memoria, los elementos se enlazan a través de un
determinado tipo de dato que disponen la mayoría de lenguajes de programación y que
se denominan puntero o apuntador, cuyos valores son referencias o punteros a variables
de un tipo.
TipoPunteroEntero = TIPO Apuntador a Entero;
Se hace una definición de un tipo de dato con la particularidad que tendrá como valor
una dirección de memoria. Se dirá entonces que es un puntero al tipo de dato o que
apunta a determinado tipo de dato
Si de define
PunteroEntero = TipoPunteroEntero
Los posibles valores de PunteroEntero no serán enteros, sino referencias a enteros; esto
sería la dirección del espacio de memoria en la que se almacena el entero.
Ya se definió variable como un identificador que denota un espacio de memoria en el
que se almacena un valor del tipo asociado en la dirección.
Un valor apuntador es la dirección de una variable “anónima”, se le asigna la dirección
a se crea en tiempo de ejecución.
Para indicar que una variable puntero no referencia o apunta a ninguna a otra variable
se le debe asignar el valor NULO.
TipoInfo = TIPO Entero
//define la información que tendrá el campo dato del nodo//
TipoPuntero = TIPO Apuntador a TipoNodo;
//Define un puntero que en cada instancia generara un nodo.
TipoNodo = TIPO < dato : TipoInfo; sgte : TipoPuntero >;
//Define un nodo con la información y la referencia al siguiente que es un puntero a la
siguiente dirección de memoria de la secuencia definida//
Se trata de una definición recursiva o autorreferenciada siguiendo la definición
inductiva de secuencia.
Una estructura enlazada utilizando punteros debe tener una variable que controle la
estructura, en general debe contener la dirección de memoria del primer nodo de la
misma, que debe ser de tipo puntero e inicialmente debe ser creada haciendo apuntar a
la misma al valor NULO, lo que indica que la secuencia esta vacía.
Con este tipo de estructura no es necesario especificar una capacidad máxima en la
declaración, sino que se asigna espacio en tiempo de ejecución, conforme se necesita, a
través de los apuntadores, por lo que se obtienen dos importantes beneficios.
1. No se desaprovecha espacio cuando la secuencia tiene menos elementos que el
tamaño máximo establecido.
2. El tamaño de la secuencia no está limitado.
Solo se podría mencionar como desventaja el hecho que cada elemento adema de tener
la información propia debe destinar recursos para referenciar al siguiente, situación que
puede estar a favor de las tablas. Con lar particularidades de cada estructura es
responsabilidad del programador seleccionar la más idónea para cada caso que deba
resolver.
Como ya mencionamos estas estructuras de datos cuyo tamaño puede variar en tiempo
de ejecución se denominan estructuras de datos dinámicas, que son básicas en
programación, como: listas, pilas, colas y árboles binarios de búsqueda que serán
abordados en este capitulo y el siguiente.

El tipo de dato Puntero


Se ha definido un tipo de datos puntero como aquel cuyo dominio de valores está
formado por referencias o punteros a variables (direcciones de memoria) de un tipo
existente.
Si los tipos de datos se definen por sus valores y sus operaciones los valores que pueden
tener los punteros son los de direcciones de memoria o el valor NULO en caso de no
estar apuntando a una dirección definida y, entre las operaciones se pueden mencionar
la asignación interna, la creación o la destrucción, los lenguajes de programación
ofrecen los mecanismos para estas operaciones.

Constantes y operaciones con punteros


No es posible el uso de literales para representar valores de tipo puntero salvo las
constantes simbólicas que representan el valor NULO con sintaxis diferente según el
lenguaje de programación que se trate. NULO representa solo eso y no contiene un
valor de dirección de memoria válido. Esta constante NULO es compatible de
asignación y comparación con cualquier tipo de dato apuntador, con independencia a
cualquiera sea el tipo de valores a los que apunta éste.
Los valores de tipo apuntador son datos internos propios de cada ejecución del
programa, solo aceptan asignación interna, no es correcto hacer asignaciones externas
leer o escribir con variables de tipo apuntador.
Las operaciones elementales de una variable de tipo apuntador son las de creación de
un nuevo objeto y destrucción del objeto apuntado.
Para la creación de un nuevo objeto apuntado dispondremos de la acción Nuevo. Esta
acción tiene un único parámetro de tipo Apuntador a T, cualquiera sea el tipo de T, y su
efecto es el siguiente:
Reserva espacio de memoria suficiente para alojar una variable de tipo T
Asigna al el valor de la dirección de memoria que acaba de reservar, si es que se
dispone de espacio en memoria o el valor NULO en caso de no poder ejecutar la acción
de creación.
El efecto de invocar a la acción Nuevo (Puntero) sería la creación de una nueva variable
anónima del tipo al que apunta el puntero, y la asignación a pe de la dirección de
memoria donde se encuentra dicha variable. La nueva variable se denomina anónima
porque no tiene identificador propio, y únicamente será accesible a través de la
dirección que la acción Nuevo ha asignado al parámetro puntero. La nueva variable está
recién creada y, por tanto, sin inicializar; no tiene un valor definido mientras no se le
asigne nada.
Aunque los lenguajes de programación tienden a aliviar al programador de la
responsabilidad de liberar el espacio reservado a variables de tipo apuntador e
incorporan rutinas de recolección de basuras para liberar los espacios de memoria
reservados que ya no están siendo utilizados, de cualquier modo es erróneo el realizar
reservas de espacios de memoria que posteriormente queden reservados e inaccesibles
por la pérdida de valor de la dirección donde se encuentran.
Cuando un espacio de memoria que ha sido reservado con la acción Nuevo no es ya
necesario, podemos destruir las variables en él contenidas y liberar ese espacio para que
quede disponible para futuras reservas. Para ello, utilizaremos la acción Destruir, que
ejecuta la operación inversa de Nuevo: recibe como parámetro una variable de tipo
apuntador que contiene una dirección válida que previamente ha sido reservada con la
acción Nuevo, y libera el espacio de memoria al que apunta este parámetro. Cuando
programemos, no debemos suponer que la acción Destruir modifica el valor del
parámetro que recibe, sino que una buena práctica es asignar el valor NULO a una
variable de tipo apuntador tras invocar Destruir. Si analizamos el siguiente fragmento de
algoritmo:
LÉXICO
TPEntero = TIPO Apuntador a Entero;
p, q = TPEntero;
...
ALGORITMO
...
Nuevo(p);
q ← p;
Destruir(q);
...
FIN
Se puede ver que con independencia de si Destruir modifica o no el valor de q, después
de ejecutar esas tres instrucciones el apuntador p tiene un valor de dirección de memoria
que no sería válida, pues ha sido liberada. Se dice que p queda como un apuntador
colgante, ya que no apunta a nada, o mejor dicho, apunta a una dirección que ya no es
válida, pues ha sido liberada. Es responsabilidad del programador el mantener de
manera conveniente los valores de los apuntadores y no acceder a direcciones que no
son válidas.
Acceso a datos mediante apuntadores
Sea TPEntero un tipo de apuntador que referencia a variables de un tipo cualquiera
TipoBase y p una variable apuntador del tipo TPuntero:
TipoPuntero = TIPO Apuntador a TipoBase;
p : TipoPuntero
Los lenguajes de programación utilizan el operador * en notación prefija (*Puntero) o el
operador ^ (Punteros)en notación posfija, en esta publicación se los utilizara en forma
indistinta, agregando el operador ↑ en notación postfija, es decir puntero↑, para
referenciar al objeto apuntado por el puntero. La expresión Puntero↑, *Puntero o
Puntrero^ hará referencia al contenido de la dirección apuntada por el puntero y será un
identificador de la variable de tipo TipoBase a que se refiere el apuntador puntero.
Respecto al tema de la asignación debe diferenciarse si lo que se asigna es el contenido
o lo que se asigna es la dirección. Si p y q so dos variables de tipo puntero que apuntan
al mismo tipo base hay que diferenciar que es lo que ocurre con las asignaciones
siguientes:
p↑ = q↑
En este caso se le asigna al contenido de p el contenido de q. P y Q siguen apuntando a
su propia dirección de memoria, i los contenidos de esas dos direcciones es lo que se
iguala.
Por otro lado la asignación:
p ← q
Hace que q apunte a la dirección apuntada por p.
En el caso en que el tipo base de un determinado tipo apuntador no sea un tipo simple,
sino un tipo estructurado, el acceso se realiza con los mismos operadores de acceso que
los datos estáticos.
TipoRegistro=TIPO <Campo1:TipoDeDato1;Campo2:TipoDeDato2>
TipoPunteroRegistro = TIPO Apuntador a TipoRegistro;
PunteroRegistro : TipoPunteroRegistro
PunteroRegistro es un puntero a un registro, contiene la dirección de memoria donde se
aloja un registro, pro lo tanto el contenido de la dirección de memoria a la que apunta es
un registro.
PunteroRegistro es un p TipoPuntero.
PunteroRegistro^ es un registro que se encuentra en la dirección apuntada por el
puntero.
Si PunteroRegistro^ es un registro, el operador de acceso a un miembro de un registro
es el operador punto, por lo tanto
PunteroRegistro^.Campo1 hace referencia al miembro Campo1 del registro que esta en
la dirección de memoria apuntada por PunteroRegistro
Algunos lenguajes de programación permiten utilizar apuntadores para referenciar
variables no anónimas declaradas en el léxico. Para ello disponen de un operador
dirección_de (el operador & en el caso del lenguaje de programación C) que dada una
variable, devuelve su dirección.

LÉXICO
TipoRegistro=TIPO <Campo1 : Entero ; Campo2 : Entero>
TipoPunteroRegistro = TIPO Apuntador a TipoRegistro;

Registro : TipoRegistro
PunteroRegistro : TipoPunteroRegistro
ALGORITMO
Registro.Campo1 ← 5; //asigna valores al registro
Registro.Campo2  10;
PunteroRegistro ← dirección_de(Registro);//
PunteroRegistro↑.Campo1 ← 35;
Escribir(Registro.Campo1); //imprime el valor 35
FIN
Obviamente, cuando una variable de tipo apuntador haga referencia a una variable
declarada en el léxico, como en el caso del ejemplo anterior, no será posible destruir su
contenido mediante la acción Destruir, ya que solo pueden destruirse las instancias que
se crean en tiempo de ejecución con la acción Nuevo.

Tipos de datos autorreferenciados o recursivos


Hemos mostrado que con punteros se pueden definir tipos que se autorreferencian, lo
que permite que el tamaño de una estructura enlazada sólo esté limitado por la
disponibilidad de memoria principal. Con una única variable de tipo puntero será
posible referenciar a una secuencia cuyo número de elementos podrá crecer o disminuir
en tiempo de ejecución.
En tipo de dato recursivo o autorreferenciado es un registro, llamado nodo, que contiene
entre sus elementos al menos dos campos, uno con la información y el otro es un
puntero a una estructura del mismo tipo. La bibliografía denomina nodo para referir a
ese elemento ya que es el término utilizado habitualmente para referirse a los elementos
de una estructura dinámica.
TPNodo = TIPO Apuntador a Nodo;
Nodo = TIPO < dato : Entero; sig : TPNodo >;
Cada vez que reservemos espacio para una variable se crea una nueva variable de tipo
Nodo. Es posible construir sucesivamente una secuencia indefinidamente larga de datos
de tipo Nodo, en la que el campo sig de cada uno de ellos apunta al siguiente elemento
de tipo Nodo creado. El último elemento de tipo Nodo contiene en su campo sig el valor
NULO para indicar que no existen más elementos siguientes.
El tipo Nodo es, por tanto, un tipo de dato autorreferenciado.
La siguiente función CrearSecuencia lee de la entrada n valores de tipo entero, crea una
secuencia con esos valores en el orden inverso de entrada y devuelve como resultado un
apuntador al primer elemento de la secuencia. La variable r se utiliza para apuntar al
nodo creado en cada paso y p apunta al primer elemento de la secuencia. Cada nuevo
nodo se añade delante del primero.
CrearSecuencia(n : Entero)  TPNodo : una función
LÉXICO Guarda en el registro apuntado por r el valor v y en el
p, q, r : TPNodo; campo siguiente el puntero p, este puntero contiene la
i, v : Entero; direccion del que estaba en primer lugar por lo que se
establece como siguiente el que era primero antes.
ALGORITMO
p ← NULO; //Crea la estructura
Leer(n);
i PARA [1, n] HACER
Escribir(“Ingrese un valor entero: ”);
Leer(v);
Nuevo(r); // instancia y pide memoria
r^ = < v, p >;
p ← r
FIN_PARA;
CrearSecuencia ← p
FIN

El ámbito de una variable local es la acción o función en la que se declara.


En cambio, aun cuando todas las variables apuntador usadas en la función
CrearSecuencia, es decir, p y r, son parte de su léxico local y, por tanto, desaparecen
tras concluir la llamada a ésta. No sucede así con las variables dinámicas creadas a
través de ellas con las llamadas a Nuevo. La secuencia creada por la función sería
accesible fuera de ella a través del valor TPNodo que retorna.
La siguiente acción recorre una secuencia y escribe los datos en ella contenidos:
EscribirSecuencia(dato p : TPNodo) : una acción
LÉXICO
q = TPNodo;
ALGORITMO
q = p;
MIENTRAS q ≠ NULO HACER
Escribir(q↑.dato);
q ← q↑.sig
FIN_MIENTRAS
FIN

DestruirSecuencia(dato-resultado p : TPNodo) : una acción


LÉXICO
q : TPNodo;
ALGORITMO
MIENTRAS p < > NULO HACER
q ← p;
p ← p↑.sig
Destruir(q)
FIN_MIENTRAS
FIN

Estructuras de datos dinámicas lineales


Dependiendo del número de punteros y de las relaciones entre nodos, podemos
distinguir varios tipos de estructuras dinámicas

El tipo pila
Una pila es una colección de elementos de un mismo tipo, posiblemente vacía, sobre la
que podemos hacer operaciones de inserción de un nuevo elemento, eliminación de un
elemento. Una pila es una estructura de tipo LIFO (del inglés, Last-Input, First-
Output), lo cual significa que los elementos siempre serán eliminados de ella en orden
inverso al que fueron colocados, de modo que el último elemento en entrar será el
primero en salir. A este tipo de colección de datos se la conoce por el nombre de “pila”
precisamente por esta característica. A la hora de retirar elementos, únicamente
podremos tomar el que está en la cima de la pila, que será el último que fue apilado.
Para definir el tipo de pila debemos, por tanto, diseñar las siguientes operaciones:
PilaVacia:  Pila
EsPilaVacia: Pila  Booleano
Apilar : Pila X TipoBase  Pila
Cima : Pila  TipoBase
Desapilar : Pila  Pila
La lista anterior de operaciones disponibles para un tipo se conoce con el nombre de
signatura, y en ella se establecen los nombres de las operaciones y el número y tipo de
parámetros de cada una de ellas. En la signatura de un cierto tipo T se distinguen tres
tipos de operaciones:
1. Operaciones constructoras: son aquellas en las que el tipo T aparece como
resultado devuelto, pero no como parámetro de la operación.
2. Operaciones modificadoras: son aquellas en las que el tipo T aparece tanto en la
lista de parámetros como en el resultado devuelto.
3. Operaciones de consulta: son aquellas en las que el tipo T aparece únicamente
en la lista de parámetros.
En el caso del tipo pila anterior, la única operación constructora sería PilaVacia; las
operaciones Apilar y Desapilar serían modificadoras, y las operaciones EsPilaVacia y
Cima serían de consulta. Las operaciones Cima y Desapilar tendrán como precondición
que la pila que reciben como parámetro no sea vacía, pues para una pila vacía no estaría
definida su cima ni se podría desapilar.
Se puede definir una pila de caracteres mediante las siguientes declaraciones:
TPNodoPilaCars = TIPO Apuntador a NodoPilaCars;
NodoPilaCars=Tipo < dato: Carácter; sig : TPNodoPilaCars >;
PilaCars = TPNodoPilaCars;
PilaVacia  PilaCars : una función
ALGORITMO
PilaVacia ← NULO
FIN

EsPilaVacia(p : PilaCars)  Carácter : una función


ALGORITMO
EsPilaVacia ← p = PilaVacia
FIN

Cima(p : PilaCars)  Carácter : una función


PRE ( no EsPilaVacia (p) )
ALGORITMO
Cima ← p↑.dato
FIN

Apilar(p : PilaCars; c : Carácter) PilaCars : una función


LÉXICO
q : TPNodoPilaCars;
ALGORITMO
Nuevo(q);
q↑ ← < c, p >;
Apilar ← q
FIN
Desapilar(p : PilaCars)  PilaCars : una función
PRE ( NO EsPilaVacia(p) )
LÉXICO
q : PilaCars;
ALGORITMO
q ← p↑ .sig;
Destruir(p);
Desapilar ← q
FIN

Es importante que se sepa que cuando se definen tipos de datos basados en estructuras
de datos complejas, las operaciones usuales de igualdad o desigualdad, que se realizan
por defecto mediante los operadores booleanos = y ≠, producirían resultados que no se
corresponden con la semántica del tipo implementado. Por ejemplo, suponga que
declaramos dos variables, p1 y p2 de tipo PilaCars, y efectuamos una comparación
como la siguiente:
SI p1 = p2 ENTONCES
...
FIN_SI;
Lo que estamos comparando en realidad no son las pilas, es decir, si constan de los
mismos elementos y están en idéntico orden, sino los apuntadores p1 y p2, puesto que
ambas variables son de tipo PilaCars el cual, a su vez, es un tipo apuntador. La
comparación p1 = p2 devolverá Verdadero si y sólo si los apuntadores p1 y p2
apuntan a la misma dirección de memoria.

Insertar elemento en una pila:

Apilar en una pila vacía:


Partiendo que ya tiene el nodo a insertar y un puntero que apunte a él, además el puntero
a la pila valdrá NULO:
El proceso es:
1. nodo^.siguiente apunte a NULO
2. Pila apunte a nodo.

Meter en una pila no vacía:


Se puede considerar el caso anterior como un caso particular de éste, la única diferencia
es el siguiente será pila. Se puede utilizar este procedimiento para ambos casos.
El proceso sigue siendo muy sencillo:
1. Hacemos que nodo^.siguiente apunte a Pila.
2. Hacemos que Pila apunte a nodo.

Desapilar: leer y eliminar un elemento


Sólo existe un caso posible, en las pilas sólo se puede leer y sacar desde le extremo de la
pila.
1. Se utiliza un puntero auxiliar.
2. Se hace apuntar al auxiliar al primer elemento de la pila, es decir a Pila.
3. Se avanza con la pila, asignando a Pila la dirección del segundo nodo de la
pila Pila^.siguiente.
4. Se conserva el contenido del nodo para devolverlo como retorno. La operación
sacar equivale a leer y borrar.
5. Se libera la memoria asignada al auxiliar, que es el nodo a liberar.
Si la pila sólo tiene un nodo, el proceso sigue siendo válido, ya que el valor de
Pila^.siguiente es NULO, y después de eliminar el último nodo la pila quedará vacía, y
el valor de Pila será NULO.
Algoritmo de la función "push" Apilar:
1. Se Crea un nodo para el valor que se colocara en la pila.
2. Se hace que nodo^.siguiente apunte a Pila.
3. Pila debe apuntar al nuevo nodo.

Algoritmo de la función "pop" Desapilar:


1. Se hace que nodo apunte al primer elemento de la pila, es decir a Pila.
2. Se asigna a Pila la dirección del segundo nodo de la pila: Pilasiguiente.
3. Se guarda el contenido del nodo retornarlo.
4. Se libera la memoria asignada a nodo.

El tipo cola
El tipo cola difiere del tipo pila únicamente en la forma de inserción y extracción de
elementos. Una cola es una estructurade tipo FIFO (del inglés, First-Input, First-
Output), es decir, primero en entrar, primero en salir. Se conoce con el nombre de cola
por ser la que habitualmente se utiliza en las colas de la vida cotidiana: el primero que
llega (que entra en la cola) es el primero en ser atendido (en ser eliminado de la cola).
TPNodoColaCars = TIPO Apuntador a NodoColaCars;
NodoColaCars = TIPO < dato: carácter; sig TPNodoColaCars >;
ColaCars = TPNodoColaCars;
Las operaciones propias del tipo cola son las siguientes:
ColaVacia :  Cola
EsColaVacia : Cola  Booleano
Encolar : Cola X TipoBase  Cola
Primero : Cola  TipoBase
EliminarPrimero : Cola  Cola

Operaciones básicas con colas


Por las restricciones a esta estructura tienen muy pocas operaciones disponibles. Las
colas sólo permiten añadir y leer elementos:
1. Añadir: Inserta un elemento al final de la cola.
2. Leer: Lee y elimina un elemento del principio de la cola.

Añadir un elemento Encolar:


Las operaciones con colas son muy sencillas, prácticamente no hay casos especiales,
salvo que la cola esté vacía.

Añadir elemento en una cola vacía:


Se parte de tener el nodo a insertar y un puntero que apunte a él, además los punteros
que definen la cola, primero y ultimo que valdrán NULO
El proceso es muy simple, bastará con que:
1. nodo^.siguiente apunte a NULO.
2. Y que los punteros primero y último apunten a nodo.

Añadir elemento en una cola no vacía:


De nuevo partiremos de un nodo a insertar, con un puntero que apunte a él, y de una
cola, en este caso, al no estar vacía, los punteros primero y último no serán nulos:
El proceso sigue siendo muy sencillo:
1. Nodo^.siguiente apunte a NULO.
2. Ultimo^,siguiente apunte a nodo.
3. Y se actualiza último, haciendo que apunte a nodo.

Añadir elemento en una cola, caso general:


Para generalizar el caso anterior, sólo necesitamos añadir una operación:
Siempre nodo^.siguiente apunta a NULO.
Si ultimo no es NULO, entonces ultimo^.siguiente apunta a nodo.
Si no el primero también es NULO, significa que la cola estaba vacía, así que primero
también apunta a nodo
Y se actualiza último, haciendo que apunte a nodo.
.
Leer un elemento de una cola Eliminar primero:
Ahora también existen dos casos, que la cola tenga un solo elemento o que tenga más de
uno.

Leer un elemento en una cola con más de un elemento:


1. Se utilaza puntero auxiliar:
2. Se hace que auxiliar apunte al primer elemento de la cola, es decir a primero.
3. Se asigna a primero la dirección del segundo nodo de la cola:
primeroprimero^.siguiente.
4. Se guarda el contenido del auxiliar para devolverlo, la operación de lectura en
colas implican también borrar.
5. Se Libera la memoria asignada a nodo.

Leer un elemento en una cola con un solo elemento:


1. También se requiere un puntero auxiliar:
2. Se Hacemos que auxiliar apunte al primer elemento de la cola.
3. Se le asigna NULO
4. Se guarda el contenido del auxiliar para retornarlo.
5. Se libera la memoria asignada al primer nodo, el que queremos eliminar.
6. El último debe apuntar a NULO.

El tipo lista
El tipo lista es el caso más general de estructura de datos lineal. No existe una forma
prefijada de inserción y extracción de elementos, de modo que éstos pueden ser
insertados en, y también eliminados de, cualquier posición arbitraria.

Listas simplemente enlazadas

Con las listas existe un repertorio más amplio de operaciones básicas que se pueden
realizar:
1. Añadir o insertar elementos.
2. Buscar o localizar elementos.
3. Borrar elementos.
4. Moverse a través de una lista, anterior, siguiente, primero.

Insertar un elemento en una lista vacía:


El proceso es muy simple

1 Crear el nodo Nuevo(Nodo)


2 Guardar la información
Nodo^<Valor, NULO>
3 nodo^.siguiente apunte a NULO
4 Lista apunte a nodo Lista  Nodo

Insertar un elemento en la primera posición de una lista:


El proceso sigue siendo muy sencillo:
1. Crear el Nodo
2. Guardar la información
3. Nodo^.siguiente apunte a Lista, que contiene la dirección del anterior primero.
4. Lista debe apuntar al nuevo nodo.

Insertar un elemento en la última posición de una lista:


Se supone una lista no vacía, el proceso en este caso tampoco es complejo, se necesita
un puntero que señale al último elemento de la lista. La manera de conseguirlo es
empezar por el primero y avanzar hasta que el nodo que tenga como siguiente el valor
NULO.
1. Auxiliar  primero
2. Al Nodo se le asigna el valor y NULO como siguiente Nodo^.  <valor,
NULO>
3. Avanzar hasta que Auxiliar^.siguiente apunte al valor NULO.
4. Hacer que Auxiliar^.siguiente apunte al nuevo Nodo y así queda enlazado.

Insertar un elemento a continuación de un nodo cualquiera de una lista:


En este caso, siguiendo el criterio del ejemplo anterior se hace que el nodo "anterior"
sea aquel a continuación del cual insertaremos el nuevo nodo:
Si ya se dispone del anterior y del nuevo nodo, el proceso a seguir será:
1. Hacer que Nodo^.siguiente apunte a anterior^.siguiente.
2. Hacer que anterior^.siguiente señale Nodo.

Recorrer una lista:


Las listas simplemente enlazadas sólo pueden recorrerse en un sentido, ya que cada
nodo apunta al siguiente.
Para recorrer una lista se utiliza un puntero auxiliar como índice:
1. Se le asigna al puntero índice el valor de Lista.
2. Se recorre con un ciclo de repetición que al menos debe tener una condición, que
el índice no sea NULO.
3. Dentro del Ciclo se asigna al índice el valor del nodo siguiente al índice actual.

Eliminar elementos en una lista

Eliminar el primer nodo de una lista abierta:


Es el caso más simple. Se parte de una lista con uno o más nodos, y se utiliza un
puntero auxiliar, Nodo:
1. Se hace apuntar a Nodo al primer elemento de la lista, es decir a Lista.
2. Se le asigna a Lista la dirección del segundo nodo de la lista:
ListaLista^.siguiente.
3. Se libera la memoria asignada al primer nodo, apuntado por Nodo.
Si la lista sólo tiene un nodo, el proceso es también válido, ya que el valor de
Lista^.siguiente es NULO, y después de eliminar el primer nodo la lista quedará vacía, y
el valor de Lista será NULO.

Eliminar un nodo cualquiera de una lista simplemente enlazada:


En todos los demás casos, eliminar un nodo se puede hacer siempre del mismo modo.
Supongamos que tener una lista con al menos dos elementos, y un puntero al nodo
anterior al que queremos eliminar. Y un puntero auxiliar nodo.

El proceso es parecido al del caso anterior:


Se busca que Nodo apunte al nodo a eliminar(1).
Se asigna como nodo siguiente del nodo anterior, el siguiente al que se quiere eliminar:
anterior^.siguiente = nodo^.siguiente.(2)
Se elimina la memoria asociada al nodo a eliminar.(3)

Si el nodo a eliminar es el último, es procedimiento es igualmente válido, ya que


anterior pasará a ser el último, y anterior^.siguiente valdrá NULO.

Moverse a través de una lista


Sólo hay un modo de moverse a través de una lista abierta, hacia delante.
Aún así, a veces necesitaremos acceder a determinados elementos de una lista abierta.
Veremos ahora como acceder a los más corrientes: el primero, el último, el siguiente y
el anterior.

Primer elemento de una lista:


El primer elemento es el más accesible, ya que es a ese a que apunta el puntero que
define la lista.
1. Para obtener un puntero al primer elemento bastará con copiar el puntero Lista.

Elemento siguiente a uno cualquiera:


Supongamos que tenemos un puntero nodo que señala a un elemento de una lista. Para
obtener un puntero al siguiente bastará con asignarle el campo "siguiente" del nodo,
nodo^.siguiente.

Elemento anterior a uno cualquiera:


Ya hemos dicho que no es posible retroceder en una lista, de modo que para obtener un
puntero al nodo anterior a uno dado tendremos que partir del primero, e ir avanzando
hasta que el nodo siguiente sea precisamente nuestro nodo, teniendo un puntero auxiliar
para contener el anterior.
Nodo = Primero
MIENTRAS no sea el nodo buscado HACER
Auxiliar = Nodo
Nodo = Nodo^.siguiente
FIN_MIENTRAS
Auxiliar apuntara al nodo anterior al buscado
Último elemento de una lista:
Para obtener un puntero al último elemento de una lista se parte del primer nodo y se
avanza hasta que el nodo apunte a NULO, el auxiliar apuntara al último. También se
puede preguntar anticipadamente por el valor NULO evitándose de este modo el
puntero auxiliar
Suponiendo la lista no vacía
Nodo = Primero;
MIENTRAS Nodo^.siguiente <> NULO HACER
Nodo  Nodo^.siguiente
FIN_MIENTRAS
En este caso Nodo, al final del ciclo apunta l último nodo de la estructura

Como determinar si una lista está vacía:


Basta con comparar el puntero Lista con NULLO si Lista vale NULO la lista está vacía.

Borrar una lista completa:


El algoritmo genérico para borrar una lista completa consiste simplemente en borrar el
primer elemento sucesivamente mientras la lista no esté vacía.

Algoritmo de inserción:
2. El primer paso es crear un nodo para el dato que vamos a insertar.
3. Si Lista es NULO, o el valor del primer elemento de la lista es mayor que el del
nuevo, insertaremos el nuevo nodo en la primera posición de la lista.
4. En caso contrario, se debe buscar el lugar adecuado para la inserción, tenemos
un puntero "anterior". Lo inicializamos con el valor de Lista, y avanzaremos
mientras anterior^.siguiente no sea NULO y el dato que contiene
anterior^.siguiente sea menor que el dato a insertar.
5. Ahora anterior señalando al nodo previo al insertar, por lo que se enlazan lo
puntero de modo que el siguiente del nuevo sea el que era siguiente del anterior
y al siguiente del anterior se lo hace apuntar al nuevo nodo. Se debe recordar que
anterior contiene el valor inmediato anterior al valor insertado y el siguiente es
mayor. El nuevo nodo debe intercalarse entre ambos.
En el capitulo de algoritmos puntuales se ofrecen varios ejemplos para insertar nodos en
situaciones distintas y con distintos fines

Algoritmo para borrar un elemento:


Para eliminar un nodo se necesita disponer de un puntero al nodo anterior.
1. Lo primero será localizar el nodo a eliminar, si es que existe. Pero sin perder el
puntero al nodo anterior.
2. Se parte del nodo primero, y del valor NULO para anterior.
3. Se avanza mientras nodo no sea NULO o mientras que el valor almacenado en
nodo sea menor que el que buscamos.
4. Ahora pueden darse tres casos:
5. Que el nodo sea NULO, esto indica que todos los valores almacenados en la lista
son menores que el que buscamos y el nodo que buscamos no existe. Entonces
se retorna sin borrar nada.
6. Que el valor almacenado en nodo sea mayor que el buscado, en ese caso también
se retorna sin borrar nada, ya que esto indica que el nodo que buscado no existe.
7. Que el valor almacenado en el nodo sea igual al buscado, nuevo existen dos
casos:
a. Que anterior sea NULO. Esto indicaría que el nodo que se quiere borrar
es el primero, así que se modifica el valor de Lista para que apunte al
nodo siguiente al que se quiere borrar.
b. Que anterior no sea NULO, el nodo no es el primero, así que se asigna a
anterior^.siguiente la dirección de nodo^.siguiente.
Después de 7 , se libera la memoria de nodo.

Implementación de algoritmos para listas


TPNodoListaCars = TIPO Apuntador a NodoListaCars;
NodoListaCars=TIPO <dato : carácter; sig TPNodoListaCars >;
ListaCars = TPNodoListaCars;
Veamos como podemos implementar, haciendo uso de esta representación, las
funciones de una posible especificación:
ListaVacia :  Lista
EsListaVacia : Lista  Booleano
Long : Lista  Entero
InsertaEnPos : Lista X Entero X TipoBase  Lista
BorraDePos : Lista X Entero  Lista
BuscaPos : Lista X TipoBase  Entero
BuscaElem : Lista X Entero  TipoBase
InsertaEnPos(lis:ListaCars;pos:Entero;e:Carácter)
ListaCars : una función
PRE { 1 ≤ pos ≤ Long(lis) + 1 }
LÉXICO
Res, p, q : TPNodoListaCars;
I : Entero;
ALGORITMO
Nuevo(p);
p↑.dato ← e;
SI pos = 1 ENTONCES
res ← p;
p↑.sig ← lis;
SI_NO
res ← lis;
q ← lis;
PARA i [3, pos] HACER
q ← q↑.sig
FIN_PARA;
p↑.sig ← q↑.sig;
q↑.sig ← p
FIN_SI;
InstertaEnPos ← res
FIN

BorraDePos(lis : ListaCars; pos : Entero)  ListaCars: una


función
PRE { 1 ≤ pos ≤ Long(lis) }
LÉXICO
res, q, p : TPNodoListaCars;
i : Entero;
ALGORITMO
SI pos = 1 ENTONCES
res ← lis↑.sig;
Destruir(lis)
SI_NO
res ← lis;
p ← lis;
i RECORRIENDO [2, pos] HACER
q ← p;
p ← p↑.sig
FIN_RECORRIENDO;
q↑.sig ← p↑.sig;
Destruir(p)
FIN_SI;
BorraDePos ← res
FIN

Listas circulares
Una lista circular es una lista lineal en la que el último nodo a punta al primero.
Las listas circulares evitan excepciones en la operaciones que se realicen sobre ellas. No
existen casos especiales, cada nodo siempre tiene uno anterior y uno siguiente.
En algunas listas circulares se añade un nodo especial de cabecera, de ese modo se evita
la única excepción posible, la de que la lista esté vacía.
El nodo típico es el mismo que para construir listas abiertas es una estructura
autoreferenciada que tiene un campo con la información y otro campo con un puntero a
una estructura del mismo tipo:

Lista es el puntero para contener el inicio de las listas, tanto abiertas como circulares.
En el caso de las circulares, apuntará a un nodo cualquiera de la lista.

A pesar de que las listas circulares simplifiquen las operaciones sobre ellas, también
introducen algunas complicaciones. Por ejemplo, en un proceso de búsqueda, no es tan
sencillo dar por terminada la búsqueda cuando el elemento buscado no existe.
Por ese motivo se suele resaltar un nodo en particular, que no tiene por qué ser siempre
el mismo. Cualquier nodo puede cumplir ese propósito, y puede variar durante la
ejecución del programa.
Otra alternativa que se usa a menudo, y que simplifica en cierto modo el uso de listas
circulares es crear un nodo especial de hará la función de nodo cabecera. De este modo,
la lista nunca estará vacía, y se eliminan casi todos los casos especiales.
Operaciones básicas con listas circulares
A todos los efectos, las listas circulares son como las listas abiertas en cuanto a las
operaciones que se pueden realizar sobre ellas:
1. Añadir o insertar elementos.
2. Buscar o localizar elementos.
3. Borrar elementos.
4. Moverse a través de la lista.
Cada una de estas operaciones podrá tener varios casos especiales, por ejemplo,
tendremos que tener en cuenta cuando se inserte un nodo en una lista vacía, o cuando se
elimina el único nodo de una lista.

Añadir un elemento:
El único caso especial a la hora de insertar nodos en listas circulares es cuando la lista
esté vacía.

Añadir elemento en una lista circular vacía:


Partiremos de que ya tenemos el nodo a insertar y un puntero que apunte a él, además el
puntero que define la lista, que valdrá NULO:

El proceso es muy simple:


1. lista apunta a nodo.
2. lista^.siguiente apunte a nodo.

Añadir elemento en una lista circular no vacía:


De nuevo partiremos de un nodo a insertar, con un puntero que apunte a él, y de una
lista, en este caso, el puntero no será nulo:
El proceso sigue siendo muy sencillo:
1. Nodo^.siguiente apunte a lista^.siguiente.
2. lista^.siguiente apunte a nodo.

Añadir elemento en una lista circular, caso general:


Para generalizar los dos casos anteriores, sólo necesitamos añadir una operación:
1. Si lista está vacía hacemos que lista apunte a nodo.
2. Si lista no está vacía, hacemos que nodo^.siguiente apunte a lista^.siguiente.
3. Después que lista^.siguiente apunte a nodo.

Buscar o localizar un elemento de una lista circular


Para buscar elementos en una lista circular sólo hay que tener una precaución, es
necesario almacenar el puntero del nodo en que se empezó la búsqueda, para poder
detectar el caso en que no exista el valor que se busca. Por lo demás, la búsqueda es
igual que en el caso de las listas abiertas, salvo que podemos empezar en cualquier
punto de la lista.

Eliminar un elemento de una lista circular:


Para ésta operación podemos encontrar tres casos diferentes:
1. Eliminar un nodo cualquiera, que no sea el apuntado por lista.
2. Eliminar el nodo apuntado por lista, y que no sea el único nodo.
3. Eliminar el único nodo de la lista.
En el primer caso necesitamos localizar el nodo anterior al que queremos borrar. Como
el principio de la lista puede ser cualquier nodo, haremos que sea precisamente lista
quien apunte al nodo anterior al que queremos eliminar.
Esto elimina la excepción del segundo caso, ya que lista nunca será el nodo a eliminar,
salvo que sea el único nodo de la lista.
Una vez localizado el nodo anterior y apuntado por lista, hacemos que lista^.siguiente
apunte a nodo^.siguiente. Y a continuación borramos nodo.
En el caso de que sólo exista un nodo, será imposible localizar el nodo anterior, así que
simplemente eliminaremos el nodo, y haremos que lista valga NULO

Eliminar un nodo en una lista circular con más de un elemento:


Considerando los dos primeros casos como uno sólo.
El primer paso es conseguir que lista apunte al nodo anterior al que se quiere eliminar.
1. Esto se consigue haciendo que lista valga lista^.siguiente mientras
lista^.siguiente sea distinto de nodo.
2. Se hacemos que lista^.siguiente apunte a nodo^.siguiente.
3. Se elimina el nodo.

Eliminar el único nodo en una lista circular:


Este caso es mucho más sencillo. Si lista es el único nodo de una lista circular:
1. Borramos el nodo apuntado por lista.
2. Hacemos que lista valga NULO.

Otro algoritmo para borrar nodos:


Existe un modo alternativo de eliminar un nodo en una lista circular con más de un
nodo.
Si se quiere eliminar un nodo apuntado por nodo:

1. Se copia el contenido del nodo^.siguiente sobre el contenido de nodo.


2. Se hace que nodo^.siguiente apunte a nodo^.siguiente^.siguiente.
3. Se elimina nodo^.siguiente.
Si lista es el nodo^.siguiente, se hace lista = nodo.

Este método también funciona con listas circulares de un sólo elemento, salvo que el
nodo a borrar es el único nodo que existe, y hay que hacer que lista apunte a NULO.

En una lista circular desde cualquier nodo se puede alcanzar cualquier otro. En una lista
simplemente enlazada apuntando a un nodo no es posible volver a nodos anteriores, es
necesario volver a recorrer desde el principio. En una lista circular apuntando a un nodo
se puede volver al predecesor recorriendo hacia delante.
El riesgo con esta estructura es que de no ser riguroso se puede caer en ciclos infinitos
la lista esta sin orden el puntero a lista puede apuntar, como señalamos a cualquier
nodo.
Estas lista tienen código sencillo pero ineficiente. Para insertar un nodo en esta lista sin
orden:
1. Si se aceptan repeticiones simplemente habrá que insertar el nodo en el lugar
donde se encuentra el puntero.
2. Si no se aceptan repeticiones habrá que recorrer la lista, sin caer en ciclos
infinitos para ver si el elemento a insertar ya existe. Para evitar ciclos
infinitos se debe:
a. Guardar en un puntero auxiliar el nodo donde se encuentra el comienzo
del recorrido.
b. Detener el ciclo al encontrar el dato, si es que esta o al igualar el puntero
de recorrido con el auxiliar.

Listas Circulares Ordenadas


En estas estructuras, como en las listas simplemente enlazadas se señala con un puntero
el inicio de la estructura. El código es un poco mas complejo que en las listas sin orden
pero mas eficientes ya que se evitan recorridos innecesarios.
La bibliografía discute donde debe apuntar el puntero al inicio de esta listas para
simplificar el código.
En las listas simplemente enlazadas para insertar un nodo y tener la dirección del
anterior para hacer la inserción se podía recorrer con dos punteros, uno que señala al
nodo actual y otro que señala al nodo anterior. También es posible evitarse el uso de dos
punteros preguntando el forma avanzada por el dato contenido en el próximo nodo.
En una lista circular no vacía ningún siguiente es NULO y el recorrido se hace con un
puntero preguntando en forma avanzada. Como en el recorrido se pregunta en forma
avanzada, el puntero debe apuntar al predecesor del primer nodo, esto por si la inserción
debiera hacerse delante del primer nodo.
Si hay un único nodo, predecesor y sucesor apuntan a dicho nodo.

Lista circular con header


Es una lista especial donde hay un nodo especial llamado HEADER, que guarda
información genérica sobre los otros nodos.
Por ejemplo si los nodos tienen los nombres de las personas y los sueldos, el nodo
HEADER podría tener la cantidad de nodos de la lista, excluyéndolo, el sueldo
promedio y el mínimo.
Para definir este tipo de registros los lenguajes de programación permiten definir
registros variantes o uniones, estas estructuras tienen un tratamiento similar a los
registros y pueden tener una parte fija y una parte variante en la que se solapa la
información.
Las ventajas que pueden señalarse entre las listas circulares con header y sin header es:
1. El Header guarda información genérica sobre la lista circular. No es
necesario recorrer la lista para obtener información global. Se debe tener en
cuenta que al insertar o eliminar un nodo de la lista se debe actualizar la
información de header para que sea consistente.
2. El código se simplifica porque el header esta siempre, aunque la lista este
vacía. En este caso el problema de poner el puntero a la lista esta resuelto, se
coloca siempre en el header.

Lista Circular Ordenada con HEADER

Definiciones
Nodo = (header, común) // enumera dos valores posibles si es header o común.
TipoPunteroCircularCon Header = TIPO Apuntador a TipoNodo;
TipoNodo = <
Sig : TipoPuntero;
Según tag: Nodo
Header : (cant: Entero; promedio Real; mínimo Real);
// parte del nodo cabecera//
común : (nombre Cadena; Sueldo : Real)
// Parte común del resto de los nodos//
FIN_SEGUN
>;
TipoDato = <nombre : Cadena; sueldo : Rel>

CrearVacia (Dato_Resultadolch_TipoPunteroCircularConHeader): una acción


ALGORITMO
Nuevo(lch);
Lch^.tag  header
Lch^.cant  0;
Lch^.promedio  0;
Lch^.Minimo  ValorAlto;
Lch^.sig  lch
FIN

esVacia (DATO lch: TipoPunteroCircularConHeader): booleano UNA ACCION


// si el siguiente es el mismo nodo entonces solo hay un nodo y este es el header//
ALGORITMO
esVacia  lch = lch^.sig
FIN

insertarOrdenado(DATO_RESULTADO lch :TipoPunterCircularConHeader; DATO


dato: TipoDato)
ALGORITMO
SI (Dato.sueldo < lcj^.Minimo)
ENTONCES
Lch^.cant = Lch^.cant + 1
// el resto de las operaciones generales//
FIN_SI
Salir  Falso
REPETIR
SI (lch^.sig^.nombre < dato.nombre)
ENTONCES
Lch  lch^.sig
SINO
Salir  verdadero
FIN_SI
HASTA que (salir o lch^.sig.tag = header)
Nuevo(Aux)
Aux^.sig  lch^.sig
Lch^.sig  aux
Aux^.nombre  dato.nombre
Aux^.sueldo  dato.sueldo
Aux^.tag  común
FIN

ImprimirOrdenado(DATO lch :TipoPunterCircularConHeader)


ALGORITMO
REPETIR
Imprimir(lch^.sig^.nombre)
Imprimir(lch^.sig^.sueldo)
Lch  lch^.sig
HASTA QUE lch^.sig^.tag = header
FIN

Listas doblemente enlazadas


Una lista doblemente enlazada es una lista lineal en la que cada nodo tiene dos enlaces,
uno al nodo siguiente, y otro al anterior.
Las listas doblemente enlazadas no necesitan un nodo especial para acceder a ellas,
pueden recorrerse en ambos sentidos a partir de cualquier nodo, esto es porque a partir
de cualquier nodo, siempre es posible alcanzar cualquier nodo de la lista, hasta que se
llega a uno de los extremos.
El nodo típico es el mismo que para construir las listas que hemos visto, salvo que
tienen otro puntero al nodo anterior:

El movimiento a través de listas doblemente enlazadas es más sencillo, y como veremos


las operaciones de búsqueda, inserción y borrado, también tienen más ventajas.

Operaciones básicas con listas doblemente enlazadas


Es imilar al de listas:
1. Añadir o insertar elementos.
2. Buscar o localizar elementos.
3. Borrar elementos.
4. Moverse a través de la lista, siguiente y anterior.

Añadir un elemento:
La estructura s diferente a las vistas anteriormente por lo que se analizaran todos los
casos posibles de inserción.

Añadir elemento en una lista doblemente enlazada vacía:


también se parte que se dispone del nodo a inserta y el puntero que define la lista, que
valdrá NULO:
El proceso es muy simple:
lista apunta a nodo.
Lista^.siguiente y lista^.anterior apunten a NULO.

Insertar un elemento en la primera posición de la lista:


Se parte de una lista no vacía y lista apunta al primer elemento de la lista doblemente
enlazada:

El proceso es el siguiente:
Nodo^.siguiente debe apuntar a Lista.
Nodo^.anterior apuntará a Lista^.anterior.
Lista^.anterior debe apuntar a nodo.

Lista no tiene por qué apuntar a ningún miembro concreto de una lista doblemente
enlazada, cualquier miembro es igualmente válido como referencia.

Insertar un elemento en la última posición de la lista:


Igual que en el caso anterior, se parte de una lista no vacía, y de nuevo para simplificar,
que Lista está apuntando al último elemento de la lista:
El proceso es el siguiente:
1. Nodo^.siguiente debe apuntar a Lista^.siguiente (NULO).
2. Lista^.siguiente debe apuntar a nodo.
3. Nodo^.anterior apuntará a Lista.

Insertar un elemento a continuación de un nodo cualquiera de una lista:


Bien, este caso es más genérico, ahora partimos de una lista no vacía, e insertaremos un
nodo a continuación de uno nodo cualquiera que no sea el último de la lista:

El proceso sigue siendo muy sencillo:


1. Que Nodo^.siguiente apunte a lista^.siguiente.
2. Que Lista^.siguiente apunte a nodo.
3. Que nodo^.anterior apunte a lista.
4. Que nodo^.siguiente^.anterior apunte a nodo.

Añadir elemento en una lista doblemente enlazada, caso general:


1. Si lista está vacía se hace que Lista apunte a nodo, y nodo^.anterior y
nodo^.siguiente a NULO.
2. Si lista no está vacía, entonces que nodo^.siguiente apunte a Lista^.siguiente.
3. Luego que Lista^.siguiente apunte a nodo.
4. Que nodo^.anterior apunte a Lista.
5. Si nodo^.siguiente no es NULO, entonces nodo^.siguiente^.anterior apunte a
nodo.

Buscar un elemento de una lista doblemente enlazada


En muchos aspectos, una lista doblemente enlazada se comporta como dos listas
abiertas que comparten los datos. Pero además se tiene la ventaja que se puede avanzar
y retroceder desde cualquier nodo, sin necesidad de volver a uno de los extremos de la
lista.
Para recorrer una lista se procede de un modo parecido al que definió con las listas
simplemente enlazadas, ahora no se necesita un puntero auxiliar, y debe tenerse en
cuenta que Lista no tiene por qué estar en uno de los extremos:
Se retrocede hasta el comienzo de la lista, asignando a lista el valor de lista^.anterior
mientras lista^.anterior no sea NULO.
Se abre un ciclo de repetición que al menos debe controlar que el puntero no sea NULO.
Dentro del ciclo se le asigna a lista la dirección del nodo siguiente.

Eliminar un elemento de una lista doblemente enlazada:


Se Analizan cuatro casos diferentes:
1. Eliminar el único nodo de una lista doblemente enlazada.
2. Eliminar el primer nodo.
3. Eliminar el último nodo.
4. Eliminar un nodo intermedio.
Para los casos que lo permitan consideraremos dos casos: que el nodo a eliminar es el
actualmente apuntado por Lista o que no.

Eliminar el único nodo en una lista doblemente enlazada:

En este caso, ese nodo será el apuntado por Lista.


1. Eliminamos el nodo.
2. Hacemos que Lista apunte a NULL.
Eliminar el primer nodo de una lista doblemente enlazada:
Se tienen los dos casos posibles, que el nodo a borrar esté apuntado por Lista o que no.
Si lo está, simplemente hacemos que Lista sea Lista^.siguiente.

1. Si nodo apunta a Lista, se hace que Lista apunte a Lista^.siguiente.


2. que nodo^.siguiente^.anterior apunte a NULO
3. Borramos el nodo apuntado por nodo.

El paso 2 separa el nodo a borrar del resto de la lista, independientemente del nodo al
que apunte Lista.

Eliminar el último nodo de una lista doblemente enlazada:


De nuevo tenemos los dos casos posibles, que el nodo a borrar esté apuntado por Lista o
que no. Si lo está, simplemente hacemos que Lista sea Lista^.anterior.

1. Si nodo apunta a Lista, se hace que Lista apunte a Lista^.anterior.


2. que nodo^.anterior^.siguiente apunte a NULL
3. Se Borra el nodo apuntado por nodo.

Eliminar un nodo intermedio de una lista doblemente enlazada:


De nuevo tenemos los dos casos posibles, que el nodo a borrar esté apuntado por Lista o
que no.
Si lo está, simplemente hacemos que Lista sea Lista^.anterior o Lista^.siguiente
Se trata de un caso más general de los dos casos anteriores..
1. Si nodo apunta a Lista, se hace que Lista apunte a Lista^.anterior (o
Lista^.siguiente).
2. que nodo^.anterior^.siguiente apunte a nodo^.siguiente.
3. que nodo^.siguiente^.anterior apunte a nodo^.anterior.
4. Borrar el nodo apuntado por nodo.

Eliminar un nodo de una lista doblemente enlazada, caso general:


1. De nuevo están los dos casos posibles, que Si nodo apunta a Lista,
2. Si Lista^.anterior no es NULO se hace que Lista apunte a Lista^.anterior.
3. Si Lista^.siguiente no es NULO se hace que Lista apunte a Lista^.siguiente.
4. Si ambos son NULO, se hace que Lista sea NULO.
5. Si nodo^.anterior no es NULO, se hace que nodo^.anterior^.siguiente apunte
a nodo^.siguiente.
6. Si nodo^.siguiente no es NULO, Se hace que nodo^.siguiente^.anterior
apunte a nodo^.anterior.
7. Se borra el nodo apuntado por el nodo a borrar esté apuntado por Lista o que
no. Si lo está, simplemente hacemos que Lista sea Lista^.anterior, si no es
NULO o Lista^.siguiente en caso contrario.
A modo de síntesis con estructuras enlazadas
Listas simplemente enlazadas: cada elemento sólo dispone de un puntero, que
apuntará al siguiente elemento de la lista o valdrá NULO si es el último elemento.
Pilas: son un tipo especial de lista, conocidas como listas LIFO (Last In, First Out: el
último en entrar es el primero en salir).
Colas: otro tipo de listas, conocidas como listas FIFO (First In, First Out: El primero en
entrar es el primero en salir).
Listas circulares no ordenadas: el último elemento apunta al primero. Cualquier nodo
puede ser el nodo de entrada y salida.
Lista circular ordenada: por convención el puntero a la lista circular apunta al
predecesor del primer nodo.
Lista con Header: Existe un nodo especial donde se guarda información genérica sobre
los demás nodos.
Listas doblemente enlazadas: cada elemento dispone de dos punteros, uno a punta al
siguiente elemento y el otro al elemento anterior.
Árboles: cada elemento dispone de dos o más punteros, pero las referencias nunca son a
elementos anteriores, de modo que la estructura se ramifica y crece igual que un árbol.
Árboles binarios: son árboles donde cada nodo sólo puede apuntar a dos nodos.
Árboles binarios de búsqueda (ABB): son árboles binarios ordenados. Desde cada
nodo todos los nodos de una rama serán mayores, según la norma que se haya seguido
para ordenar el árbol, y los de la otra rama serán menores.
Árboles AVL: son también árboles de búsqueda, pero su estructura está más optimizada
para reducir los tiempos de búsqueda.
Árboles B: son estructuras más complejas, aunque también se trata de árboles de
búsqueda, están mucho más optimizados que los anteriores.
Tablas HASH: son estructuras auxiliares para ordenar listas.
Grafos: es el siguiente nivel de complejidad, podemos considerar estas estructuras
como árboles no jerarquizados.
Diccionarios. Se implementan con tablas Hash para la búsqueda.
ALGORITMOS PUNTUALES
Objetivos de aprendizaje
Dominando los temas del presente capitulo Usted podrá.
1. Evaluar algoritmos puntuales aplicables a distintas estructuras de datos.
2. Conocer las precondiciones para la utilización de algoritmos puntuales

Introducción
Se describen a continuación un conjunto de algoritmos puntuales para el manejo de
estructuras estáticas y dinámicas. Con una descripción breve de las precondiciones y
poscondiciones, utilizando definiciones genéricas para todos los casos

Definiciones de tipos
Definiciones de los tipos de datos utilizados en los algoritmos que se describen
MAX_FIL = 100;
Tinfo = TIPO Entero;
TinfoC = TIPO <C1 : Td1, C2 : Td2>
TVector = TIPO Tabla [1,MAX_FIL] de Tinfo;
TPNodo = TIPO Apuntador a Nodo;
Nodo = TIPO <Info : Tinfo; sgte : TPNodo>
Arbol = TIPO <Info : Tinfo; Izq, Der : TPArbol>

Acciones y funciones para vectores


BusqSecEnVector(Dato V: Tvector; Dato N: Entero; Dato Clave:Tinfo;
Dato_resultado Posic: Entero): una accion
Usar este algoritmo si alguna de las otras búsquedas en vectores mas eficientes no son
posibles, recordando que búsqueda directa tiene eficiencia 1, búsqueda binaria es
logarítmica y búsqueda secuencial es de orden N
PRE: V: Vector en el que se debe buscar
Clave : Valor Buscado
N: Tamaño lógico del vector
POS: Posic: Posición donde se encuentra la clave, 0 (Cero) si no esta.
LEXICO
j : Entero; Controla No superar el tamaño fisico del vector j<= MAX_FIL
No leer mas alla del ultimo elemento logico cargado j <= N
ALGORITMO Salir si es que encuentra la clave buscada V[j] <> clave
Posic = 0;
j = 1; //Pone el indice en la primera posición para recorrer el vector//
MIENTRAS (j <= MAX_FIL y j <= N y V[j] <> Clave) HACER
Inc (j) //Incrementa el indice para avanzar en la estructura//
FIN_MIENTRAS;
SI (j > N)
ENTONCES
Posic =0 // No encontró la clave buscada
SI_NO
Posic = j // Encontró la clave en la posición de índice j
FIN_SI;

FIN. // Búsqueda secuencial En Vector


BusqMaxEnVector(Dato V: Tvector; Dato N: Entero; Dato_resultado Maximo :Tinfo;
Dato_resultado Posic: Entero): una acccion
PRE: V: Vector en el que se debe buscar (sin orden)
N : Tamaño lógico del vector
POS: Posic: Posición donde se encuentra el máximo
Maximo : Valor máximo del vector.
LEXICO
j : Entero; Supone que el maximo es el primer valor del vector por lo que le asigna ese
ALGORITMO valor a maximo y la posición 1 a la posición del maximo. Al haber leido solo un
elemento supone ese como maximo
Posic = 1;
Maximo = V[1];
PARA j [2, N] HACER Recorre ahora las restantes posiciones del vector, a partir de la
SI (v[j] > Maximo) segunda y lcada vez que el valor leido supera al maximo
contiene ese valor como maximo y el indice actual como posición
ENTONCES del maximo
Posic = j;
Maximo = v[j];
FIN_SI;
FIN_PARA;

FIN. // Búsqueda máximo En Vector

BusqMinDistCeroEnVector(Dato V: Tvector; Dato N: Entero; Dato_resultado


Minimo :Tinfo; Dato_resultado Posic: Entero): una acccion
PRE: V: Vector en el que se debe buscar (sin orden)
N : Tamaño lógico del vector, existe al menos un valor <> de cero
POS: Posic: Posición donde se encuentra el minimo distinto de cero
Minimo : Valor minimo distinto de cero del vector.
LEXICO
i,j : Entero; Recorre el vector hasta encontrar el primero distinto de cero.
ALGORITMO Al encontrarlo supone ese valor como minimo y el valor del
indice como posición del minimo
//
J = 1;
Mientras (J<=N) Y (V[j] = 0) Hacer
Incrementar[j];
Posic = J;
Minimo = V[j];
PARA j [Posic.+1 , N] HACER Recorre el vector desde la posición inmediata
siguiente hasta la ultima desplazando el minimo
SI (v[j]<> 0 Y v[j] < Minimo) solo si el valor es distinto de cero y, ademas,
ENTONCES menor que el minimo
Posic = j;
Minimo = v[j];
FIN_SI;
FIN_PARA;

FIN. // Búsqueda minimo distinto de cero En Vector

BusqMaxySiguienteEnVector(Dato V: Tvector; Dato N: Entero; Dato_resultado


Maximo :Tinfo; Dato_resultado Posic: Entero, Dato_resultado Segundo :Tinfo;
Dato_resultado PosicSegundo: Entero): una accion
PRE: V: Vector en el que se debe buscar
N : Tamaño lógico del vector mayor o gual a 2
POS: Posic: Posición donde se encuentra el máximo, PosicSegundo: Posición donde se
encuentra el siguiente al máximo
Maximo : Valor máximo del vector. Segundo : Valor del siguiente al máximo del vector
LEXICO
j : Entero;
ALGORITMO
SI V[1] > V[2]
ENTONCES
Posic = 1;
Maximo = V[1]; Se tiene como precondicion que al menos hay dos
PosicSegund = 2; valores. Se verifica el valor que esta en la primera
posición y se lo compara con el que esta en la
Segundo = V[2]; segunda posición, en el caso de ser mayor, el
SINO maximo es ese valor, posición del máximo es uno,
Posic = 2; el segundo el valor que esta en segundo lugar y
posición del segundo es 2. En caso contrario se
Maximo = V[2]; establece como maximo el valor de la segunda
PosicSegund =1; posición y segundo el de la primera.
Segundo = V[1];

FIN_SI

PARA j [3, N] HACER Se verifica luego desde la tercera


SI (v[j] > Maximo) posición hasta el final. En el caso
que el nuevo valor sea mayor que
ENTONCES el maximo, se debe contener el
Segundo = Maximo; anterior maximo en el segundo y al
PosicSegundo = Posic; maximo se le asigna el nuevo
valor. Cosa similar hay que hacer
Posic = j; con las posiciones. Si esto no
Maximo = v[j]; ocurriera se debe verificar si el
SINO nuevo valor supera al segundo, en
ese caso debera desplazarlo
SI Maximo>Segundo
ENTONCES
Segundo = V[j];
PosicSegundo = j
FIN_SI
FIN_SI;
FIN_PARA;

FIN. // Búsqueda máximo En Vector

CargaSinRepetirEnVectorV1(Dato_Resultado V: Tvector; Dato_Resultado N: Entero;


Dato Clave:Tinfo; Dato_resultado Posic: Entero; Dato_resultado Enc : Booleano): una
accion
Utilizar este algoritmo si la cantidad de claves diferentes es fija, se dispone de memoria
suficiente como para almacenar el vector y la clave no es posicional(es decir clave e
índice no se corresponden directamente con posición única y predecible.Si la posición
fuera unica y predecible la busqueda debe ser directa
PRE: V: Vector en el que se debe buscar
Clave : Valor Buscado
N : Tamaño lógico del vector
POS: Posic: Posición donde se encuentra la clave, o donde lo inserta si no esta.
Retorna
0 (cero) en caso que el vector esta completo y no lo encuentra
Enc : Retorna True si estaba y False si lo inserto con esta invocación
Carga vector sin orden
LEXICO
j : Entero;
Controla No superar el tamaño fisico del vector j<= MAX_FIL
ALGORITMO/ No leer mas alla del ultimo elemento logico cargado j <= N
Posic = 0; Salir si es que encuentra la clave buscada V[j] <> clave
J = 1;
MIENTRAS (j <= MAX_FIL y j <= N y V[j] <> Clave) HACER
Inc (j)
FIN_MIENTRAS; Si debio superar el tamaño fisico maximo del vector no pudo
SI j > MAX_FIL cargarlo y retorna cero como señal de error
ENTONCES
Posic = 0 Si encontro un dato o lo debe cargar esto es en el indice j por lo
SI_NO que a pos se se asigna ese valor. En el caso que j sea mayor que
n significa que recorrio los n elemntos cargados del vector, tiene
Posic = j: estpacio por lo que debe cargar el nuevo en la posición j. En este
SI (j > N) caso, y al haber un elemento nuevo debe incrementar n que es el
ENTONCES identificador que controla el tamaño logico del vector

Enc =FALSE; // No encontró la clave buscada


Inc(N);
V[N] = Clave;
SI_NO
Enc = True // Encontró la clave en la posición de índice j
FIN_SI;
FIN_SI
FIN. // Carga sin repetir en vector

BusquedaBinariaEnVectorV1(Dato V: Tvector; Dato N: Entero; Dato Clave:Tinfo;


Dato_resultado Posic: Entero; Dato_resultado Pri : Entero): una accion
Utilizar este algoritmo si los datos en el vector están ordenados por un campo clave y
se busca por ese campo. Debe tenerse en cuenta que si la clave es posicional se deberá
utilizar búsqueda directa ya que la diferencia en eficiencia esta dada entre 1, para la
búsqueda directa y log2N para la binaria
PRE: V: Vector en el que se debe buscar con clave sin repetir
Clave : Valor Buscado
N : Tamaño lógico del vector
POS: Posic: Posición donde se encuentra la clave, o 0 (cero) si no esta
Pri : Retorna la posición del limite inferior

LEXICO Establece valores para las posiciones de los elementos del vector, Pri
j : Entero; contiene el indice del primero, es decir el valor 1, U el indice del ultimo
elemento logicio, es decir N. Ademas se coloca en Posic. El valor cero,
u,m : Entero; utilizando este valor como bandera para salir del ciclo cuando encuentar
ALGORITMO el valor buscado
Posic = 0;
Pri = 1;
U = N;
MIENTRAS (Pri < = U y Pos = 0) HACER
M = (Pri + U ) div 2 Permanece en el ciclo mientras no encuentre lo
buscado, al encontrarlo le asigna a pos el indice
donde lo encontro, como es un valor > que cero
hace false la expresión logica y sale del ciclo. Si no
lo encuentra, y para evirtar ciclo infinito verifica
que el primero no tome un valor mayor que el
ultimo. Si eso ocurre es que el dato buscado no esta
y se debe salir
SI V[M] = Clave
ENTONCES
Posic = M;
SI_NO
SI Clave > V[M]
ENTONCES
Pri = M+1
SI_NO
U=M–1 Si el dato buscado lo encuentra le asigna a posición
FIN_SI el indice para salir. Si no lo encuentra verifica si
esmayor el dato buscabo a lo que se encuentra
FIN_SI revisa en la mitad de los mayores por lo que le
FIN_MIENTRAS; asigna al primero el indice siguiente al de la mitad
dado que alli no estab y vuelve a dividir el conjunto
de datos en la mitas, de ser menor pone como tome
FIN. // Búsqueda binaria en vector ultimo el anterior al de la mitad actual

BusquedaBinariaEnVectorV2(Dato V: Tvector; Dato N: Entero; Dato Clave:Tinfo;


Dato_resultado Posic: Entero; Dato_resultado Pri : Entero): una acccion
PRE: V: Vector en el que se debe buscar clave puede estar repetida
Clave : Valor Buscado
N : Tamaño lógico del vector
POS: Posic: Posición donde se encuentra la primera ocurrencia de la clave.
0 (cero) si no esta.
Pri : Retorna la posición del limite inferior

LEXICO
j : Entero;
u,m : Entero;
ALGORITMO
Posic = 0; La busqueda es bastante parecida a lo
Pri = 1; desarrollado anteriormente, pero en pos debe
tener la primera aparicion de la clave buscada
U = N; que puede repetirse.
MIENTRAS (Pri < U ) HACER En la busqueda anterior utilizabamos esta pos
M = (Pri + U ) div 2 como bandera, para saber cuando Sali si lo
encontro. En este caso si lo utilizamos con el
SI V[M] = Clave mismo proposito saldria cuando encuentra un
ENTONCES valor oincidente con la clave que no
Posic = M; necesariamente es el primero, por lo que esa
condicion se elimina. Al encontrarlo en m se le
Pri = M; asigna ese valoe a pos, alli seguro esta. No
SI_NO sabemos si mas arriba vuelve a estar por lo que
SI Clave > V[M] se asigna tambien esa posición al ultimo para
seguir iterando y ver si lo vuelve a encontrar.
ENTONCES Debe modificarse el operador de relacion que
Pri = M+1 compara primero con ultimo para evitar un
SI_NO ciclo infinito, esto se hace eliminando la
relacion por igual. Insisto en el concepto de los
U=M–1 valores de retorno de la busqueda binaria. Una
FIN_SI particularidad de los datos es que si lo que se
FIN_SI busca no esta puede retornal en el primero la
posición donde esa clave deberia estar
FIN_MIENTRAS;

FIN. // Búsqueda binaria en vector


CargaSinRepetirEnVectorV2(Dato_Resultado V: Tvector; Dato_Resultado N: Entero;
Dato Clave:Tinfo; Dato_resultado Posic: Entero; Dato_resultado Enc : Booleano): una
acccion
PRE: V: Vector en el que se debe buscar ordenado por clave
Clave : Valor Buscado
N : Tamaño lógico del vector
La busqueda es bastante parecida a lo desarrollado anteriormente, pero en pos debe tener la primera
aparicion de la clave buscada que puede repetirse.
En la busqueda anterior utilizabamos esta pos como bandera, para saber cuando Sali si lo encontro.
En este caso si lo utilizamos con el mismo proposito saldria cuando encuentra un valor oincidente
con la clave que no necesariamente es el primero, por lo que esa condicion se elimina. Al encontrarlo
en m se le asigna ese valoe a pos, alli seguro esta. No sabemos si mas arriba vuelve a estar por lo que
se asigna tambien esa posición al ultimo para seguir iterando y ver si lo vuelve a encontrar. Debe
modificarse el operador de relacion que compara primero con ultimo para evitar un ciclo infinito,
esto se hace eliminando la relacion por igual. Insisto en el concepto de los valores de retorno de la
busqueda binaria. Una particularidad de los datos es que si lo que se busca no esta puede retornal en
el primero la posición donde esa clave deberiaestar
POS: Posic: Posición donde se encuentra la clave, o donde lo inserta si no esta.
Retorna
0 (cero) en caso que el vector esta completo y no lo encuentra
Enc : Retorna True si estaba y False si lo inserto con esta invocación
Carga vector Ordenado
LEXICO Al estar el vector ordenadola busqueda puede ser binaria, si lo
encuentra retorna en posición un valor mayor a cero. Si no lo
j : Entero; encuentra el valor de posición sera cero. En este caso, se conoce
ALGORITMO que en pri es en la posición donde este valor debe estar
Enc = True;
BusquedaBinariaEnVectorV(V; N; Clave; Posic; Pri)
SI (Posic = 0)
ENTONCES
Enc = False ; Se produce un desplazamiento de los valores
desde el ultimo hasta el valor de pri
Posic = Pri; corriendolos un lugar para poder insertar en
PARA j [N, Pri](-) HACER la posición pri el nuevo valos. Al pasar por
V[j+1] = V[j]; aquí se inserto un nuevo elemento por lo que
n, que contiene la cantidad de elementos del
FIN_PARA; vector debe incrementarse en uno
V[Pri] = Clave;
Inc(N);
FIN_SI
FIN. // Carga sin repetir en vector Versión 2. con vector ordenado

OrdenarVectorBurbuja(Dato_Resultado V: Tvector; Dato N: Entero): una acccion


Pre: V: Vector en el que se debe ordenar, se supone dato simple
N : Tamaño lógico del vector
POS: Vector ordenado por clave creciente
Usar este algoritmo cuando los datos contenidos en un vector deben ser ordenados. Se
podría por ejemplo cargar los datos de un archivo al vector, ordenar el vector
recorrerlo y generar la estructura ordenada. Para esto la cantidad de elementos del
archivo debe ser conocida y se debe disponer de memoria suficiente como para
almacenar los datos. Una alternativa, si la memoria no alcanza para almacenar todos
los datos podría ser guardar la clave de ordenamiento y la referencia donde encontrar
los datos, por ejemplo, la posición en el archivo.
La idea general es ir desarrollando pasos sucesivos en cada uno de los cuales ir
dejando el mayor de los elementos en el último lugar. En el primer paso se coloca el
mayor en la ultima posición, en el paso siguiente se coloca el que le sigue sobre ese
y asi hasta que queden dos elemntos. En ese caso al acomodar el segundo el otro
queda acomodado el primer ciclo cuenta los pasos, son uno menos que la cantidad
de elementos porque el ultimo paso permite acomodar 2 elementos, por eso el ciclo
se hace entre 1 y N – 1 siendo n la cantidad de elementos
LEXICO
I,J, : Entero;
Aux : Tinfo;
ALGORITMO
PARA i [1, N - 1] HACER
PARA j [1, N - i] HACER
SI (v[j] > v[j + 1])
ENTONCES
Aux = v[j]; Para poder colocar el mayor al final es necesario
hacer comparaciones. Se compara el primero con el
V[j] = v[j + 1]; segundo y si corresponde se intercambian. Asi hasta
V[j + 1] = Aux; llegar al ante ultimo eleemento que se lo compara
FIN_SI; con el últim.
Al ir recorriendo los distintos pasos, y dado que en
FIN_PARA; cada uno se acomoda un nuevo elemento
FIN_PARA; corresponde hacer una comparación menos en cada
FIN avance, como los pasos los recorremos con i, las
comparaciones seran n – i. disminuye en 1 en cada
paso

OrdenarVectorBurbujaMejorado(Dato_Resultado V: Tvector; Dato N: Entero): una


acccion
PRE: V: Vector en el que se debe ordenar, se supone dato simple
N : Tamaño lógico del vector
POS: Vector ordenado por clave creciente

LEXICO
I,J, : Entero;
Aux : Tinfo;
Ord : Boolean;
ALGORITMO El algoritmo es similar al anterior, solo que
I = 0; el ciclo de repetición externo no lo hace si es
REPETIR que tiene la certeza, en el paso anterior que
los datos ya estan ordenados. Es por eso que
Inc(i); agrega una bandera para verificar si ya esta
Ord = TRUE; ordenado y cambia el cilo exactp por un
PARA j [1, N - i] HACER ciclo pos condicional. Es decir reemplaza la
composición para por la composición repetir
SI (v[j] > v[j + 1]) hasta
ENTONCES
Ord = False;
Aux = v[j];
V[j] = v[j + 1];
V[j + 1] = Aux;
FIN_SI;
FIN_PARA;
HASTA ( Ord o I = N – 1);
FIN

OrdenarVectorInserion(Dato_Resultado V: Tvector; Dato N: Entero): una accion


PRE: V: Vector en el que se debe ordenar, se supone dato simple
N : Tamaño lógico del vector
POS: Vector ordenado por clave creciente
Este algoritmo consta de los siguientes pasos
El primer elemento A[0] se lo considera ordenado; es decir se considera el array con
un solo elemento.
Se inserta A[1] en la posicion correcta, delante o detras de A[0] segun sea mayor o
menor.
Por cada iteracion, d i desde i=1 hasta n-1, se explora la sublista desde A[i-1] hasta
A[0],buscando la posicion correcta de la insercion ; a la vez se mueve hacia abajouna
posicion todos los elementos mayores que el elemento a insertar A[i] para dejar vacia
la posicion.
Insertar el elemento en l posicion correcta.

LEXICO
I,J, : Entero;
Aux : Tinfo;

ALGORITMO
PARA I[1..N-1]
J = I;
Aux = A[i] ;
MIENTRAS (J >0 Y AUX < A[J - 1])HACER
A[J] = A[J - 1] ;
Dec(J) ;
FIN MIENTRAS ;
A[J] = Aux ;
FIN PARA;
FIN

OrdenarVectorShell(Dato_Resultado V: Tvector; Dato N: Entero): una acccion


PRE: V: Vector en el que se debe ordenar, se supone dato simple
N : Tamaño lógico del vector
POS: Vector ordenado por clave creciente
Este algoritmo consta de los siguientes pasos
Dividir la lista original en n/2 grupos de dos, considerando un incremento o salto entre
los elementos en n/2.
Analizar cada grupo por separado comparandolas parejas de elementos, y si no estan
ordenados, se intercambian .
Se divide ahora la lista en la mitad n/4, con un incremento tambien en n/4 y nuevamente
se clasifica cada grupo por separado.
Se sigue dividiendo la lista en la mitad de grupos que en el paso anterior y se clasifica
cada grupo por separado.
El algoritmo termina cuando el tamaño del salto es 1.

ALGORITMO
Intervalo = n / 2;

MIENTRAS Intervalo > 0 HACER


PARA I [Intervalo + 1 .. N] HACER
MIENTRAS (J > 0) HACER
K = J + Intervalo;
SI (A[J] <= A[K]
ENTONCES
J = -1
SINO
Intercambio(A[J] ,A[K]) ;
J = J – Intervalo ;
FINSI ;
FIN PARA ;
FIN MIENTRAS;
FIN.

CorteDeControlEnVector(Dato V:Tvector; Dato N: Entero): una acccion


Usar este procedimiento solo si se tienen los datos agrupados por una clave común y se
requiere procesar emitiendo información por cada subconjunto correspondiente a cada
clave.
PRE: V: Vector en el que se debe Recorrer con corte de control
Debe tener un elemento que se repite y estar agrupado por el.
N : Tamaño lógico del vector
POS: Recorre agrupando por una clave

LEXICO
I : Entero;

ALGORITMO
I = 1;
Anterior = TipoInfo;
// Inicializar contadores generales
MIENTRAS (I<=N) Hacer
//inicializar contadores de cada sublote
Anterior = V[i]
MIENTRAS (I<=N Y Anterior = V[i] HACER
// Ejecutar acciones del ciclo

I = I+1 // avanza a la siguiente posición


FIN_MIENTRAS
// Mostrar resultados del sublote
FIN_MIENTRAS
// Mostrar resultados generales
FIN

ApareoDeVectores(Dato V1,v2:Tvector; Dato N1,N2: Entero): una acccion


Utilizar este procedimiento si se tiene mas de una estructura con un campo clave por el
que se los debe procesar intercalado y esas estructuras están ORDENADAS por ese
campo común.
PRE: V1,V2: Vectores a Recorrer mezclados o intercalados
Los vectores deben estar ordenados.
N1,N2 : Tamaño lógico de los vectores
POS: Muestra la totalidad de los datos con el orden de las estructuras
LEXICO
I,J : Entero;
ALGORITMO
I = 1;
J = 1;

MIENTRAS (I<=N1 o J<=N2) Hacer


SI((J > N2) o ((I<=N1) y (V1[I]<V2[J])) HACER
ENTONCES
Imprimir (V1[I]);
I = I + 1;
SINO
Imprimir(V2[J]);
J = J + 1;
FIN_SI;
FIN_MIENTRAS

FIN

CargaNMejoresEnVector(Dato_Resultado V: Tvector; Dato_Resultado N: Entero;


Dato Clave:Tinfo): una acccion
PRE: V: Vector en el que se debe buscar e insertar los mejores
Clave: Valor Buscado
N: Tamaño lógico del vector
POS: Vector con los N mejores sin orden
LEXICO
j : Entero;
Maximo: Tinfo
Posic: Entero;
ALGORITMO
SI (N < MAX-FIL)
ENTONCES
Inc (N);
V[n] = Clave
SI_NO
BusqMaxEnVector(V; N; Maximo :Tinfo; Posic: Entero);
SI (Clave > Maximo)
ENTONCES
V[Posic] = Clave;
FIN_SI;
FIN_SI;
FIN. // Carga los N mejores en vector

Acciones y funciones para archivos


Se identifican dos tipos de archivos, archivos de texto y archivos biarios. Los archivos
de texto son un conjunto de lineas las cuales tienen 0, 1 o mas caracteres que finalizan
con un carácter particular que representa el fin de la linea. Los datos son interpretados
como caracteres. <los archivos binario, en cambio, son una secuencia de bytes
lmacenados según su representación interna y sin interpretar, en este caso es necesario
que sean leidos los datos tal como fueron guardados para poder ser reconocidos como
iguales.
Operaciones elementales de acceso a archivos:

Accion Efecto
Asignar(a,s) Asigna al idntificador a la cadena s que representa ub archivo
en disco
Abrir(a) Prepara el archivo asignado a la variable a para su utilizacion
Crear(a) Crea el archivo asignado al identificador a y lo prepra para su
acceso
Cerrar(a) Cierra el arhivo apuntado por a, actualiza la marca de fin si
corresponde
LeerCaracter(a,c) Lee el siguiente carácter del flujo apuntado por a y lo almacena
en c
LeerLinea(a,s) Lee la siguente linea del flujo apuntado por a y la almacena en s
GrabarCaracter(a,c) Escribe secuencialmente en el flujo a el caracter c
GrabarCadena(a,s) Escribe en el flujo a la cadena s
LeerArchivo(a,r) Lee el siguiente tipo de dato (ejemplo registro) del flujo a y lo
almacena en r
GrabarArchivo(a,r) Graba el siguiente tipo de dato, r, en el flujo a
LeerPosicion(a,p,r) Lee del flujo a el valor contenido en l posición p y lo almacena
en r
GrabarPosicion(a,p,r) Graba en la posicion p del flujo a el valor contenido en r
NumeroElementos(a) Retorna el numero de elementos almacenados en el archivo
PosicionActual(a) Retorna la posición en la que se encuentra posicionado el
puntero actual del archivo.
ApuntarA(a,p) Accede a la posición indicada por p en el archivo a.
FinArchivo(a) Retorna verdadero si se ha alcanzado la marca de fin de archivo

Definiciones de tipos
TipoArchivoEntero = TIPO Entero;
TipoRegistro = TIPO <Clave : Entero ; Nombre : Cadena>;
TipoArchivoRegistro = TIPO Archivo de TipoRegistro;

Declaracion de variables
ArchTexto : Texto //declra una varible de tipo archivo de texto
ArchEntero : TipoArchivoEntero // declara una variable de tipo archivo entero
ArchRegistro: TipoArchivoRegistro //declara una variable de tipo archivo registro

CrearArchivoEnteros(Dato_Resultado Archivo: TipoArchivoEntero): una Accion


Crea un archivo y almacena en el un conjunto de enteros, el proceso termina cuando se
ingresa un entero menor o igual a cero.
LEXICO
I : Entero;
ALGORITMO
Asignar(Archivo,”Archivo.dat”);
Crear(Archivo);
Imprimir(‘Ingrese un valor entero’);
Leer(i);
MIENTRAS (i <> 0) HACER
GrabarArchivo(Archivo,i);
Imprimir(‘Ingrese un valor entero’);
Leer(i);
FIN_MIENTRAS
Cerrar(Archivo);
FIN.

RecorrerArchivoEnteros(Dato_Resultado Archivo: TipoArchivoEntero): una Accion


Recorre un archivo existente que contiene valores enteros y los muestra por pantalla.
LEXICO
I : Entero;
ALGORITMO
Asignar(Archivo,”Archivo.dat”);
Abrir(Archivo);
MIENTRAS (No Sea FinArchivo(Archivo)) HACER
LeerArchivo(Archivo,i);
Imprimir(‘El valor almacenado es : ’,i);
FIN_MIENTRAS
Cerrar(Archivo);
FIN.

CrearArchivodeRegistros(Dato_Resultado Archivo: TipoArchivoRegistro): una


Accion
Crea un archivo y almacena en el un conjunto deregistros, el proceso termina cuando
se ingresa un entero menor o igual a cero en el campo clave del registro.
LEXICO
La lectura de cada miembro de un registro
R : TipoRegistro; cuando el dispositivo es el teclado debe hacerse
ALGORITMO por seprado. Es decir la lectura de un registro por
Asignar(Archivo,”ArchivoR.dat”); teclado se hace camo a campo
Crear(ArchivoR);
Imprimir(‘Ingrese un valor entero’);
Leer(R.clave); La escritura de un registro en un archivo (Grabar
elarchivo)puede hacersecampo a campo o por la
MIENTRAS (R.clave <> 0) HACER etructura completa. Hay lenguajes de
Imprmir(‘Ingrese un nombre’); programación omo Pascal que solo permiten esta
Leer(R.nombre); ultima opcion
GrabarArchivo(Archivo,R);
Imprmir(‘Ingrese un valor entero’);
Leer(R.Clave);
FIN_MIENTRAS
Cerrar(Archivo);
FIN.

RecorrerArchivoRegistros(Dato_Resultado Archivo: TipoArchivoRegistro): una


Accion
Recorre un archivo exsistente que contiene registros y los muestra por pantalla.
LEXICO
La lectura de un registro cuando el dispositivo es
R : TipoRegistro; un archivo se hace por estructura completa
ALGORITMO
Asignar(Archivo,”ArchivoR.dat”);
Abrir(Archivo);
MIENTRAS (No Sea FinArchivo(ArchivoR)) HACER
LeerArchivo(Archivo,R); Imprimir los dtos de un registro
Imprimir(‘La Clave es : ’,R.clave); cuando el dispositivo es la
Imprimir(‘El Nombre es : ’,R.nombre); pantalla se hace miembro a
miembro. Es decir por pantalla
FIN_MIENTRAS los registros se imprimen campo
Cerrar(Archivo); a campo
FIN.

AgregaArchivodeRegistros(Dato_Resultado Archivo: TipoArchivoRegistro): una


Accion
Agrega datos a un archivo y almacena en el un conjunto deregistros, el proceso termina
cuando se ingresa un entero menor o igual a cero en el campo clave del registro.
LEXICO El archivo existe por lo que no hay que crearlo.
R : TipoRegistro; Para agragar valores debe colocarse el punrtero
en la ultima posición por lo que hay que
ALGORITMO desplazarlo tantos registro como el valor
Asignar(Archivo,”ArchivoR.dat”); contenidoen cantidad de elementos
Abrir(ArchivoR);
ApuntarA(Archivo,CantidadElementos(Archivo))
Imprimir(‘Ingrese un valor entero’);
Leer(R.clave);
MIENTRAS (R.clave <> 0) HACER
Imprmir(‘Ingrese un nombre’);
Leer(R.nombre);
GrabarArchivo(Archivo,R);
Imprmir(‘Ingrese un valor entero’);
Leer(i);
FIN_MIENTRAS
Cerrar(Archivo);
FIN.

AgregaArchivoAlFinalDeOtro(Dato_Resultado Anterior, Actual:


TipoArchivoRegistro): una Accion
Agrega los datos del archivo actual al final del archivo anterior.
LEXICO
R : TipoRegistro; Ambos archivos existen por lo que se deben abrir
ALGORITMO y no crear, para grabar todos los registros del
actual al anterior se debe colocar el puntero del
Asignar(Anterior,”ArchivoN.dat”); anterior al final del archivo y recorriendo el
Abrir(Anterior); actual se lee y graba en anterior
Asignar(Actual,”ArchivoA.dat”);
Abrir(Actual);
ApuntarA(Anterior,CantidadElementos,Anterior)
MIENTRAS (No FinArchivo(Actual)) HACER
LeerArchivo(Actual,R);
GrabarArchivo(Anterior,R);
FIN_MIENTRAS
Cerrar(Anterior);
Cerrar(Actual);
FIN.
Acciones y funciones para pilas
Pila estructura del tipo LIFO el ultimo en entrar es el primero en salir, en general el
uso de esta estructura es adecuado cuando se persigue el propósito de invertir el orden
de una estructura dada. Su uso es reservado para los compiladores que los utilizan
para recursividad y las notaciones sufijas, por ejemplo.

CrearPila(Dato_Resultado Pila: TPNodo): una Accion


Las estructuras deben ser creadas, esto es hacer apuntar al valor NULO, o inicializar la
estructura antes de comenzar a trabajar con ellas.
ALGORITMO
Pila = NULO; Simplemente asigna el valor NULO al puntero
que controla el inicio de la estructura
FIN

EsVacia(Dato Puntero: TPNodo) : Boolean una Funcion


Esta función determina si hay nodos en la pila, es una forma de verificar la existencia
de elementos en la estructura para no producir errores en tiempo de ejecución como
por ejemplo intentar sacar cuando ya no hay datos.

ALGORITMO Retona verdadero si el puntero a punta al valor


EsVaciaPila  Puntero = NULO; NULO y falso en caso contrario. La asignación d
una expresión logica asigna verdadero al
FIN identificador booleano si se cumple la condicion y
falso en caso contrario

Meter(Dato_Resultado Pila: TPNodo; Dato Valor: Tinfo) una accion


Este procedimiento inserta un nuevo nodo en la pila, se encarga de pedir memoria,
guardar la información y actualizar los punteros. En esta estructura siempre la pila
retorna el valor del primer nodo, y como se agrega adelante, el procedimiento siempre
retorna en pila el nodo que acaba de crear.
LEXICO
Pre Pila Apunta al Inicio o a NULO si esta vacía
Pos Pila apunta al primer elemento de la estructura (coincide con el creado
La estructura queda perfectamente enlazada.
Ptr : TPNodo;
ALGORITMO Pide memoria, guarda el valor en el nuevo nodo,
Nuevo(Ptr); hace que el siguiente de este nodo sea pila, es ex
primero (porque agrega delante del primero) y
Ptr^  <Valor, Pila>; pila apunta al nodo creado
Pila  Ptr
FIN.

Sacar(Dato_Resultado Pila: TPNodo; Dato_Resultado Valor: Tinfo) una accion


Este procedimiento libera el nodo apuntado por pila, se encarga de guardar la
información contenida en el primer nodo en valor, por lo que este es un parámetro
variable y actualizar los punteros.
LEXICO
PRE: Pila Apunta al Inicio y no esta vacía
POS: Libera el nodo de la cima y retorna en valor la informacion.
Pila apunta al nuevo primer elemento de la estructura o a NULO si queda
Vacia.
La estructura queda perfectamente enlazada.
Ptr : TPNodo;
ALGORITMO
Ptr  Pila; Utiliza un puntero auxiliar para conservar el
inicio de la pila, guarda el valor contenido en ese
Valor Ptr^ .info; puntero, avanza con la estructura y libera el
Pila  Pila^.sgte; puntero auxiliar.
Destruir(Ptr);
FIN

Acciones y funciones para Colas


CrearCola(Dato_Resultado ColaFte,ColaFin: TPNodo): una Accion
ALGORITMO
ColaFte = NULO;
ColaFin = NULO;
FIN

Agregar(Dato_Resultado Colafte, Colafin: TPNodo; Dato Valor: Tinfo) una accion


Este procedimiento inserta un nuevo nodo en la cola, se encarga de pedir memoria,
guardar la información y actualizar los punteros. En esta estructura siempre ColaFte
retorna el valor del primer nodo, y como se agrega después del último, el
procedimiento siempre retorna en colafin el nodo que acaba de crear.

LEXICO
PRE Colafte Apunta al Inicio o a NULO si esta vacía, Cola Fin al final o
NULO
POS ColaFte apunta al primer elemento de la estructura.
ColaFin apunta al ultimo elemento de la estructura (coincide con el
creado)
La estructura queda perfectamente enlazada.
Ptr : TPNodo;
ALGORITMO Se pide memoria se guarda la información y el
Nuevo(Ptr); siguiente del nuevo nodo siempre es el valor
Ptr^  <Valor, NULO>; NULO. Para enlazarlo, como vimos, hay dos
situaciones posibles cuando es el primer nodo, en
SI (Colafte = NULO) ese caso el puntero al inicio apunta al nuevo nodo
ENTONCES y cuando ya hay por lo menos un nodo, en ese
Colafte  Ptr caso se debe enlazar el nuevo nodo a
continuación del anterior ultimo. En todos los
SI_NO casos el puntero al ultimo siempre apuntara al
ColaFin^.sgte = Ptr; nodo creado.
FIN_SI;
ColaFin  Ptr
FIN.

Suprimir(Dato_Resultado Colafte, ColaFin: TPNodo; Dato_Resultado Valor: Tinfo)


una accion
Este procedimiento libera el nodo apuntado porcolafte, se encarga de guardar la
información contenida en el primer nodo en valor, por lo que este es un parámetro
variable y actualizar los punteros
LEXICO
PRE ColaFte Apunta al Inicio y no esta vacia
POS Libera el nodo de la cima y retorna en valor la informacion.
Colafte apunta al nuevo primer elemento de la estructura o a NULO si queda
Vacia, en ese caso, ColaFin tambien apuntara a nulo.
La estructura queda perfectamente enlazada.
Ptr : TPNodo;
ALGORITMO Utiliza un puntero auxiliar para conservar el
Ptr  Colafte; inicio de lacolaa, guarda el valor contenido en
ese puntero, avanza con la estructura y libera el
Valor Ptr^ .info; puntero auxiliar Si el puntero al inicio apunta a
ColaFte  ColaFte^.sgte; NULO (cuando saca el ultimo valor), entonces
SI (ColaFte = NULO) tambien se hace apuntar al puntero auxiliar al
valor NULO. La unica vez que el puntero al final
ENTONCES se modifica, cuando se saca, es en este ultimo
ColaFin = NULO caso.
FIN_SI;
Destruir(Ptr);
FIN

Acciones y funciones para Listas Ordenadas enlazadas


CrearLista(Dato_Resultado Lista: TPNodo): una Accion
ALGORITMO
Lista = NULO;
FIN

InsertaNodo(Dato_Resultado Lista: TPNodo; Dato Valor: Tinfo) una accion

LEXICO
PRE Lista Apunta al Inicio o a NULO si esta vacia.
POS Lista apunta al primer elemento de la estructura.
No retorna la direccion del nodo creado, salvo si es el primero
La estructura queda perfectamente enlazada y ordenada creciente.
Ptr, PtrNuevo : TPNodo;
ALGORITMO

SI (lista = NULO o Valor < Lista^.info


ENTONCES
Si la lista esta vacia, o el valor a guardar es
Nuevo(Ptr); menor que el que esta en la primera posición se
Ptr^  <Valor, Lista>; coloca delante del primero con un procedimiento
Lista  Ptr identico al de insertar en una pila.
SI_NO
Se pide memoria y se guarda la informacion

Nuevo(PtrNuevo);
PtrNuevo^  <Valor, NULO>;

Ptr = Lista;
MIENTRAS (Ptr^.sgte <>NULO y Valor > Ptr^.sgte^.info)
HACER
Pregunta anticipadamente por el valor contenido en el
Ptr  ptr^.sgte nodo siguiente al apuntado por ptr. Si la informacióna
FIN_MIENTRAS ingresar es mayor a la del nodo siguiente debe avanzar
una posicion
PtrNuevo`.sgte  Ptr^.sgte; Se enlazan los punteros, como se pregunta por
Ptr^.sgte  Ptrnuevo; adelantado, el siguiente del nuevo sera el que es siguiente
FIN_SI; al nodo donde salimos que es el inmediato anterior al
nueo valor. El siguiente de ese nodo sea ahora el nuevo.
El nuevo lo colocamos entre el que señalamos con ptr y el
FIN. siguiente

InsertaPrimero(Dato_Resultado Lista: TPNodo; Dato Valor: Tinfo) una accion

LEXICO
PRE Lista Apunta a NULO porque esta vacia.
POS Lista apunta al primer elemento de la estructura.

Ptr: TPNodo;
ALGORITMO
Nuevo(Ptr);
Ptr^  <Valor, NULO>;
Lista  Ptr
FIN.

InsertaDelante(Dato_Resultado Lista: TPNodo; Dato Valor: Tinfo) una accion

LEXICO
PRE Lista Apunta al Inicio y noesta vacia.
POS Lista apunta al primer elemento de la estructura.

Ptr: TPNodo;
ALGORITMO
Nuevo(Ptr);
Ptr^  <Valor, Lista>;
Lista  Ptr
FIN.

InsertaEnMedio(Dato_Resultado Lista: TPNodo; Dato Valor: Tinfo) una accion


LEXICO
PRE Lista Apunta al Inicio no esta vacia.
POS Lista apunta al primer elemento de la estructura.
No retorna la direccion,queda perfectamente enlazada y ordenada.
Ptr, PtrNuevo : TPNodo;
ALGORITMO
Nuevo(PtrNuevo);
PtrNuevo^  <Valor, NULO>;
Ptr = Lista;
MIENTRAS (Ptr^.sgte <>NULO y Valor > Ptr^.sgte^.info)
HACER
Ptr  ptr^.sgte
FIN_MIENTRAS
PtrNuevo`.sgte  Ptr^.sgte;
Ptr^.sgte  Ptrnuevo;
FIN.
InsertaAl Final(Dato_Resultado Lista: TPNodo; Dato Valor: Tinfo) una accion

LEXICO
PRE Lista Apunta al Inicio o a NULO si esta vacia.
POS Lista apunta al primer elemento de la estructura.
No retorna la direccion del nodo creado.
Ptr, PtrNuevo : TPNodo;
ALGORITMO
SI (lista = NULO o Valor < Lista^.info
ENTONCES
Nuevo(Ptr);
Ptr^  <Valor, Lista>;
Lista  Ptr
SI_NO
Nuevo(PtrNuevo);
PtrNuevo^  <Valor, NULO>;
Ptr = Lista;
MIENTRAS (Ptr^.sgte <>NULO)
HACER
Ptr  ptr^.sgte
FIN_MIENTRAS
PtrNuevo`.sgte  Ptr^.sgte;
Ptr^.sgte  Ptrnuevo;
FIN_SI;

FIN.

InsertaNodoPorDosCampos(Dato_Resultado Lista: TPNodo; Dato Valor: Tinfo) una


accion

LEXICO
PRE Lista Apunta al Inicio o a NULO si esta vacia.
POS Lista apunta al primer elemento de la estructura.
Info es un rec¡gistro con al menos dos campos para ordenar
No retorna la direccion del nodo creado, salvo si es el primero
La estructura queda perfectamente enlazada y ordenada creciente.
Ptr, PtrNuevo : TPNodo;
ALGORITMO
SI (lista = NULO) o (Valor.C1 < Lista^.info.C1) o
(Valor.C1 =Lista^.info.C1)y(Valor.C2<Lista^.info.c2)
ENTONCES
Nuevo(Ptr);
Ptr^  <Valor, Lista>;
Lista  Ptr
SI_NO
Nuevo(PtrNuevo);
PtrNuevo^  <Valor, NULO>;
Ptr = Lista;
MIENTRAS (Ptr^.sgte <>NULO) y ((Valor > Ptr^.sgte^.info) o
((valor.C1 = Lista*.info.C1)y(Valor.C2 >Lista*.info.C2))
HACER
Ptr  ptr^.sgte
FIN_MIENTRAS
PtrNuevo`.sgte  Ptr^.sgte;
Ptr^.sgte  Ptrnuevo;
FIN_SI;

FIN.

BuscarNodo(Dato Lista: TPNodo; Dato Valor: Tinfo): TPNodo una funcion

LEXICO
PRE Lista Apunta al Inicio y no esta vacia.
Se busca encontrar el nodo que contenga valor como informacion
POS Lista apunta al primer elemento de la estructura.
Retorna la direccion del nodo con el valor buscado o NULO esta

Ptr : TPNodo;
ALGORITMO
Ptr = NULO;
MIENTRAS (Lista <>NULO Y Ptr = NULO) HACER
SI valor = Lista ^.info
ENTONCES
Ptr = Lista {lo encontro y sale}
SINO
Lista = Lista ^.sgte {avanza al proximo nodo}
FIN_SI
FIN_MIENTRAS
BuscarNodo = Ptr;

FIN.

BuscaOInserta(Dato_Resultado Lista,Ptr: TPNodo; Dato Valor: Tinfo) una accion

LEXICO
PRE Lista Apunta al Inicio o a NULO si esta vacia.
POS Lista apunta al primer elemento de la estructura.
Retorna la direccion del nodo creado, salvo si es el primero
La estructura queda perfectamente enlazada y ordenada creciente.
No se repite la clave
PtrNuevo : TPNodo;
ALGORITMO
SI (lista = NULO o Valor < Lista^.info
ENTONCES
Nuevo(Ptr);
Ptr^  <Valor, Lista>;
Lista  Ptr
SI_NO
Ptr = Lista;
MIENTRAS (Ptr^.sgte <>NULO y Valor >= Ptr^.sgte^.info)
HACER
Similar al procedimiento inserta nodo, pero como no
Ptr  ptr^.sgte debe insertar siempre se cambia el orden de las
FIN_MIENTRAS accines cuando se debe insertar en el medio. En este
SI (Ptr^.Info <> Valor) caso se busca primero y si no esta se crea el nodo y se
enlazan los punteros. Como ptr en este estado no
ENTONCES puede valer NULO y el siguiente si el ciclo de
PtrNuevo^.sgte  Ptr^.sgte; repetición se hace modificando el operador de relacion
Ptr^.sgte  Ptrnuevo; por >= en lugar de >. Al salir del ciclo si el valor
contenido en el nodo actual es distinto al buscado
Ptr  PtrNuevo; significa de ese dato no esta en la lista y se debe
FIN_SI; inserta, de lo contrario no se inserta.
FIN_SI;

FIN.

InsertaNodo2(Dato_Resultado Lista: TPNodo; Dato Valor: Tinfo) una accion

LEXICO
PRE Lista Apunta al Inicio o a NULO si esta vacia.
POS Lista apunta al primer elemento de la estructura.
No retorna la direccion del nodo creado, salvo si es el primero
La estructura queda perfectamente enlazada y ordenada creciente.
P,Q,Ptr : TPNodo;
ALGORITMO
Nuevo(Ptr);
Ptr^  <Valor, NULO>;
P  Lista;
Q  NULO;
MIENTRAS P <> NULO y Valor > p^.info HACER
Q  P;
P  P^.sgte;
FIN_MIENTRAS;

SI (P = Lista)
ENTONCES
Lista  Ptr;
SI_NO
Q^.sgte  Ptr;
FIN_SI;
Ptr^.sgte  P;
FIN.

SuprimeNodo(Dato_Resultado Lista: TPNodo; Dato Valor: Tinfo) una accion

LEXICO
PRE Lista Apunta al Inicio y no esta vacia
POS Libera el nodo si encentra el valor.
P, Q : TPNodo;
ALGORITMO
P  Lista;
Q  NULO:
MIENTRAS (P <> NULO y Valor > P^.info) HACER
Q  P;
P  P^.sgte:
FIN_MIENTRAS;
SI (P <> NULO y Valor = P^.info
ENTONCES
SI Q <> NULO
ENTONCES
Q^.sgte  P^.sgte
SI_NO
Lista  P^.sgte;
FIN_SI:
Destruir(P):
FIN_SI;
FIN

InsertaNodoListaDoblementeEnlazada(Dato_Resultado Lista: TPNodo; Dato Valor:


Tinfo) una accion
// El Nodo tiene un puntero al nodo anterior y un puntero al nodo siguiente
LEXICO
PRE Lista Apunta al Inicio o a NULO si esta vacia.
<Valor,Siguiente,Anterior>
POS Lista apunta al primer elemento de la estructura.
No retorna la direccion del nodo creado, salvo si es el primero
La estructura queda perfectamente enlazada y ordenada creciente.
Se la puede recorrer en ambas direcciones
Ptr, PtrNuevo : TPNodo;
ALGORITMO

SI (lista = NULO o Valor < Lista^.info


ENTONCES
Nuevo(Ptr);
Ptr^  <Valor, Lista,NULO>;
SI lista <> NULO
ENTONCES
Lista^.anterior Ptr
Lista  Ptr
SI_NO
Nuevo(PtrNuevo);
PtrNuevo^  <Valor, NULO,NULO>;
Ptr Lista;
MIENTRAS (Ptr^.sgte <>NULO y Valor > Ptr^.sgte^.info)
HACER
Ptr  ptr^.sgte
FIN_MIENTRAS
PtrNuevo^.sgte  Ptr^.sgte;
PtrNuevo^.ant  Ptr;
Ptr^.sgte  Ptrnuevo;
SI PtrNuevo^.sgte <> NULO
ENTONCES
PtrNuevo^.sgte.ant = PtrNuevo;
FIN_SI;

FIN_SI;

FIN.

ApareoDeListas(Dato_Resultado ListA,ListB,ListAB) una accion

LEXICO
PRE ListA y ListB Listas ordenadas simplemente enlazadas.
POS ListAB Lista enlazada producto del apareo de las listas dato.
Ptr : TPNodo; Puntero auxiliar para insertar como cola
VA,VB,VAB: TipoInfo el valor asociado a cada nodo de la lisra
ALGORITMO

ListAB = NULO;
Ptr = NULO;
MIENTRAS (ListA <> NULO) O (ListB <> NULO) HACER
SI ((ListB = NULO)O((ListA<>NULO)Y(ListA^.info<ListB^.info)))
ENTONCES
VAB = VA
SI_NO
VAB = VB
FIN_SI
Agregar(ListAB,Ptr,VAB);

FIN_MIENTRAS;
Ptr = NULO;
FIN.

ListaParalelaParaAgrupar(Dato_Resultado ListA, Dato ArchDatos,ArchProceso :


TipoArchivo) una accion

LEXICO
PRE ListA Lista Paralela al archivo de datos, con tantos nodos como registros tiene
ese archivo. Las restricciones del nodo no alcanzan para poner la clave de ordenamiento
y solo se puede poner un campo que agrupe datos del archivo de proceso.
ArchDatos es el archivo de datos personales, contiene todas las claves, esta ordenada
por esa por lo que es posible hacer búsqueda binaria. ArchProceso es el archivo a
procesar contiene la clave por la que se vincula con el archivo de datos con lo que esta
ordenado.
Se busca hacer una lista paralela para agrupar evitando busquedas secuenciales en
archivos.
POS ListA contendra el valor acumulado de cada clave del archivo de datos
relacionados posicionalmente.

ALGORITMO
ListA = NULO;
PARA I [1 .. CantidadRegistros(ArchDatos)] HACER
InsertaDelante(ListA, 0);
//Crea la lista con los contadores en cero//
FIN_PARA

MIENTRAS (HayaDatos(ArchProceso)) HACER


LeerRegistro(ArchProceso, Registro);
BusquedaBinaria(ArchDatos, Registro.Clave; Pos);
Ptr = Lista;
Para J [1 .. Pos] HACER
Ptr = Ptr*.sgte;
FIN_PARA
Incrementar(Ptr*.info, Registro.Agregado);
FIN_MIENTRAS;

FIN.

ListaParalelaParaBuscar(Dato_Resultado ListA, Dato ArchDatos,ArchProceso :


TipoArchivo) una accion

LEXICO
PRE ListA Lista Paralela al archivo de datos, con tantos nodos como registros tiene
ese archivo. Las restricciones del nodo no alcanzan para poner la posición en el
archivoclave de ordenamiento y solo se puede poner un campo que agrupe datos del
archivo de proceso.
ArchDatos es el archivo de datos personales, contiene todas las claves, No esta
ordenado lo que no es posible hacer busqueda directa ni búsqueda binaria.Se lo carga
en una lista como cola para poder buscar en la lista y luego accedre al archivo según el
numero de nodo
ArchProceso es el archivo a procesar contiene la clave por la que se vincula con el
archivo y hay que ir a buscar un valor.
Se busca hacer una lista paralela, cargada como cola para buscar evitando busquedas
secuenciales en archivos.
POS ListA contendra el la clave de busqueda y para cada clave del archivo de datos
se relacionan posicionalmente según el numero de nodo.

ALGORITMO

ListA = NULO;
Aux = NULO
PARA I [1 .. CantidadRegistros(ArchDatos)] HACER
Leer(Registro(ArchDatos, Registro)
Agregar(ListA, Aux, Registro.clave);
//Crea la lista con la clave a buscar//
FIN_PARA
Aux = NULO // Para que el resultado sea una lista y no una cola
MIENTRAS (HayaDatos(ArchProceso)) HACER
LeerRegistro(ArchProceso, Registro);
Ptr = Lista;
NumeroNodo = 0;
MIENTRAS Ptr*.info <> Registro.clave HACER
Ptr = Ptr*.sgte;
Incrementar(NumeroNodo);
FIN_MIENTRAS
AccesoDirectoArchivo(ArchDatos, NumeroNodo);
LeerRegistro(ArchDatos, RegistroDatos);
Imprimir(Registrodatos.Otra clave);
FIN_MIENTRAS;

FIN.

InsertaNodoListaCircular(Dato_Resultado Lista: TPNodo; Dato Valor: Tinfo) una


accion
//El Puntero a una lista circular apunta al predecesor al primer elemento
LEXICO
PRE Lista Apunta al al predecesor al primer elemento.
Lista no vacia, al menos un nodo
Si hay un solo nodo apunta a si mismo
POS Lista apunta al primer elemento de la estructura.
No retorna la direccion del nodo creado, salvo si es el primero
La estructura queda perfectamente enlazada y ordenada creciente.
Ptr, Auxiliar : TPNodo; Salir Booleano;
ALGORITMO

Nuevo(Auxiliar);
Aux^  <Valor, NULO>;
Lista  Ptr
SI (lista = NULO)
ENTONCES
Auxiliar^.sgte = Auxiliar;
Lista = Auxiliar;
SI_NO {La lista no esta vacia}
Ptr = Lista;
Salir = FALSO

REPETIR
SI (Ptr^.sgte^.info< Valor)
ENTONCES
Ptr  ptr^.sgte
SINO
Salir = Verdadero
FIN_SI
HASTA Salir o Ptr = Lista

Auxiliar^.sgte  Ptr^.sgte;
Ptr^.sgte  Auxiliar;
SI (Salir = FALSO)
ENTONCES
Lista = Auxiliar
FIN_SI; {de la lista no vacia}

FIN.

Acciones y funciones para arboles


RecorrerEnOrdenArbol(Dato Arbol: TPNodo; Dato Valor: Tinfo) una accion
//El Nodo tiene puntero al hijo izquierdo Y derecho
LEXICO
PRE Arbol Apunta al nodo raiz o es Nulo.
POS Recorre la estructura completa en orden.
ALGORITMO
SI (Arbol <> NULO)
ENTONCES
RecorrerEnOrdenArbol(Arbol^.izquierdo);
Imprimir(Arbol*.info);
RecorrerEnOrdenArbol(Arbol^.Derecho);
FIN_SI;

FIN.

RecorrerPreOrdenArbol(Dato Arbol: TPNodo; Dato Valor: Tinfo) una accion


//El Nodo tiene puntero al hijo izquierdo Y derecho
LEXICO
PRE Arbol Apunta al nodo raiz o es Nulo.
POS Recorre la estructura completa en pre orden.
ALGORITMO
SI (Arbol <> NULO)
ENTONCES
RecorrerPreOrdenArbol(Arbol^.izquierdo);
Imprimir(Arbol*.info);
RecorrerPreOrdenArbol(Arbol^.Derecho);
FIN_SI;

FIN.

RecorrerPosOrdenArbol(Dato Arbol: TPNodo; Dato Valor: Tinfo) una accion


//El Nodo tiene puntero al hijo izquierdo Y derecho
LEXICO
Pre Arbol Apunta al nodo raiz o es Nulo.
POS Recorre la estructura completa pos orden.
ALGORITMO
SI (Arbol <> NULO)
ENTONCES
RecorrerPosOrdenArbol(Arbol^.izquierdo);
Imprimir(Arbol*.info);
RecorrerPosOrdenArbol(Arbol^.Derecho);
FIN_SI;

FIN.
RecorrerEnOrdenInArbol(Dato Arbol: TPNodo; Dato Valor: Tinfo) una accion
//El Nodo tiene puntero al hijo izquierdo Y derecho
LEXICO
PRE Arbol Apunta al nodo raiz o es Nulo.
POS Recorre la estructura completa en orden inverso.
ALGORITMO
SI (Arbol <> NULO)
ENTONCES
RecorrerEnOrdenInArbol(Arbol^.derecho);
Imprimir(Arbol*.info);
RecorrerEnOrdenArbol(Arbol^.Izquierdo);
FIN_SI;

FIN.

RecorrerPreOrdenInArbol(Dato Arbol: TPNodo; Dato Valor: Tinfo) una accion


//El Nodo tiene puntero al hijo izquierdo Y derecho
LEXICO
PRE Arbol Apunta al nodo raiz o es Nulo.
POS Recorre la estructura completa en pre orden inverso.
ALGORITMO
SI (Arbol <> NULO)
ENTONCES
RecorrerPreOrdenInArbol(Arbol^.Derecho);
Imprimir(Arbol*.info);
RecorrerPreOrdenArbol(Arbol^.Izquierdo;
FIN_SI;

FIN.

RecorrerPosOrdenInArbol(Dato Arbol: TPNodo; Dato Valor: Tinfo) una accion


//El Nodo tiene puntero al hijo izquierdo Y derecho
LEXICO
PRE Arbol Apunta al nodo raiz o es Nulo.
POS Recorre la estructura completa pos orden inverso.
ALGORITMO
SI (Arbol <> NULO)
ENTONCES
RecorrerPosOrdenArbol(Arbol^.derecho);
Imprimir(Arbol*.info);
RecorrerPosOrdenArbol(Arbol^.izquierdo;
FIN_SI;

FIN.

RecorrerEnAnchoPrimero(Dato Arbol: TPNodo; Dato Valor: Tinfo) una accion


//El Nodo tiene puntero al hijo izquierdo Y derecho
LEXICO
PRE Arbol Apunta al nodo raiz no es Nulo.
POS Recorre la estructura completa ancho primero.
Fte, Fin: TPNodo
// Saca el nodo del árbol y lo va cargando en una cola, un nodo hay. Luego recorre hasta
que la cola quede vacía. Por cada nodo que va recorriendo, y como solo puede tener dos
hijos por ser binario, si hay nodo izquierdo lo agrega en la cola, si hay derecho también
lo agrega (esto asegura el recorrido en ancho primero). Al colocar el nodo completo del
árbol en la cola, cuando se saca se tienen los enlaces a los hijos, si es que tiene.//
ALGORITMO
Fte = NULO;
Fin = NULO;
Agregar(Fte, Fin, Arbol);
Mientras (Fte <> NULO) HACER
Suprimir(Fte, Fin, Arbol);
Imprimir(Arbol*.info);
SI (Arbol*.izq<>NULO
ENTONCES
Agregar(Fte, Fin, Arbol*.izq)
FIN_SI
SI (Arbol*.der<>NULO
ENTONCES
Agregar(Fte, Fin, Arbol*.der)
FIN_SI;

FIN_MIENTRAS;

FIN.

InsertarNodoArbol(Dato_Resultado Arbol: TPNodo; Dato Valor: Tinfo) una accion


LEXICO
PRE Arbol Apunta al nodo raiz o es Nulo.<izquierdo, info, derecho>
Las Inserciones se hacen siempre en las hojas
POS Inserta un nodo ordenado
ALGORITMO
SI (Arbol = NULO)
ENTONCES
Nuevo(Arbol);
Arbol^ <NULO, Valor, NULO>;
SINO SI (Valor<Arbol^.info)
ENTONCES
InsertarNodoArbol(Arbol^.izquierdo, Valor)
SINO SI (Valor>Arbol^.info)
ENTONCES
InsertarNodoArbol(Arbol^.izquierdo, Valor)
SINO ERROR
FIN_SI
FIN_SI
FIN_SI;
FIN.
CantidadHojasArbol(Dato Arbol: TPNodo): Entero una funcion;
Eshoja(Dato Arbol): Booleano una funcion;
ALGORITMO
EsHoja  (Arbol^.izquierdo = NULO) Y (Arbol^.derecho = NULO;
FIN /*EsHoja
ALGORITMO
SI (Arbol <> NULO)
ENTONCES SI (EsHoja(Arbol))
ENTONCES
CantidadHojas = 1;
SINO
CanidadHojas CantidadHojas(Arbol^.izquierdo) +
CantidadHojas(Arbol^.derecho);
SINO
CantidadHojas = 0;
FIN_SI;
FIN.

AlturaArbol(Dato Arbol: TPNodo): Entero una funcion;


Maximo(Dato A, B : Entero): Entero una funcion;
ALGORITMO
SI (A > B)
ENTONCES
Maximo = A;
SINO
Maximo = B;
FIN_SI
FIN /*Maximo
ALGORITMO
SI (Arbol <> NULO)
ENTONCES
AlturaArbol 1 +
Maximo(AlturaArbol(Arbol^.izquierdo),AlturaArbol(Arbol^.derecho))

SINO
AlturaArbol -1
FIN_SI;
FIN.

BuscarEnArbol(Dato Arbol: TPNodo; Dato Valor: Tinfo): Booleano una funcion


LEXICO
PRE Arbol Apunta al nodo raiz o es Nulo.<izquierdo, info, derecho>
Busca el dato contenido en Valor
POS Retorna Verdadero si lo encuentra o falso en caso contrario.
ALGORITMO
SI (Arbol <> NULO)
ENTONCES
Si (Valor< Arbol^.info)
ENTONCES
BuscarEnArbol  BuscarEnArbol(Arbol^.izquierda, valor)
SINO SI (Valor>Arbol^.info)
ENTONCES
BuscarEnArbol  BuscarEnArbol(Arbol^.derecho, valor)
SINO
BuscarEnArbol  VERDADERO
FIN_SI
FIN_SI

SINO
BuscarEnArbol  FALSO;
FIN_SI;
FIN.

Borrar(Dato_Resultado Arbol: TPNodo; Dato Valor: Tinfo) una accion


LEXICO
PRE Arbol Apunta al nodo raiz o es Nulo.<izquierdo, info, derecho>
POS Busca el dato contenido en Valor y si lo encuentra libera el nodo
BorrarInOrder(Dato_Resultado Arbol)
ALGORITMO
SI (Arbol^.derecho<> NULO
ENTONCES
BorrarInOrder(Arbol^.derecho)
SINO
Auxiliar^.info  Arbol^.info;
Auxiliar Arbol;
Arbol  Arbol^.izquierdo;
FIN_SI
FIN

ALGORITMO
SI (Arbol <> NULO)
ENTONCES
Si (Valor< Arbol^.info)
ENTONCES
Borrar(Arbol^.izquierda, Valor)
SINO SI (Valor>Arbol^.info)
ENTONCES
Borrar(Arbol^.derecho, valor)
SINO /* en este estado lo encontro*/
Auxiliar = Arbol;
SI (Arbol^.derecha = NULO)/* No tiene hijo derecho
ENTONCES
Arbol = Arbol^.Izquierda
SINO SI(Arbol^.izquierda = NULO)
ENTONCES
Arbol = Arbol^.derecha
SINO
BorrarInOrder(Arbol^.izquierdo)
FIN_SI
FIN_SI
Liberar(Auxiliar);
FIN_SI
FIN_SI

SINO
ERROR;
FIN_SI;
FIN.

Inserciones en arboles AVL


Insercion en el sularbol izquierdo de la rama izquierda de A
Rotacion Simple Izquierda Izquierda

N1^.izquierdo  N1^.derecho (N es el nodo desbalanceado N1 su hijo izquierdo)


N1^.derecho  N1
N  N1

Insercion en el sularbol derecho de la rama izquierda de A


Rotacion Doble derecha Izquierda
N1^. izquierdo  N2^. derecho
N2^. derecho  N1
N^. derecho  N2^. izquierdo
N2^.izquierdo  N
N N2

Insercion en el sularbol derecho de la rama derecha de A


Rotacion Simple Derecha Derecha
N1^.derecho  N1^. izquierdo (N es el nodo desbalanceado N1 su hijo derecho)
N1^.izquierdo  N1
N  N1

Insercion en el sularbol izquierdo de la rama derecha de A


Rotacion Doble Izquierda derecha
N1^. derecho  N2^. izquierdo
N2^. izquierdo  N1
N^.izquierdo  N2^.derecho
N2^.derecho  N
N N2

Funciones recursivas
El flujo de control de una función recursiva requiere tres condiciones para una
terminación normal:
1. Un test para detener o continuar con la recursion.
2. Una llamada recursiva para continuar la recursion
3. Un caso base para terminar la recursion

Recursividad
SI (Es el caso base)
ENTONCES
Ejecutar la accion final
Terminr recursion
SINO
Ejecutar accion para cercar a la solucion
Invocar nuevamente a la funcion

Factorial
(Dato N : Entero): Entero una funcion;
ALGORITMO
SI (N = 0)
ENTONCES
Factorial = 1
SINO
Factorial = N * Factorial(N-1)
FINSI
FIN.

Fibonacci
(Dato N : Entero): Entero una funcion;
ALGORITMO
SI (N = 0) O (N = 1)
ENTONCES
Fibonacci = N
SINO
Fibonacci = Fibonaci(N-2)+Fibonacci(N-1)
FINSI
FIN.

EuclidesMaxCD
(Dato M,N : Entero): Entero una funcion;
ALGORITMO
SI (N <= M) Y (M Modulo N = 0)
ENTONCES
EuclidesMaxCD = N
SINO SI (M<N)
ENTONCES
EuclidesMaxCD(N,M)
SINO
EuclidesMaxCD(N, M Mod N)
FINSI
FIN.

Hanoi
(Dato Inicio, Medio, Centro : Cráter: N : Entero): NULO una funcion;
ALGORITMO
SI (N = 1)
ENTONCES
Imprimir(Mover Disco N de inicial a final)
SINO
Hanoi(Inicial, Final, Central, N- 1);
Imprimir(Mover Disco N de inicial a final)
Hanoi(Central, Final, Inicial, N- 1);
FINSI
FIN.

Recursividad indirecta

Funcion mutuamente reursiva implementdas en C

Imprimir los carcteres del alfabeto ingles


# incluye <stdio.h>
void FuncionA(char c);
void FuncionB(char c);
int main()
{
FuncionA(‘Z’);
Return 0;
}

void FuncionA(char c)
{
if( c > ‘A’ )
FuncionB(c);
Printf(“%c”,c);
}
void FuncionB(char c)
{
FuncionA(--c);
}

Determinar si un numero es par


# incluye <stdio.h>
void FuncionPar(int n);
void FuncionImpar(int n);
int main()
{
if (FuncionPr(9))
printf(“Es par”);
else
printf(“Es Impar”);
return 0;
}

int FuncionPar(int n)
{
if (n == 0)
return 1;
else
return FuncionImpar(n-1);

int FuncionImpar(int n)
{
if (n == 0)
return 0;
else
return FuncionPar(n-1);
}

Archivos en pascal
Pascal Dispone del tipo de dato text que permite vincular a una variable interna con un
archivo de texto.
En el caso de C los nombres internos se declaran como un puntero a una struct FILE, y
la discriminacion del tipo, texto o binario se realiza en la apertura
Para trabajar con archivos de texto en Pascal se debe:
1. Declarar el nombre lógico del archivo con un identificador de tipo text.
2. Relacionar el nombre interno o lógico con l externo o físico, mediante
Assign.
3. Abrirlo con Reset o Rewrite según corresponda.
En el ejemplo que sigue se desarrollan las acciones para lectura completa de un archivo
de texto. Se lee
1. Carácter a carácter.
2. Por línea completa.
3. Con formato
a. En datos simples
b. En registros

program LeerCaracteres;
{Lee un archivo de texto caracter a caracter y lo muestra por pantalla}
Arch : text;
Letra : char;
begin
Assign (Arch,'C:\....\archivo.txt');
Reset(Arch);
while not EOF(Arch) do
begin
{Lectura caracter a caracter}
read(Arch, Letra);
write(Letra);
end;
Close(Arch);
End.

program LeerPorLineas;
Arch : text;
Nombre : string;

begin
Assign (Arch,'C:\...\archivo.txt');
Reset(Arch);
while not EOF(Arch) do
begin
{Lectura por linea}
readln(Arch, nombre);
writeln(nombre);
end;
Close(Arch);
End.

program LeerConFormato;
var
Arch : text;
Entero : Integer;
Texto : string[10];
begin
Assign (Arch,'C:\...\archivo.txt');
Reset(Arch);
while not EOF(Arch) do
begin
{Lectura con formato}
readln(Arch, Entero, Texto);
writeln('Este es el entero : ', Entero:8);
writeln('Este es el texto : ', Texto:8);
end;
Close(Arch);
End.

program LeerConFormatoEnRegistro;
TipoRegistro = Record
Numero : Integer;
Cadena : string[10];
End;
var
Arch : text;
Registro : TipoRegistro;
begin
Assign (Arch,'C:\...\archivo.txt');
Reset(Arch);
while not EOF(Arch) do
begin
{Lectura con formato en regitro}
readln(Arch, Registro.Numero, Registro.Cadena);
writeln('El entero del reg.: ', Registro.Numero:8);
writeln('El texto del re. : ', Registro.Cadena:8);
end;
Close(Arch);
End.

Los archivos de tipo o de acceso directo es una colección de datos del mismo tipo con
almacenamiento sin interpretar y guardadas según su representación interna. Solo se
pueden comparar como iguales si son leídos del modo en que fueron escritos Requieren
en pascal que para poder utilizarlos se deba hacer y en orden los siguientes pasos
1. El la cláusula Type definir los tipos
a. Para el registro si corresponde, o podria evitarse se se utilizan archivo de
de tipos de datos primitivos
b. Para el archivo NombreDelTipo = FILE OF TIPO DE DATO
2. Declarar las variables en la clausula Var
a. Una para el archivo
b. Otra para el tipo de dato de cada posición.
3. Asignar y abrir los archivos
a. La asignación a traves de ASSIGN vinculando el nombre interno con el
externo.
b. La apertura según corresponda con Reset o Rewrite

Lo disponible para archivos, una vez en condiciones de ser operados es:

1. Lectura Read(Archivo, TipoDeDato) En el caso de ser un registro se lee


completo.
2. Grabar Write(NombreInterno, TipoDeDato)
3. Seek(NombreInterno,Posición), Ubica el Puntero a Pos Registros
desplazados desde el inicio del mismo
4. Flesize(NombreInterno) Indica cantidad de registros.
5. Filepos(NombreInterno) retorna la posición actual del puntero. Tambien
cantidad de registros de desoplazamiento desde el inicio del archivo.
6. Tanto filepos como filesize retonan un tipo de dato entero largo, pero pueden
ser contenido en un entero de menor jerarquia mientras no se produzca
desbordamiento del mismo.
7. EOF(NombreInterno) Retorna true si se alcanzo la marca de fin de archivo y
False en caso contrario.
8. Truncate(NombreInterno) pone la marca de fin de archivo en el lugar donde
esta el puntero. Trunca el archivo

program ConvierteTextoABinario;
Type
TipoRegistro = Record
Numero : Integer;
Cadena : string[10];
End;
TipoArchivo = FILE OF TipoRegistro;
var
Arch : text;
Registro : TipoRegistro;
Binario : TipoArchivo;
I : Integer;
begin
clrscr;
Assign (Arch,'C:\borlandc\archivo.txt');
Reset(Arch);
Assign (Binario,'C:\...\Binario.Dat');
Rewrite(Binario);
while not EOF(Arch) do
begin
{Lectura con formato en regitrode un archico de texto
y lo almacena en un archivo binario}
readln(Arch, Registro.Numero, Registro.Cadena);
write(Binario,Registro);
end;
Close(Arch);
Close(Binario);
End.

program RecorrerBinario;
uses crt;
Type
TipoRegistro = Record
Numero : Integer;
Cadena : string[10];
End;
TipoArchivo = FILE OF TipoRegistro;
var
Arch : text;
Registro : TipoRegistro;
Binario : TipoArchivo;
begin
Assign (Binario,'C:\...\Binario.Dat');
Reset(Binario);
while not EOF(Binario) do
begin
{Lectura con formato en regitro del archivo Binario}
read(Binario, Registro);
writeln('El entero del Bin.: ', Registro.Numero:8);
writeln('El texto del Bin. : ', Registro.Cadena:8);
end;
Close(Binario);
end.

program RecorreBinarioInverso;
Type
TipoRegistro = Record
Numero : Integer;
Cadena : string[10];
End;
TipoArchivo = FILE OF TipoRegistro;
Var
Binario : TipoArchivo;
Registro : TipoRegistro;
I : Integer;
Begin
Assign (Binario,'C:\...\Binario.Dat');
Reset(Binario);
For i := FileSize(Binario) - 1 downto 0 do
begin
{Lectura con formato en regitro del archivo Binario
en orden inverso}
Seek(Binario,I);
read(Binario, Registro);
writeln('El entero del Bin.: ', Registro.Numero:8);
writeln('El texto del Bin. : ', Registro.Cadena:8);
end;
Close(Arch);
Close(Binario);
end.
Ejemplo en C con aplicaciones de estructuras enlzadas
/* Toma una cadena que representa una expresión aritmética y la convierte a notación
sufijo usando procedimientos de pilas*/
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>

typedef char TipoInfo;

typedef struct tiponodo {


TipoInfo Info;
struct tiponodo *sgte;
} TipoNodo;

typedef TipoNodo* TipoPuntero;

void Meter(TipoPuntero *pila , TipoInfo valor);


void Sacar(TipoPuntero *pila , TipoInfo *valor);
void Sufijo(char * cadena, char * suf);

int main()
{

char cad1[10];
clrscr();
Sufijo("5*8+3",cad1);
printf("%s\n", cad1);
getchar();
return 0;
}

void Sufijo(char * cadena, char * suf)


{
char c;
int i = 0,j=0;
TipoPuntero pila=NULL;
c = cadena[i];
while (c) {
switch(c) {
case '+':
case '-':
case '*':
case '(':
case '/': Meter(&pila, c); break;
case ')': Sacar(&pila, &c);
while (c != '(') {
suf[j++] = c;
Sacar(&pila, &c);
} break;
default : suf[j++]= c; break;
}
i++;
c=cadena[i];
}
while(pila){
Sacar(&pila,&c);
suf[j++]=c;
}
suf[j] = '\0';
}

void Meter(TipoPuntero *pila , TipoInfo valor)


{
TipoPuntero ptr;
ptr =(TipoPuntero) malloc(sizeof(TipoNodo));
ptr -> Info = valor;
ptr -> sgte = *pila;
*pila = ptr;
}

void Sacar(TipoPuntero *pila , TipoInfo *valor)


{
TipoPuntero ptr;
ptr = *pila;
*pila = (*pila)->sgte;
*valor = ptr->Info;
free(ptr);
}
ANEXO 1 Representaciones gráficas de algoritmos
Diagrama de Nassi-Sneiderman

Condición 1

T F

Acción 1 Acción 5
Acción 2 Mientras condición 3
Condición 2 Acción 6
T F
Acción 7
Acción 3
Acción 8
Acción 4 Acción 9
Acción 10
Acción 11
Acción 12

Repetir hasta condición 4

Diagramas de Jackson
Diagramas de Lindsay.

PASCAL DIAGRAMA DE DETALLE

Variable = expresión Variable ← expresión

READ (var1, var2,....var n) var1, var2,....

WRITELN var 1 var 2 var 1 var 2


(ó ó , ..... ) ó ó ,....
WRITE liter1 liter2 liter1 liter2

IF condición
THEN Condición
sentencia 1
ELSE Instrucción 1 Instrucción 2
sentencia 2

WHILE condición Condición


DO
sentencia Instrucción

REPEAT
sentencia; Instrucción 1
: :
: :
sentencia n Instrucción n
Condición
UNTIL condición

FOR variable: expres1 TO expres2


ó Instrucción
Var: exp1, exp2
DOWNTO
DO sentencia

CASE expresión
OF Expresión
const1....... const n : instrucción1
Const1... Const n Const1... Const p
:
: Instrucción1 Instrucción m
const1...... const p : instrucción m
END
Cualquier sentencia puede ser reemplazada por Correspondiendo en el diagrama de detalle
un bloque: BEGIN la secuencia:
sentencias 1; instrucción 1;
: :
: :
sentencias n instrucción n
END
Llaves de Warniel

HacerUnaCosa)
Si HacerOtraCosa

Condición Exclusión

No Vacio
Algoritmo 1
Case
Ordinal 2
HacerUnaCosa;
Mientras HacerOtraCosa;
Condición HacerAlgoMas

Notación Algoritmica
LEXICO {Léxico Global del algoritmo}
{Declaración de tipos, constantes, variables y acciones}
Acción 1
PRE {Precondición de la acción 1}
POS {Poscondición de la acción 1}
LEXICO {Léxico local, propio de la acción 1}
Declaraciones locales
ALGORITMO {Implementación de la acción 1}
{Secuencia de instrucciones de la acción 1}
FIN {Fin implementación algoritmo de la acción 1}

ALGORITMO
PRE {Precondición del algoritmo principal}
POS {Poscondición del algoritmo principal}
{Secuencia de instrucciones del algoritmo principal}
FIN {Fin del algoritmo principal}
Equivalencias entre notación algorítmica y lenguajes de programación
CONDICIONAL
Formato Pascal C
SI Condicion If expresion condicional If (expresion)
ENTONCES Then S;
S S Else
SI_NO Else R;
R R;
FIN_SI

Formato Pascal C
SEGÚN expr Case selector of switch (selector) {
V1 : S1 Valor1 : S1; case etiqueta:S; break;
V2 : S2 ......................... ..............................
EN_OTRO_CASO : Sn else Ve: Se; default: R;
FIN_SEGÚN end; }

ITERACION
Formato Pascal C
Mientras Cond. Hacer While Expresion logica do while(expresion)
S S; S;
FIN_MIENTRAS

Formato Efecto
REPETIR Repeat do
S S S;
HASTA Cond Until expresion logica while(expresion)

Formto Efecto C
PARA i [Vi..Vf] HACER For i:=Vi to vf do for(i=0;i<vf;i++)
S S; S;
FIN_PARA

Estilos de Indentación

Recomendacion de estilos de indentacion para desarrollos más claros y legibles.(Ing. J.


M. Sola)

Estilo The One True Brace Style


while( SeaVerdad() ) {
HacerUnaCosa();
HacerOtraCosa();
}
HacerUnaUltimaCosaMas();

BSD/Allman.
while( SeaVerdad() )
{
HacerUnaCosa();
HacerOtraCosa();
}
HacerUnaUltimaCosaMas();
Estilo Whitesmiths
while( SeaVerdad() )
{
HacerUnaCosa();
HacerOtraCosa();
}
HacerUnaUltimaCosaMas();

Estilo GNU
while( SeaVerdad() )
{
HacerUnaCosa();
HacerOtraCosa();
}
HacerUnaUltimaCosaMas();

Estilo Pico
while( SeaVerdad()
{ HacerUnaCosa();
HacerOtraCosa(); }
HacerUnaUltimaCosaMas();

Estilo Banner
while( SeaVerdad() ) {
HacerUnaCosa();
HacerOtraCosa();
}
HacerUnaUltimaCosaMas();
BIBLIOGRAFIA
Behrouz Forouzan. Introducción a la ciencia de la computación. 2005. Ciencias e
Ingenieria.
De Giusti. Algoritmos datos y programas. 2001. Prentice Hall.
Garcia Molina. Una introducción a la programación. 2005. Thomson.
Kernighan - Ritchie. El lenguaje de programacion C. 1988. Pearson
Kerighan – Pike. La practica de la programacion. 2000. Pearson
Perkins David. La bañera de Arquimedes y otras historias del descubrimiento
cientifico. Paidos 2004
Iranzo, j. Logica simbolica para informaticos. 2006. Alfaomega.
Perez M. Matematica discreta y algoritmos. 2005. Answer.
Joyanes Aguilar, L.Algoritmos y estructura de datos, una perspectiva en C. 2004
Mc Graw Hill

El Autor
Oscar Ricardo Bruno
Formación Academica
Doctorando en educación UnTref
Licenciado en Sistemas (Instituto Tecnologico de Buenos Aires)
Magíster en Docencia Universitaria UTN FRBA
Especialista en Ingenieria en Sistemas (Maestrando) UTN FRBA
Especialista en Docencia Universitaria UTN FRBA
Profesor en Docencia Universitaria en Sistema INSPT UTN FRBA
Espeialista en Investigación Operativa ESIO DIGID.
Miembro de la Sociedad Argentina de Estudios Comparados en Educacion

Actividad Docente
Director IAFIP. Instituto Argentino de Formación e Investigación en Programacion
Profesor Adjunto Algoritmos y Estructura de Datos y Sintaxis y Semántica de Lengujes
UTN FRBA .
Profesor Adjunto Estructura de Datos Univeridad del Salvador
Profesor Titular Laboratorio II y III Escuela Tecnica Nro 1 Otto Krause
Coordinador Area Computación EIOK
Director y jurado de tesis UTN FRBA
Ex Consejero Departamental docente UTN FRBA departamento Sistemas.

Menciones
Finalista premios Sadosky 2006 - 2007 a la inteligencia argentina categoría calidad
docente

También podría gustarte