Documente Academic
Documente Profesional
Documente Cultură
programar
Índice general I
Índice de tablas IX
Índice de figuras XI
1. Introducción 1
1.1. Problemas, algoritmos y metodologı́a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1.1. Solución de problemas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1.2. Tipos de problemas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2. Algoritmos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.1. Caracterı́sticas de un algoritmo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.2. Estructura de un algoritmo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.3. Solución de problemas algorı́tmicos . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.3.1. Metodologı́a de Programación . . . . . . . . . . . . . . . . . . . . . . 3
3. Lógica matemática 17
3.1. Lógica proposicional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.1.1. El lenguaje de la lógica proposicional . . . . . . . . . . . . . . . . . . . . . . . . 18
3.1.2. Precedencia de conectivos lógicos . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.1.3. Interpretaciones y clasificación de las fórmulas lógicas . . . . . . . . . . . . 22
3.1.3.1. Tautologı́as, contradicciones y contingencias . . . . . . . . . . . . 22
3.1.3.2. Tablas de verdad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.1.4. Argumentación y leyes lógicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.1.4.1. Argumentación lógica directa . . . . . . . . . . . . . . . . . . . . . . . 24
3.1.4.2. Equivalencias Lógicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.1.4.3. Argumentación lógica indirecta por la contrarrecı́proca . . . 25
3.1.4.4. Implicaciones Lógicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.1.4.5. Argumentación mediante implicaciones lógicas . . . . . . . . . . 27
3.2. Lógica de predicados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.2.1. Cuantificadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.2.2. Semántica de los cuantificadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.2.3. Leyes de De Morgan para cuantificadores . . . . . . . . . . . . . . . . . . . . . 30
3.2.4. Reglas de inferencia sobre fórmulas cuantificadas . . . . . . . . . . . . . . . 30
3.2.4.1. Particularización universal . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.2.4.2. Generalización universal . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.2.4.3. Particularización existencial . . . . . . . . . . . . . . . . . . . . . . . . 31
3.2.4.4. Generalización existencial . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.3. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4. Teorı́a de conjuntos 37
4.1. Conceptos básicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.1.1. Conjunto y elemento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.1.2. Especificación de Conjuntos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.1.2.1. Extensión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.1.2.2. Comprensión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.1.3. El conjunto vacı́o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
ÍNDICE GENERAL III
6. Relaciones y funciones 85
6.1. Relaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
6.1.1. Propiedades de las relaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
6.1.2. Relaciones de orden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
6.1.3. Relaciones de equivalencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
6.2. Función parcial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
6.2.1. Propiedades de las funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
6.3. Extensión de una función parcial a una función total . . . . . . . . . . . . . . . . . . 93
6.4. Funciones importantes en computación . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
6.5. Composición de funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
6.5.1. Evaluación como composición de funciones . . . . . . . . . . . . . . . . . . . . 104
6.6. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
Bibliografı́a 255
VIII ÍNDICE GENERAL
Índice de tablas
6.1. Pesos atómicos del Potasio (K), el Cloro (Cl) y el Oxı́geno (O). . . . . . . . . . 101
IX
X ÍNDICE DE TABLAS
Índice de figuras
6.1. Representación de la relación R = {(0, ¨), (0, «), (2, «), (2, ©)} mediante
diagramas Sagitales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
XI
XII ÍNDICE DE FIGURAS
6.2. Representación de la relación R = {(¨, ©), (©, ¨), (ª, «), («, ª)} mediante
diagramas Sagitales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
6.3. Representación de la función f = {(0, ©), (1, ©), (4, ª)} mediante diagramas
Sagitales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
6.4. Representación de la relación f ′ = {(0, ¨), (1, ¨), (2, ª), (1, «)} mediante
diagramas Sagitales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
6.5. Representación de la función inyectiva f = {(0, «), (2, ¨)} mediante diagra-
mas Sagitales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
6.6. Representación de la función sobreyectiva f = {(0, ¨), (1, ª), (2, «), (4, ¨)}
mediante diagramas Sagitales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
6.7. Representación de la función total f = {(0, «), (1, ©), (2, ¨), (3, «), (4, ¨)}
mediante diagramas Sagitales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
6.8. Representación de la función biyectiva f = {(0, ª), (1, ©), (2, «), (3, ¨)}
mediante diagramas Sagitales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
6.9. Representación de la función identidad idA . . . . . . . . . . . . . . . . . . . . . . . . . . 95
6.10. Representación mediante diagramas Sagitales de la composición de las fun-
ciones f y g, f ○ g = {(1, a), (2, d), (3, c), (4, c), (6, c)}. . . . . . . . . . . . . . . . . . 100
6.11. Representación mediante diagramas de la función f ○g = {(1, a), (2, d), (3, c), (4, c), (6, c)}.100
Capı́tulo 1
Introducción
Bien condicionados
Mal condicionados
Indecidibles
1.2. Algoritmos
Definición. Secuencia finita de tareas bien definidas, cada una de las cuales se puede
realizar con una cantidad de recursos finitos.
Precisión: Hay un orden preciso en el cual deben ejecutarse las tareas que conforman el
algoritmo.
Determinismo: Todas las veces que se realicen las tareas o pasos de un algoritmo, con
las mismas condiciones iniciales, se deben obtener resultados idénticos.
Instrucciones: Las acciones, procesos u operaciones que el algoritmo realiza sobre los
datos.
Estructuras de control: Las que determinan el orden en que se ejecutarán las instruc-
ciones del algoritmo.
1.2. ALGORITMOS 3
Problema
Metodologı́a
Solución
Análisis del problema: Entender de manera clara el problema que se esta resolviendo.
Proceso de identificación de objetos conocidos, objetos desconocidos y condiciones
del problema.
Prueba del algoritmo y refinamiento: Proceso de seguimiento del algoritmo para ve-
rificar que cumple con la especificación. Si no se cumple con la especificación se va
refinando hasta lograr el objetivo.
Señal
Señal recibida
Emisor Canal Receptor
Mensaje Mensaje
original final
Fuente de Fuente de
ruido Destino
información
Léxico: El léxico de un lenguaje lo conforman las unidades mı́nimas con significado com-
pleto. A cada uno de estas unidades mı́nimas con significado se le conoce como
lexema 1 .
Por ejemplo, en el español, las palabras y los sı́mbolos de puntuación (que son usa-
dos para formar frases, oraciones y párrafos) conforman el léxico. A tales lexemas
se les asocia un significado preciso en términos de las frases construidas con ellos.
Las palabras generalmente se componen de dos unidades mı́nimas: lexema y mor-
fema, las cuales aportan significado léxico y gramatical, respectivamente. Una fa-
milia de palabras comparte un mismo lexema: Arte, Artista, Artı́stico, Artesanal
[Gramáticas.net 2013].
⟨Frase⟩
⟨Sujeto⟩ ⟨Predicado⟩
un examen
Figura 2.2. Árbol de derivación
no es fácil de definir ya que intervienen elementos muy elaborados que han sido
construidos de manera natural a través del tiempo (cada objeto/idea conocido(a)
por el ser humano esta asociado(a) con una palabra).
El sentido de una frase o una oración en español depende mucho del contexto en el
que se escribe o dice la frase y del posible conjunto de significados el cual es muy
grande. Este hecho es lo que hace difı́cil para los computadores actuales, trabajar
directamente en lenguaje natural.
Para ordenarle a una máquina de computo (computador) que ejecute cierto procedi-
miento o realice un calculo predeterminado, se dispone de los lenguajes de programación,
los cuales son definidos a partir del lenguaje matemático, por eso los computadores hacen
exactamente lo que se les dice, no lo que se quiere que hagan. De esta manera, en progra-
mación se tiene un lenguaje bien definido donde los significados de las frases son únicos
(no ambiguos). Esto exige que el programador exprese de forma precisa lo que desea hacer.
Al principio programar era muy complicado ya que se programa directamente en el
hardware realizando modificaciones en dispositivos bien sea mecánicos o electrónicos con
el fin de realizar operaciones matemáticas y lógicas principalmente.
En algunos diseños se requerı́a que los programas se escribieran cableando ciertas com-
puertas de la máquina. Un error en el cableado, es decir un error en el programa era difı́cil
de detectar. Posteriormente el hombre construyó máquinas de cálculo para tareas muy es-
pecı́ficas como investigación y militares, usando dispositivos electro-mecánicos como relés
y tubos de vacı́o. Se programaba revisando las salidas de los estados de los tubos (encendi-
do ó 1 y apagado ó 0). A estos computadores solı́an acercarseles insectos en busca de calor
2.3. CLASIFICACIÓN DE LOS LENGUAJES DE PROGRAMACIÓN 9
dañando los tubos. De allı́ proviene el termino “bug” (bicho de programación) conocido
actualmente en programación como un defecto en el programa.
Otros diseños separaron la información (el programa) de la parte fı́sica, es ası́ como
llegaron las tarjetas perforadas inspiradas en las máquinas telares de la época. De esta
forma, los programas eran representados por huecos en las tarjetas, y la máquina realizaba
lecturas de aquellos huecos en un orden especı́fico. De desordenarse las tarjetas el programa
dejarı́a de funcionar.
Estos computadores dieron paso a los elementos transistorizados. Las máquinas de
cómputo de esta generación tenı́an pocas facilidades de programación. La comunicación
se establecı́a en lenguaje de máquina, que como su nombre lo indica, dependı́an de la
máquina, lo que hacia poco portable al programa.
A partir de la definición del lenguaje de máquina se generaron lenguajes a diferentes
niveles que tratan de asemejarse al lenguaje utilizado por los humanos. A continuación se
presentan una clasificación de los lenguaje por su nivel de abstracción.
CODIGO ARGUMENTO(S)
0010 00011010
1010 10111000
0110 11010001
MNEMONICO ARGUMENTO(S)
ADD R1, F4
MOV F4, C2
SUB AX, AX
MOV AX, 18D
SUB AX, 18D
INT 20h
Lo anterior dio origen a los sistemas operativos, logrando que la máquina completa
pudiera controlar otro programa.
Lenguajes de alto nivel. Aunque útil, el lenguaje ensamblador, es aún muy difı́cil de
entender, por eso se planteó la idea de generar un lenguaje más parecido al lenguaje
natural que tiene facilidades de aprendizaje, lectura, escritura, corrección, transfor-
mación y conversión.
Estos lenguajes están basados en una estructura gramatical para codificar estructuras
de control y/o instrucciones. Cuenta con un conjunto de palabras reservadas (escritas
en lenguaje natural).
Programa Programa
Compilador
fuente objeto
Lenguaje de Lenguaje de
alto nivel máquina
Lenguajes de muy alto nivel. También conocidos como lenguajes declarativos. Su defi-
nición es más complicada que la de los anteriores. Se trata esencialmente de lenguajes
taquigráficos que usan macroinstrucciones (se escribe más con menos). Cuando una
operación que requiere de cientos de lı́neas en un lenguaje de alto nivel, en un len-
guaje de muy alto nivel se requiere tı́picamente de unas cinco a diez lı́neas. Entre las
caracterı́sticas de estos lenguajes está el no uso de procedimientos. En los lenguajes
de procedimientos se dice con detalle a la computadora las tareas a realizarse. En
12 CAPÍTULO 2. LENGUAJES Y GENERACIONES DE LOS COMPUTADORES
Lenguaje
Programa Programa
Interprete de
fuente objeto máquina
Compilación
lı́nea a lı́nea
Los lenguajes de muy alto nivel son fáciles de leer, comprender y programar, no
requieren altos conocimientos de arquitecturas computacionales, esto los hace alta-
mente transportables.
El principal inconveniente de estos lenguajes es que no hacen uso eficiente de los
recursos computacionales.
Los lenguajes de alto y muy alto nivel se clasifican por el modelo conceptual que desa-
rrollan. En la siguiente se presenta esta clasificación.
2.4. PARADIGMAS DE PROGRAMACIÓN 13
• Philco 212.
• UNIVAC M460.
2.5. GENERACIONES DE LOS COMPUTADORES 15
• IBM 360.
• Control Data Corporaions serie 6000.
• Control Data Corporaions serie 6600. Considerada la más rápida de su época.
• IBM 370.
• Reemplazo de las memorias con núcleos magnéticos, por las de chips de silicio.
• Colocación de muchos componentes electrónicos en un sólo chip.
• Se aumenta la velocidad de computo.
• Reducción significativa de los costos de los computadores.
• Popularización del uso de los computadores.
• Steve Woziniak y Steve Jobs inventan la primera microcomputadora de uso
masivo, fundadores de APPLE (1976) .
• Sistemas de tratamiento de base de datos.
• Generalización de las aplicaciones.
• Multiproceso.
Quinta generación de los computadores (1982 − 1989):
• Japón lanzó en 1983 el llamado“programa de la quinta generación de compu-
tadoras”.
• Traductores de lenguajes.
• Creación de la primera supercomputadora con capacidad de proceso paralelo,
diseñada por Seymouy Cray (1982).
• Fuerte aplicación de la inteligencia artificial: sistemas expertos, redes neurona-
les, teorı́a del caos, programación heurı́stica, algoritmos genéticos.
• Fibras ópticas.
• Telecomunicaciones.
• DVD.
• Uso del ratón (mouse).
• Robots con capacidad de movimiento.
• Juegos.
• Reconocimientos de formas tridimensionales, voz e imágenes.
Sexta generación de los computadores (1990−actualidad):
• Arquitecturas combinadas Paralelo / Vectorial.
• Masificación del uso de redes de área mundial (Wide Area Network, WAN).
• Comunicación a través de fibras ópticas y satélites.
• 1997- El Pentium II
• 1999- El Pentium III
• 2001- el Pentium 4
• Intel Core i3
• Intel Core i5
• Intel Core i7
• AMD Phenom II
• Tablets y Smartphones.
Capı́tulo 3
Lógica matemática
• Pero con certeza el enunciado debe poseer algún valor fijo que lo califique.
En la lógica proposicional, el léxico esta definido por tres elementos: los sı́mbolos o
letras proposicionales, los conectivos lógicos y los paréntesis.
Definición. El léxico de la lógica proposicional se compone de tres tipos de lexemas:
El sı́mbolo proposicional ⊥ (que se lee “bottom”) es usado para representar una propo-
sición genérica que su significado es siempre falso 1 , mientras que ⊺ (que se lee “top”) es
usado para representar una proposición genérica que su significado es siempre verdadero 2 .
1
Que se representará abreviadamente por el sı́mbolo F .
2
Que se representará abreviadamente por el sı́mbolo V .
3.1. LÓGICA PROPOSICIONAL 19
El significado que cada uno de estos conectivos le da a las proposiciones compuestas que
se construyen con ellos se explicará más adelante3 .
Los paréntesis son usados para agrupar de manera apropiada las fórmulas o proposi-
ciones compuestas de la lógica proposicional.
En la lógica proposicional la gramática se describe en términos de fórmulas bien for-
madas (fbf) de manera recursiva4 , es decir, suponiendo que los sı́mbolos y letras proposi-
cionales son fbfs y definiendo nuevas fbfs en términos de fbfs ya construidas.
Definición. La gramática de la lógica proposicional se define recursivamente en términos
de fórmulas bien formadas (fbf), ası́:
ξ(f ) ξ(¬(f ))
V F
F V
para hallar el significado de f , primero se debe hallar el valor de verdad de los paréntesis
más internos y luego con esos resultados ir hallando el valor de verdad de las fórmulas más
internas que vayan apareciendo, de esta manera
3.1. LÓGICA PROPOSICIONAL 21
ası́, ξ(f ) = V .
Uno de las principales limitaciones de las fórmulas bien formadas es el uso excesivo de
los paréntesis, los cuales, en muchos casos, son redundantes. Para evitar este uso excesivo
de paréntesis (sin que esto implique que toda fórmula pueda ser escrita sin paréntesis), a
los conectores lógicos se les asigna una prioridad que determina de manera exacta el orden
en que los paréntesis se deben asumir si no se escriben. Entre más alta es la prioridad de
un conector, los paréntesis asociados a él, tienen mayor prelación, es decir, en el proceso
de completar los paréntesis, los paréntesis asociados al operador con más prioridad son
adicionados primero que los paréntesis de un conectivo con menor prioridad. Las priori-
dades asignadas a los operadores se pueden observar el la tabla 3.1. Cuando en la fórmula
aparece el mismo operador varias veces y no se puede determinar a cuál se le deben asignar
los paréntesis primero, se asignan los paréntesis de izquierda a derecha.
i) p → q ↔ r ∨ (s ∧ p)
1. f ∶= p ∨ q ↔ q ∨ p
2. f ∶= p ∧ ¬q ∧ (p → q)
3. f ∶= p ∧ (q ∨ r)
3.1. LÓGICA PROPOSICIONAL 23
Solución.
1. Si f ∶= p ∨ q ↔ q ∨ p entonces θf = {p, q}
entonces f es tautologı́a.
2. Si f ∶= p ∧ ¬q ∧ (p → q) entonces θf = {p, q}
p q ¬q p ∧ ¬q p→q p ∧ ¬q ∧ (p → q)
V V F F V F
V F V V F F
F V F F V F
F F V F V F
entonces f es contradicción.
3. Si f ∶= p ∧ (q ∨ r) entonces θf = {p, q, r}
p q r q∨r p ∧ (q ∨ r)
V V V V V
V V F V V
V F V V V
V F F F F
F V V V F
F V F V F
F F V V F
F F F F F
En la lógica proposicional clásica, una ley lógica es una equivalencia o implicación entre
fórmulas lógicas. Tal equivalencia o implicación lógica debe ser verdadera para cualquier
interpretación de las letras proposicionales que conforman las fórmulas relacionadas por
la equivalencia (debe ser tautologı́a). Las más famosas leyes lógicas son: Modus Ponen,
Modus Tollen, Inconsistencia, Doble negación, Conmutatividad, Distributivas, Asociativas
y De Morgan.
Demostración. ¿? ✓
◻
f1 ↔ f2
es una tautologı́a.
Ejemplo. Las fórmulas f1 = ¬(α∧β) y f2 = ¬α∨¬β son lógicamente equivalentes, es decir,
¬(α ∧ β) ⇔ ¬α ∨ ¬β, para cualesquiera fórmulas α y β. Para esto, se debe demostrar que
¬(α ∧ β) ↔ ¬α ∨ ¬β es una tautologı́a; como se aprecia en la siguiente tabla
α β α ∧ β ¬(α ∧ β) ¬α ¬β ¬α ∨ ¬β ¬(α ∧ β) ↔ ¬α ∨ ¬β
V V V F F F F V
V F F V F V V V
F V F V V F V V
F F F V V V V V
3.1. LÓGICA PROPOSICIONAL 25
α → β ⇔ ¬β → ¬α
con
α = n2 es impar y β = n es impar
entonces
¬α = n2 es par y ¬β = n es par
Por lo tanto demostrar el anterior teorema es equivalente a demostrar que
26 CAPÍTULO 3. LÓGICA MATEMÁTICA
para esto, obsérvese que si n es par, entonces n se puede escribir en la forma n = 2m, con
m en los enteros; ası́ que n2 = (2m)2 = 4m2 = 2(2m2 ) = 2k, donde k = 2m2 es un entero y
por lo tanto se puede concluir que n2 es par. Del razonamiento anterior se tiene que por
la equivalencia contrarrecı́proca queda demostrada la proposición original. ✓
◻
De los teoremas anteriores se tiene que para que n2 sea impar es necesario que n sea
impar, y de forma similar para que n sea impar es necesario que n2 sea impar. Esto se
expresa como que para que n2 sea impar es razón necesaria y suficiente que n sea impar,
de donde ambas proposiciones son verdaderas o ambas son falsas y se puede enunciar el
siguiente teorema bidireccional general.
Teorema. Sea n un número entero, n2 es impar, si y sólo si n es impar.
En algunos casos no es necesario exigir que dos fórmulas sean equivalentes, tal vez sea
útil exigir que en una dirección de la equivalencia la fórmula del consecuente sea verdadera
cuando la fórmula del antecedente sea verdadera, o lo que es lo mismo, que la fórmula del
antecedente sea falsa cuando la fórmula del consecuente sea falsa.
Ejemplo. A continuación se presenta un argumento directo para demostrar el siguiente
teorema.
Teorema. Sean m y n números enteros, si m es par y n es par, entonces m + n es par.
Ahora, para el enunciado que se obtiene cuando se toma el teorema en dirección recı́pro-
ca,
(f1 ∧ f2 ∧ ⋯ ∧ fn ) → g
es una tautologı́a.
Ejemplo. Las premisas Γ = {¬β, α → β} implican lógicamente a g = ¬α, para esto es
necesario que la fórmula (¬β ∧ (α → β)) → ¬α sea una tautologı́a, como se aprecia en la
siguiente tabla
α β ¬β α → β ¬β ∧ (α → β) ¬α (¬β ∧ (α → β)) → ¬α
V V F V F F V
V F V F F F V
F V F V F V V
F F V V V V V
Las implicaciones lógicas más conocidas se presentan en la tabla 3.3. Se deja al lector
la demostración de las mismas.
Implicación Nombre
{α, β} ⇒ (α ∧ β) Combinación
{α, β} ⇒ α Ley de simplificación
{α, β} ⇒ β Variante de la ley de simplificación
{α} ⇒ (α ∨ β) Ley de adición
{β} ⇒ (α ∨ β) Variante de la adición
{α, α → β} ⇒ β Modus Ponendo Ponens (Modus ponens)
{¬β, α → β} ⇒ ¬α Modus Tollendo Tollens (Modus tollens)
{α → β, β → γ} ⇒ (α → γ)
Silogismos hipotéticos
{α ↔ β, β ↔ γ} ⇒ (α ↔ γ)
{¬α, α ∨ β} ⇒ β
Silogismos disyuntivos
{α, ¬α ∨ ¬β} ⇒ ¬β
{¬β, α ∨ β} ⇒ α Variante de los silogismos
{β, ¬α ∨ ¬β} ⇒ ¬α disyuntivos
{α → β, ¬α → β} ⇒ β Ley de casos
{α ↔ β} ⇒ (α → β) Eliminación de equivalencia
Variante de eliminación
{α ↔ β} ⇒ (β → α)
de equivalencia
{β → α, α → β} ⇒ (α ↔ β) Introducción de la equivalencia
{α, ¬α} ⇒ β Ley de inconsistencia
{α → β, γ → τ, α ∨ γ} ⇒ (β ∨ τ )
Dilemas constructivos
{α → β, γ → τ, ¬β ∨ ¬τ } ⇒ (¬α ∨ ¬γ)
Tabla 3.3. Implicaciones lógicas.
“q: la foca juega con la pelota azul y verde”, en este caso las proposiciones son similares,
pues lo que cambia es el sujeto y/o el complemento.
A partir de los casos anteriores se puede pensar en definir enunciados sin un sujeto o un
complemento especı́fico. Por ejemplo el sujeto puede cambiar (la foca, el niño) y también
el complemento puede cambiar (la pelota roja y blanca, la pelota azul y verde) de acuerdo
a una realidad. Esto da como resultado frases del estilo “x juega con y”.
x e y son objetos que están relacionados mediante un predicado y dependiendo de
los objetos, se obtiene una proposición que es V o es F . En términos de los sujetos y
los complementos se define un predicado o proposición abierta a una frase que dice algo
acerca del sujeto que lo relaciona con el complemento. En el ejemplo anterior el predicado
es “juega con” y se escribirı́a simbólicamente mediante le expresión juegaCon(x, y), que
se interpreta conceptualmente como “x juega con y”, a las variables x e y se les denomina
variables libres.
Un predicado da una forma más amplia de hablar. Se podrı́a tener una colección
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, y sobre esta colección se puede definir un predicado. Por ejem-
plo, se podrı́a hablar del predicado esP ar(x). Si se toma el predicado y se asigna al sujeto
x el valor 3 entonces esP ar(3) tendrá un valor de verdad F , si se toma el predicado y se
asigna al sujeto x el valor 6 entonces esP ar(6) tendrá un valor de verdad V .
3.2. LÓGICA DE PREDICADOS 29
A una colección de objetos a los cuales se les desea aplicar el predicado se le llama el
universo del discurso. Cuando en un predicado se reemplaza una variable libre x por un
valor concreto del universo del discurso, se dice que se está “instanciando” la variable x,
la fórmula resultante se dice que es una “instancia” o del predicado inicial.
Cuando no se ha instanciado un predicado, a éste no se le puede asignar un valor de
verdad. Por ejemplo, el predicado o proposición abierta esP rimo(x) no se puede valorar,
por el contrario, cuando se instancian todas las variables de un predicado, lo que se obtiene
es una proposición cerrada, y por lo tanto se cumple la condición de que en ese caso la
instancia tendrá un valor o V o F , y no puede tener los dos a la vez.
3.2.1. Cuantificadores
Pueden haber predicados como esDigito(x) que para todos los objetos del univer-
so del discurso {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} son V . Para este mismo universo, el predica-
do esM ayora10(x) es F para todos los elementos de dicha colección, y el predicado
esM oduloAditivo(x) es V sólo para x = 0 y para el resto de los casos será F .
Cuando se desea expresar que un predicado P (x) describe una propiedad sobre todos
los elementos del universo del discurso o para sólo algunos, se dice que se está cuantificando
la variable x, y ahora la variable libre pasa a ser una variable ligada.
Cuando se desea expresar que un predicado describe una propiedad para todos los
elementos del universo del discurso, se dice que se está cuantificando universalmente.
Cuando el predicado describe una propiedad para algunos de los elementos del universo
del discurso, se dice que se está cuantificando existencialmente.
Para expresar estas nuevas propiedades se necesitan nuevos sı́mbolos, y estos son los
sı́mbolos ∀ y ∃ que permiten ampliar el léxico y se utilizan de la siguiente manera:
Cuando en una expresión una variable está cuantificada universalmente, se tiene que
Ejemplo. Si se tienen los números dı́gitos como universo del discurso y se establece como
predicado
P (x) ∶= x es múltiplo de 4,
se tiene que ξ(∃xP (x)) = V y ξ(∀xP (x)) = F ; esto porque el predicado será cierto cuando
se instancia la variable con los valores 0, 4 y 8 (P (0), P (4), P (8)), aquı́ se ha tomado la
definición de múltiplo como
¬∃xP (x) ⇔ ∀x¬P (x): no existe un x que cumpla el predicado P quiere decir que para
todo x no se cumple el predicado P .
¬∀xP (x) ⇔ ∃x¬P (x): no todo x cumple el predicado P es decir que existe un x que no
cumple el predicado.
∀x P (x)
∴ P (d) si d ∈ D
∀x(Humano(x) → M ortal(x))
Humano(Aristoteles)
∴ M ortal(Aristoteles)
• Bart vive en Springfield. • Homero vive en Springfield.
• Lisa vive en Springfield.
Ejemplo. De los planetas en el Sistema Solar ☼ , existen planetas que poseen vida inte-
ligente. Mediante particularización existencial se puede inferir que
“Algún planeta del Sistema Solar ☼, como La Tierra m, posee vida inteligente”.
3.2.4.4. Generalización existencial
Ejemplo. En los personajes de Los Simpson, El señor Burns es el jefe de Homero
3.3. Ejercicios
1. De los siguientes enunciados ¿cuáles son proposiciones y cuáles no?, justifique su
respuesta.
• Tom Hanks ha ganado dos premios Oscar como mejor actor por dos años con-
secutivos.
• Dame una cerveza.
• Colombia ganó ocho medallas olı́mpicas en Londres 2012.
• Todo número primo es impar.
• 1 + 1 = 2.
• La diferencia de dos primos.
• Todo número par mayor que 2 puede escribirse como suma de dos números
primos. (Christian Goldbach, 1742).
• ¿Que hora es?.
• xn + y n = z n .
• x + y = z + y si x = z.
2. De las siguientes secuencias de sı́mbolos ¿cuáles son fórmulas bien formadas y cuáles
no?.
• ((¬(p) → r) ∧ (p ¬ q))
• ((¬(p) ↔ ¬(q)) ↔ (q → r))
• (p ∧ q) ∨ (q → p))
• ((p ↔ p) ∧ (p → p) ∨ (p ∧ ¬(p)))
3. Escriba la fórmula bien formada que representa cada una de la siguientes secuencias
de sı́mbolos:
• p∧q ↔r∨s→q
• p→q→q→p
• ¬p ↔ q ∨ ¬r ∨ (q → r) ↔ ¬¬q
• p ∨ (q ∧ r) ↔ p ∨ q ∧ (p ∨ q)
• f1 ∶= p → q y f2 ∶= q → p
• f1 ∶= p → q y f2 ∶= ¬p → ¬q
• f1 ∶= p ∧ q ∨ r y f2 ∶= p ∧ (q ∨ r)
8. Con los operadores lógicos ¬ y ∧ es posible expresar los otros operadores lógicos
(∨, →, ↔) de forma equivalente, de la siguiente manera
p ∨ q ⇔ ¬(¬p ∧ ¬q)
p → q ⇔ ¬(p ∧ ¬q)
p ↔ q ⇔ ¬(p ∧ ¬q) ∧ ¬(q ∧ ¬p)
9. Con los operadores lógicos ¬ y ∨ es posible expresar los otros operadores lógicos
(∧, →, ↔). Encontrar fórmulas lógicas que contengan sólo los operadores lógicos ¬ y
∨ que sean equivalentes a las fórmulas p∧q, p → q, p ↔ q y verifique que efectivamente
son lógicamente equivalentes.
10. Adicional a los conectivos lógicos presentados, existen otros conectivos, tal como el
conectivo o exclusivo (⊗), el cual es muy utilizado en computación, y tiene como
objetivo que dadas dos fórmulas f1 y f2 , la operación f1 ⊗ f2 será únicamente ver-
dadera cuando se cumpla que sólo una de la fórmulas f1 o f2 sea verdadera. De esta
manera, la semántica para este conectivo es la siguiente
11. Adicional a los conectivos lógicos presentados, existe otro conectivo, tal como el
conectivo barra de Sheffer (∣), para el cual su semántica es la siguiente
3.3. EJERCICIOS 35
¬f ⇔ f ∣ f
f1 ∨ f2 ⇔ (f1 ∣ f1 ) ∣ (f2 ∣ f2 )
f1 ∧ f2 ⇔ (f1 ∣ f2 ) ∣ (f1 ∣ f2 )
f1 → f2 ⇔ f1 ∣ (f2 ∣ f2 )
12. Adicional a los conectivos lógicos presentados, existe otro conectivo, tal como el
conectivo flecha de Peirce (↓), para el cual su semántica es la siguiente
¬f ⇔ f ↓ f
f1 ∨ f2 ⇔ (f1 ↓ f2 ) ↓ (f1 ↓ f2 )
f1 ∧ f2 ⇔ (f1 ↓ f1 ) ↓ (f2 ↓ f2 )
f1 → f2 ⇔ ((f1 ↓ f1 ) ↓ f2 ) ↓ ((f1 ↓ f1 ) ↓ f2 )
13. Hallar el valor de verdad para los siguientes predicados donde las variables están
cuantificadas y el universo del discurso de las variables x y y son los números reales,
el de las variables n y m son los números naturales y a, b, c, d también son números
reales.
36 CAPÍTULO 3. LÓGICA MATEMÁTICA
i. ∃x ∀n (x > n).
ii. ∃x ∀n (x < n).
iii. ∀n ∃x (x > n).
iv. ∀n ∃x (x < n).
v. ∀x (x2 > 0).
vi. ∀x (x2 ≥ x).
vii. ∀x (−x ≤ 0).
viii. ∀x (x tiene inverso aditivo) ⇔ ∀x ∃y (x + y = 0).
ix. ∀x (x tiene inverso multiplicativo) ⇔ ∀x ∃y (xy = 1).
x. ∃x ∀y (xy = y)
xi. ∃x ∀y (xy = x)
xii. ∀x ∃y (xy = y)
xiii. ∀x ∃y (xy = x)
xiv. ∃x ∀a ∀b ∀c ((ax2 + bx + c = 0) ∧ (a ≠ 0)).
xv. ∀a ∀b ∀c ∃x ((ax2 + bx + c = 0) ∧ (a ≠ 0)).
xvi. ∃x ∀a ∀b ∃c ((ax2 + bx + c = 0) ∧ (a ≠ 0)).
xvii. ∃x ∀a ∀b ∀c ∀d ((ax3 + bx2 + cx + d = 0) ∧ (a ≠ 0)).
xviii. ∀a ∀b ∀c ∀d ∃x ((ax3 + bx2 + cx + d = 0) ∧ (a ≠ 0)).
xix. ∃x ∀a ∀b ∀c ∃d ((ax3 + bx2 + cx + d = 0) ∧ (a ≠ 0)).
xx. ∃n ∀m ((n ∣ m) ∧ (n ≠ 0)).
xxi. ∀n ∃m ((n ∣ m) ∧ (n ≠ 0)).
xxii. ∃m ∀n ((n ∣ m) ∧ (n ≠ 0)).
14. Usando las leyes de De Morgan para cuantificadores, negar los predicados del nume-
ral 13.
Capı́tulo 4
Teorı́a de conjuntos
Un conjunto A es una colección bien definida de objetos. Se dice que una colección A
está bien definida si existe un predicado ΦA (llamado constructor del conjunto A), que
determina de manera exacta los objetos que pertenecen a la colección.
⎧
⎪
⎪V, si x = 1, x = 2, x = 3 o x = 4;
ΦA (x) = ⎨
⎪
⎪
⎩F, en otro caso.
Ejemplo. Para el conjunto A = {1, 2, 3, 4}, se tiene que 1 es elemento de A (ΦA (1) = V ),
y 5 no es elemento de A (ΦA (5) = F ).
∈(x, A) ⇔ ΦA (x)
4.1.2.1. Extensión
A = {x1 , x2 , . . . , xn }
donde xi son los objetos en el conjunto A. De esta manera el predicado asociado al conjunto
es,
⎧
⎪
⎪V, si x = xi para algún i = 1, 2, . . . , n;
ΦA (x) = ⎨
⎪F, en otro caso.
⎪
⎩
Ejemplos.
1. A = {1, 2, 3, 4}
2. B = {¨, ©, ª, «}
3. C = {a, e, i, o, u}
4. B = {V, F }
5. N = {0, 1, 2, 3, 4, 5, . . .}
6. P = {1, 2, 3, 4, 5, . . .}
4.1.2.2. Comprensión
A = {x ∶ ΦA (x)}.
• 2N = {x ∶ (x = 2n) ∧ (n ∈ N)}
4.1. CONCEPTOS BÁSICOS 39
• 2N + 1 = {x ∶ (x = 2n + 1) ∧ (n ∈ N)}
• R− = {x ∶ (x ∈ R) ∧ (x < 0)}
• R0,+ = {x ∶ (x ∈ R) ∧ (x ≥ 0)} 1
√
• C = {x ∶ (x = a + bi) ∧ (a, b ∈ R) ∧ (i = −1)}
(i denota la unidad imaginaria)
• A = {x ∶ (x ∈ R) ∧ (x2 ≤ 1)}
• B = {x ∶ x es una pinta del poker}
• C = {x ∶ x es una vocal del idioma español}
Todo conjunto finito no vacı́o se puede representar mediante los llamados diagramas de
Venn, de la siguiente forma
A
1
2 3
A = {1, 2, 3, 4, 8, ¨, ª, _} 4 8
¨ ª
_
A B
7 2 1
4
8 3
¨
« ª _
A B
4 s
2 3 6 7
5 n
1 l 8 u
9 0
C
Sean A y B dos conjuntos, A esta contenido en B si y sólo si todos los elementos del
conjunto A están en el conjunto B. La contenencia entre conjuntos es un predicado que
se define de la siguiente manera
contenido(A, B) ⇔ (x ∈ A → x ∈ B)
4.1. CONCEPTOS BÁSICOS 41
C B
0 8 « 1
2
¨ 3
4
6 ª © _
(A = B) ⇔ (ΦA ⇔ ΦB ).
• A⊆B
• B⊆A
• por lo tanto A = B
• A⊆C
• C⊈A
• es decir A ≠ C
• de donde A ⊊ C (A es un subconjunto propio de C)
42 CAPÍTULO 4. TEORÍA DE CONJUNTOS
4.2.1. Unión
ΦA∪B (x) ⇔ x ∈ (A ∪ B) ∶= (x ∈ A) ∨ (x ∈ B)
A ∪ B = {x ∶ (x ∈ A) ∨ (x ∈ B)}.
A B A B
A∪B
1. A ∪ B = B ∪ A. (conmutativa)
4.2. CONSTRUCCIÓN DE CONJUNTOS 43
A B
2 3 4
1 8
¨ ª _
2. (A ∪ B) ∪ C = A ∪ (B ∪ C). (asociativa)
3. A ⊆ A ∪ B. (absorción)
4. B ⊆ A ∪ B. (absorción)
5. A ∪ ∅ = A. (identidad)
6. A ∪ A = A. (idempotencia)
7. A ⊆ B ⇔ A ∪ B = B.
4.2.2. Intersección
ΦA∩B (x) ⇔ x ∈ (A ∩ B) ∶= (x ∈ A) ∧ (x ∈ B)
A ∩ B = {x ∶ (x ∈ A) ∧ (x ∈ B)}.
A B A B
A∩B
A B
2
4
¨
ª
1. A ∩ B = B ∩ A. (conmutativa)
2. (A ∩ B) ∩ C = A ∩ (B ∩ C). (asociativa)
3. A ∩ (B ∪ C) = (A ∩ B) ∪ (A ∩ C) (distributiva)
4. A ∪ (B ∩ C) = (A ∪ B) ∩ (A ∪ C) (distributiva)
5. A ∩ B ⊆ A. (absorción)
6. A ∩ B ⊆ B. (absorción)
7. A ∩ ∅ = ∅. (dominación)
8. A ∩ A = A. (idempotencia)
9. A ⊆ B ⇔ A ∩ B = A.
4.2.3. Complemento
ΦA (x) ⇔ x ∈ ( A ) ∶= (x ∈ U ) ∧ (x ∉ A)
A = {x ∶ (x ∈ U ) ∧ (x ∉ A)}.
4.2. CONSTRUCCIÓN DE CONJUNTOS 45
U U
A A
1 3 5 6 7 U
9
A
0
©
«
_
Figura 4.7. Representación del conjunto A = {1, 3, 5, 6, 7, 9, 0, ©, «, _} mediante diagramas de
Venn.
1. A ∪ A = U. (completación)
2. A ∩ A = ∅. (nilpotencia)
3. A = A. (idempotencia)
4. U = ∅.
5. ∅ = U.
6. (A ∩ B) = A ∪ B. (De Morgan)
7. (A ∪ B) = A ∩ B. (De Morgan)
8. A ⊆ B ⇔ B ⊆ A.
46 CAPÍTULO 4. TEORÍA DE CONJUNTOS
4.2.4. Diferencia
ΦA∖B (x) ⇔ x ∈ (A ∖ B) ∶= (x ∈ A) ∧ (x ∉ B)
A ∖ B = {x ∶ (x ∈ A) ∧ (x ∉ B)}.
A B A B
A∖B
A B
1. A ∖ ∅ = A. (identidad)
4.2. CONSTRUCCIÓN DE CONJUNTOS 47
A B
1
2. A ∖ A = ∅. (nilpotencia)
3. A ∖ B ≠ B ∖ A. (no conmutatividad)
4. A ∖ B = A ∩ B.
5. A ∖ B = ∅ ⇔ A ⊆ B.
6. A ∖ B = A ⇔ A ∩ B = ∅.
7. U ∖ A = A.
8. U ∖ A = A.
A △ B = {x ∶ x ∈ ((A ∪ B) ∖ (A ∩ B))}.
1. A △ B = (A ∖ B) ∪ (B ∖ A).
2. A △ B = B △ A. (conmutativa)
48 CAPÍTULO 4. TEORÍA DE CONJUNTOS
A B A B
A△B
A B
1
8 3
3. (A △ B) △ C = A △ (B △ C). (asociativa)
4. A △ A = ∅. (nilpotencia)
5. A △ ∅ = A. (identidad)
6. A ∩ (B △ C) = (A ∩ B) △ (A ∩ C). (distributiva)
℘(A) = {X ∶ X ⊆ A}.
Ejemplo. Para el conjunto A = {1, 2, 3} se tiene que
℘(A) = {∅, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}}.
4.2. CONSTRUCCIÓN DE CONJUNTOS 49
Definición. Para todo par de objetos a y b existe un único objeto llamado par ordenado
de a con b y notado (a, b), que se define como
Nota. Las parejas (a, b) y (c, d) serán distintas, es decir, (a, b) ≠ (c, d) sólo si se cumple
alguna de las siguientes condiciones:
• (a ≠ c) ∧ (b ≠ d)
• (a = c) ∧ (b ≠ d)
• (a ≠ c) ∧ (b = d)
Proposición. Sean a y b dos objetos, se tiene que si a ≠ b, entonces los pares ordenados
(a, b) y (b, a) no son iguales.
A × B = {(x, y) ∶ (x ∈ A) ∧ (y ∈ B)}.
50 CAPÍTULO 4. TEORÍA DE CONJUNTOS
B × A = {(¨, 1), (¨, 2), (¨, 3), (©, 1), (©, 2), (©, 3),
(ª, 1), (ª, 2), (ª, 3), («, 1), («, 2), («, 3)}.
Ejemplo. Para los conjuntos A = {1, 2, 3}, B = {¨, ©, ª, «} y C = {+, ∗} se tiene que
A × B × C = {(1, ¨, +), (1, ¨, ∗), (1, ©, +), (1, ©, ∗), (1, ª, +), (1, ª, ∗),
(1, «, +), (1, «, ∗), (2, ¨, +), (2, ¨, ∗), (2, ©, +), (2, ©, ∗),
(2, ª, +), (2, ª, ∗), (2, «, +), (2, «, ∗), (3, ¨, +), (3, ¨, ∗),
(3, ©, +), (3, ©, ∗), (3, ª, +), (3, ª, ∗), (3, «, +), (3, «, ∗)}.
4.2.7. Cardinalidad
Todos los conjuntos poseen una propiedad muy importante llamada cardinalidad, ésta
se refiere a la cantidad de elementos que posee el conjunto. El cardinal de un conjunto A
es único y se denota por ∣A∣.
Con base en el concepto de cardinal se puede decidir si un conjunto es finito o infinito,
ası́, un conjunto es finito si el conjunto es el vacı́o o su cardinal es un número natural, en
caso contrario se dice que es infinito.
Ejemplo. Para los siguientes conjuntos finitos
A=∅ F = {¨, ©, ª, «}
B = {0} G = {1, 3, 5, 7, 9, ¨, ª}
C = {_} H = {2, 4, 6, 8, 0, ©, «}
D = {∅} I = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, ¨, ©, ª, «, _}
E = {∅, {∅}}
se tiene que:
4.2. CONSTRUCCIÓN DE CONJUNTOS 51
• ∣C∣ = 1 • ∣F ∣ = 4 • ∣I∣ = 15
Para el caso de los conjuntos infinitos, estos pueden tener distinto cardinal,
Ejemplo.
• ∣N∣ = ℵ0 • ∣N × N∣ = ℵ0
(que se lee “alef cero”)
• ∣℘(N)∣ = ℵ1 = 2ℵ0
• ∣P∣ = ℵ0
• ∣I∣ = ℵ1 = 2ℵ0
• ∣2N∣ = ℵ0
• ∣2N + 1∣ = ℵ0 • ∣R∣ = ℵ1 = 2ℵ0
• ∣Z∣ = ℵ0 • ∣R × R∣ = ℵ1 = 2ℵ0
4.3. Ejercicios
1. Sea ΦA el siguiente predicado constructor del conjunto A
⎧
⎪
⎪V, si x es un dı́gito y x es un multiplo de 3;
ΦA (x) = ⎨
⎪
⎪
⎩F, en otro caso.
¿Cuál es el conjunto listado por extensión que define ΦA (x)?.
3. Encuentre todos los conjuntos A, tales que A ⊆ B, para el conjunto B = {l, n, s, u}.
i. A ∪ B vii. B ∩ C
ii. A ∩ C viii. A ∖ B
iii. (A ∩ B) ∪ C ix. A
iv. (A ∪ C) ∩ (B ∪ C) x. A ∖ (B ∩ C)
v. B ∪ C xi. A ∩ B ∖ C
vi. A ∩ C xii. A ∖ (B ∖ C)
i. A × B vi. C × B xi. B × C × A
ii. B × A vii. B × B xii. C × A × B
iii. A × C viii. A × B × C xiii. C × B × A
iv. C × A ix. A × C × B xiv. (A × B) × C
v. B × C x. B × A × C xv. A × (B × C)
esto porque al sumar ∣A∣ y ∣B∣ se incluye dos veces ∣A ∩ B∣, y por lo tanto hay que
restarlo. Para el caso de tres conjuntos A, B y C, ¿Cuál es el cardinal del conjunto
A ∪ B ∪ C?. Ayuda: Utilice diagramas de Venn para tres conjuntos.
i. A ∖ B iii. B ∖ A v. C ∖ A
ii. A ∖ C iv. B ∖ C vi. C ∖ B
11. Sea ΦA△B el siguiente predicado constructor del conjunto diferencia simétrica A △ B
⎧
⎪
⎪V, (x ∈ A) ⊗ (x ∈ B);
ΦA△B (x) = ⎨
⎪
⎪
⎩F, en otro caso.
(a) Haga un diagrama de Venn que represente la operación A △ B entre conjuntos.
(b) Para los conjuntos A, B y C del numeral 4 calcule:
i. A △ B iii. B △ A v. C △ A
ii. A △ C iv. B △ C vi. C △ B
12. En una Facultad de Ciencias Polı́ticas estudian 140 estudiantes, de los cuales se tiene
la siguiente información
• 58 estudian derecho.
• 63 estudian ciencias polı́ticas
• 58 estudian administración publica.
• 19 estudian derecho y ciencias polı́ticas
• 17 estudian derecho y administración publica.
• 4 estudian ciencias polı́ticas y administración publica.
54 CAPÍTULO 4. TEORÍA DE CONJUNTOS
i
x
suma
sumando1
sumando2
Edad
paisDeNacimiento
_nombre
area_circulo
Las siguientes secuencias de caracteres son ejemplos de secuencias que no son identifi-
cadores, ¿por qué?:
1er_mes
primer nombre
while
p@dre
dı́a
Una nota importante que los lenguajes C++ y Java son sensibles a mayúsculas y
minúsculas, esto quiere decir que por ejemplo los identificadores
sirven para declarar entidades (variable, funciones, etc.) que son diferentes, pues al ser la
misma palabra, difiere en que algunas letras son mayúsculas en unos identificadores y en
los otros no.
Cabe anotar que existen lenguajes que no son sensibles a mayúsculas y minúsculas,
tales como DFD y FORTRAN.
Una variable es un espacio de la memoria M donde se almacena un dato, es un espa-
cio donde se guarda la información necesaria para realizar las acciones que ejecutan los
programas.
1 1 ⋯ 0 1
x
5.2. TIPOS DE DATOS PRIMITIVOS 57
T x;
Estos tipos de datos son conocidos como primitivos pues están definidos en el lenguaje
de programación C++ y porque de ellos se pueden derivar otros tipos de datos definidos
por el programador.
5.2.1. Enteros
int x;
lo que sirve para declarar que la variable x pertenece a los enteros que son representables
en el lenguaje C++.
58 CAPÍTULO 5. INTRODUCCIÓN A LOS LENGUAJES DE PROGRAMACIÓN
−2147483648 ≤ x ≤ 2147483647
Los literales enteros, es decir, la sintaxis de los valores que pueden ser asignados a las
variables de tipo int que soporta C++ son por ejemplo:
-32768 -0 -1 -127
32768 0 1 127
+32768 +0 +1 +127
Cuando se declara una variable de tipo entero, no se sabe que valor tiene, por eso es
necesario inicializar la variable. Los siguientes son ejemplos de inicializaciones de variables
de tipo int
int i = 0;
int j = 1;
int n = 5;
int p = -10;
int k = -1;
5.2.2. Reales
double x;
lo que sirve para declarar que la variable x pertenece a los reales de máquina que son
representables en el lenguaje C++.
El subconjunto de los números reales que pueden ser representados en el lenguaje C++,
es un subconjunto propio de los racionales, que se representan con 64 bits (8 bytes) y que
usan un tipo de codificación definida por el IEEE standard for Binary Floating-Point
Arithmetic 754 de 1985, los valores distintos de 0 de este conjunto varı́an en el rango
y
2.2250738585072014 × 10−308 ≤ x ≤ 1.7976931348623157 × 10+308
que dan una precisión cientı́fica de 15 dı́gitos.
Los números reales son densos en ellos mismos, es decir, que dados dos reales distintos
siempre se puede encontrar uno distinto que se encuentre entre ellos dos.
Los números reales de máquina no son densos, esto sucede por que los números reales
de máquina son finitos y por lo tanto, existen números distintos para los cuales no hay
números entre ellos. Además, la mayorı́a de los números se acumulan alrededor del 0 y
hacia los extremos superior e inferior se encuentran más dispersos.
Ejemplo. Para una máquina muy sencilla que utiliza una representación en base 2, que
utiliza 5 bits; de estos 1 para el signo, 3 para el exponente y 1 para la mantisa. El conjunto
de los números de esta máquina son los siguientes:
−6 −4 −3 −2 3
−2 −1 0 1 3
2
2 3 4 6
−1 − 43 − 21 − 83 − 41 0 1 3 1 3 1
4 8 2 4
Obsérvese como alrededor del origen se acumulan muchos números y hacia los extremos
se encuentran más dispersos.
Los literales reales, es decir, la sintaxis de los valores que pueden ser asignados a las
variables de tipo double que soporta C++ son por ejemplo:
Cuando se declara una variable de tipo real, no se sabe que valor tiene, por eso es
necesario inicializar la variable. Los siguientes son ejemplos de inicializaciones de variables
de tipo double
60 CAPÍTULO 5. INTRODUCCIÓN A LOS LENGUAJES DE PROGRAMACIÓN
double e = 2.7182818284;
double a = +1.0;
double X = -1.0;
double coordenada_1 = -2.5;
double const_Boltzmann = 1.3806488E-23;
double Luz = 2.998e+8;
double Avogadro = +6.02214129e+23;
double G = 6.67384e-11;
double Plank = 6.62606896E-34;
5.2.3. Booleanos
bool x;
lo que sirve para declarar que la variable x pertenece al conjunto de los booleanos (B =
{V, F }).
Como sólo hay dos valores de verdad V y F , en C++ sólo hay dos literales para
representar los valores lógicos, estos son:
true false
bool b = true;
bool flag = true;
bool exp = false;
bool isPrime = false;
el entero 0 (cero) y el valor lógico V se representa con cualquier entero distinto de 0, por
costumbre se usa el entero 1 (uno). De lo anterior se obtienen las siguientes equivalencias
lógicas:
V ⇔1 F ⇔0
Ejemplo. Para las inicializaciones del ejemplo anterior se tiene que las siguientes expre-
siones son equivalentes
bool b = 1;
bool flag = 1;
bool exp = 0;
bool isPrime = 0;
5.2.4. Caracteres
Los caracteres representan los sı́mbolos definidos por el conjunto ASCII (American
Standard Code for Information Interchange). Los caracteres se representan con 8 bits (1
byte), lo que ofrece 256 sı́mbolos distintos. El conjunto ASCII cumple con la siguiente
caracterı́stica
char x;
lo que sirve para declarar que la variable x pertenece al conjunto de los ASCII.
Existen algunos caracteres especiales que no tiene su propio sı́mbolo en el teclado o
que no se imprime el sı́mbolo en la pantalla o que tienen un uso particular en C++
68 CAPÍTULO 5. INTRODUCCIÓN A LOS LENGUAJES DE PROGRAMACIÓN
\n : Nueva lı́nea.
\t : Tabulador horizontal.
\\ : Diagonal invertida (back slash).
\’ : Imprime apóstrofo.
\" : Imprime Comillas.
\b : Retroceso (retrocede un espacio el cursor).
\v : Tabulador vertical (coloca el cursor justo debajo del último carácter de la lı́nea actual).
\r : Retorno de carro (coloca el cursor en el primer carácter
de la lı́nea actual y sobreescribe el texto de la lı́nea).
\? : Imprime el sı́mbolo de interrogación.
Cuando se declara una variable de tipo carácter, no se sabe que valor tiene, por eso es
necesario inicializar la variable. Los siguientes son ejemplos de inicializaciones de variables
de tipo char, para indicar que se está definiendo un literal de carácter, se encierra el
sı́mbolo entre
apóstrofos ’ ’, ası́ como se muestra a continuación:
char c = ’ ’;
char CH = ’\n’;
char tab = ’\t’;
char letra = ’a’;
char caracter = ’A’;
char value = ’\"’;
char _last = ’\’’;
char C_0 = ’&’;
char cero = ’0’;
char at = ’@’;
Para los datos de tipo numérico se pueden utilizar los siguientes operadores infijos, a
excepción del operador - que puede actuar también como un operador prefijo:
5.3. OPERADORES Y EXPRESIONES ARITMÉTICAS 69
+ : Suma de dos valores, por ejemplo, cuando se evalúa la expresión 2.0 + 3.0 se obtiene
el valor 5.0.
- : Resta de dos valores, por ejemplo, cuando se evalúa la expresión 2.0 - 3.0 se obtiene
el valor −1.0. También se utiliza para cambiar el signo de un número si se utiliza con
un sólo operando, por ejemplo, cuando se evalúa la expresión -23 se obtiene el valor
−23.
* : Multiplicación de dos valores, por ejemplo, cuando se evalúa la expresión 2.0 * -3.0
se obtiene el valor −6.0. La multiplicación es explicita, es decir no se puede escribir
una expresión como (2.0)(-3.0), esto se debe escribir como (2.0)*(-3.0).
/ : División de dos valores, cuando alguno de los operandos es real retorna la división
exacta, por ejemplo, cuando se evalúa la expresión -3.0/2 se obtiene el valor −1.5.
Cuando ambos operandos son enteros, se obtiene la parte entera de la división exacta,
por ejemplo, cuando se evalúa la expresión -3/2 se obtiene el valor −1. El valor del
segundo operando debe ser distinto de 0.
% : El resto de la división de dos números que deben ser enteros, representa la operación
matemática
m mód n = r,
por ejemplo, cuando se evalúa la expresión 9 % 4 se obtiene el valor 1, que es lo
mismo que 9 mód 4 = 1, el residuo de dividir 9 entre 4.
m n 9 4
r c m÷n 1 2 9 / 4
m mód n 9 % 4
Para asignar valores a variables se pueden utilizar los siguientes operadores infijos:
= : Asignación. La parte de la izquierda que debe ser una variable. Sirve para almacenar
un dato en una variable. Asigna el valor de evaluar la parte de la derecha a la
variable de la parte de la izquierda. Por ejemplo, cuando se evalúa la expresión
pi = 3.14159265, entonces se almacena el valor 3.14159265 en la variable pi.
+= : Asignación con suma. La parte de la izquierda debe ser una variable. Suma la eva-
luación de parte de la derecha con el valor almacenado en la variable definida en la
parte de la izquierda y guarda el resultado en la variable de parte de la izquierda.
Por ejemplo, la expresión x += 2, es equivalente a la expresión x = x + 2.
70 CAPÍTULO 5. INTRODUCCIÓN A LOS LENGUAJES DE PROGRAMACIÓN
-= : Asignación con resta. La parte de la izquierda debe ser una variable. Resta al valor
almacenado en la variable definida en la parte de la izquierda el resultado de la
evaluación de parte de la derecha y guarda el resultado en la variable de parte de la
izquierda. Por ejemplo, la expresión x -= 2, es equivalente a la expresión x = x - 2.
*= : Asignación con multiplicación. La parte de la izquierda debe ser una variable. Mul-
tiplica el valor almacenado en la variable definida en la parte de la izquierda con la
evaluación de parte de la derecha y guarda el producto en la variable de parte de la
izquierda. Por ejemplo, la expresión x *= 2, es equivalente a la expresión x = x * 2.
/= : Asignación con división. La parte de la izquierda debe ser una variable. Divide el
valor almacenado en la variable definida en la parte de la izquierda entre el valor
de la evaluación de la parte de la derecha y guarda el resultado en la variable de
parte de la izquierda. Por ejemplo, la expresión x /= 2, es equivalente a la expresión
x = x / 2. El valor de la evaluación de la parte de la derecha debe ser distinto de
0.
%= : Asignación con residuo. La parte de la izquierda debe ser una variable. Calcula el re-
siduo de dividir el valor almacenado en la variable definida en la parte de la izquierda
entre el valor de la evaluación de la parte de la derecha y guarda el resultado en la
variable de parte de la izquierda. Por ejemplo, la expresión x %= 2, es equivalente a
la expresión x = x % 2. El valor de la evaluación de la parte de la derecha debe ser
distinto de 0.
Dos de los operadores más utilizados para asignar valores a variables en programación
son los operadores de incremento y decremento:
int x = 2;
int y = ++x;
se tiene que al final las variables almacenan los valores x = 3 y y = 3. El código anterior es
equivalente al siguiente código
5.3. OPERADORES Y EXPRESIONES ARITMÉTICAS 71
int x = 2;
x = x + 1;
int y = x;
int x = 2;
int y = x++;
se tiene que al final las variables almacenan los valores x = 3 y y = 2. El código anterior es
equivalente al siguiente código
int x = 2;
int y = x;
x = x + 1;
int x = 2;
int y = --x;
se tiene que al final las variables almacenan los valores x = 1 y y = 1. El código anterior es
equivalente al siguiente código
int x = 2;
x = x - 1;
int y = x;
72 CAPÍTULO 5. INTRODUCCIÓN A LOS LENGUAJES DE PROGRAMACIÓN
int x = 2;
int y = x--;
se tiene que al final las variables almacenan los valores x = 1 y y = 2. El código anterior es
equivalente al siguiente código
int x = 2;
int y = x;
x = x - 1;
int x = 3;
int y = 2 * ++x;
se tiene que al final las variables almacenan los valores x = 4 y y = 8. El código anterior es
equivalente al siguiente código
int x = 3;
x = x + 1;
int y = 2 * x;
int x = 3;
int y = 2 * x--;
se tiene que al final las variables almacenan los valores x = 2 y y = 6. El código anterior es
equivalente al siguiente código
int x = 3;
int y = 2 * x;
x = x - 1;
int x = 2;
int y = 4;
int z = ++x * y--;
5.3. OPERADORES Y EXPRESIONES ARITMÉTICAS 73
se tiene que al final las variables almacenan los valores x = 3, y = 3 y z = 12. El código
anterior es equivalente al siguiente código
int x = 2;
int y = 4;
x = x + 1;
int z = x * y;
y = y - 1;
De entero a real: dado un dato o una variable de tipo entero, si se opera o se asigna
el dato o la variable con un dato o una variable de tipo real, entonces al realizar la
operación o la asignación, el dato entero se convierte (se promueve) a un dato de
tipo real de forma automática, simplemente agregándole la parte decimal “.0”.
int n = 1;
double x = n;
double y = 0;
double z = -2;
n 1
x 1.0
y 0.0
z −2.0
Ejemplo. Las siguientes operaciones son equivalentes
De real a entero: dado un dato o una variable de tipo real, si se asigna el dato o la
variable a una variable de tipo entero, entonces el valor del dato o la variable se
convierte (se promueve) a un dato de tipo entero de forma automática, simplemente
eliminando la parte decimal del real y dejando la parte entera.
double x = 1.0;
double y = -2.5;
int n = x;
int m = y;
int p = 3.14159265;
x 1.0
y −2.5
n 1
m −2
p 3
Si se desea convertir el valor de un dato o una variable de tipo real de forma directa,
sin necesidad de asignarlo a una variable, se pueden utilizar las instrucciones:
(int)valor;
(int)variable;
double x = 1.0;
double y = -2.5;
int n = (int)x;
int m = (int)y;
int p = (int)3.14159265;
x 1.0
y −2.5
n 1
m −2
p 3
• 2 * (int)2.5 ⇔ 2 * 2
• (int)-3.14 * (int)5.5 ⇔ -3 * 5
5.3. OPERADORES Y EXPRESIONES ARITMÉTICAS 75
• 2 * (int)2.5 ⇔ 2 * 2
• (int)-3.14 * (int)5.5 ⇔ -3 * 5
! : Operador ¬ de la negación.
!α ⇔ ¬α
|| : Operador ∨ de la disyunción.
α || β ⇔ α ∨ β
α == β ⇔ α = β
α != β ⇔ α ≠ β
> : Mayor que, devuelve V si el primer operador es estrictamente mayor que el segundo.
α > β⇔α>β
< : Menor que, devuelve V si el primer operador es estrictamente menor que el segundo.
α < β⇔α<β
76 CAPÍTULO 5. INTRODUCCIÓN A LOS LENGUAJES DE PROGRAMACIÓN
>= : Mayor o igual, devuelve V si el primer operador es mayor o igual que el segundo.
α >= β ⇔ α ≥ β
<= : Menor igual, devuelve V si el primer operador es menor o igual que el segundo.
α <= β ⇔ α ≤ β
(0 < a <= 1)
0
−5 −4 −3 −2 −1 0 1 2 3 4 5
−1
−2
!(a >= -2 && a < 3.5 && b > -1.25 && b <= 1.5) || (a * a + b * b <= 1)
42 / 6 + 7 * 3 - 39
5.3. OPERADORES Y EXPRESIONES ARITMÉTICAS 77
Operador(es) Prioridad
() 1
++(postincremento) --(postdecremento) 2
! -(signo menos) +(signo más)
3
++(preincremento) --(predecremento)
* / % 4
+ - 5
< > <= >= 6
== != 7
&& 8
|| 9
= += -= *= /= %= 10
Tabla 5.1. Precedencia de los operadores en C++.
i) (42/6) + 7 ∗ 3 − 39 (/ prioridad 4)
42 / 6 + 7 ∗ 3 − 39 = 7 + 7 ∗ 3 − 39
= 7 + 21 − 39
= 28 − 39
= −11
Obsérvese la diferencia entre este ejemplo y siguiente ejemplo (¡de la vida real!), donde la
diferencia de los resultados está dada por la prioridad con la cual se evalúan los operadores.
Ejemplo. Cuál será la forma correcta de escribir en C++ o Java la operación que aparece
como miembro izquierdo de la igualdad que se muestra en la siguiente imagen, de tal
manera que se obtenga como resultado de la evaluación el número que aparece como
miembro derecho de la igualdad
78 CAPÍTULO 5. INTRODUCCIÓN A LOS LENGUAJES DE PROGRAMACIÓN
(((42 / 6) + 7) * 3) - 39
12.0 * 3 - -4.0 + 8 / 2 % 3
(-2 + 5 % 3 * 4) / 4 + 2
i) ((−2) + 5 % 3 ∗ 4) / 4 + 2 (− prioridad 3)
5.4. EVALUACIÓN SECUENCIAL DE EXPRESIONES 79
(−2 + 5 % 3 ∗ 4) / 4 + 2 = ((−2) + 5 % 3 ∗ 4) / 4 + 2
= ((−2) + 2 ∗ 4) / 4 + 2
= ((−2) + 8) / 4 + 2
= (6) / 4 + 2
=6 / 4+2
=1+2
=3
x = 3, y=4 y z = −2
x = y + z - 2;
x = x + 3 - 2 * y
cuando x = 3 y y = 5.
Para entender como se realiza la asignación es útil subindizar las variables teniendo en
cuenta el instante de tiempo en el cual se esta leyendo o modificando la memoria. Con
base en lo anterior, la expresión se reescribe de la siguiente manera
xt + 1 = xt + 3 − 2 ∗ yt
x = x + 3 - 2 * y
5.4. EVALUACIÓN SECUENCIAL DE EXPRESIONES 81
cuando x = 3 y y = 5.
t x y
0 3 5
1 −4 5
Ejemplo. Supónga que se desea ejecutar la siguiente secuencia de instrucciones
i = k + 1;
j = 2 * k;
i = i * k * j;
j = j * k - i;
t k i j
0 1 — —
1 1 2 —
2 1 2 2
3 1 4 2
4 1 4 −2
82 CAPÍTULO 5. INTRODUCCIÓN A LOS LENGUAJES DE PROGRAMACIÓN
5.5. Ejercicios
p || q && r
2. Escribir en C++, en una lı́nea, una asignación a una variable real F que almacene el
valor del módulo de la fuerza con que se atraen o se repelen dos cargas Q1 y Q2 que
se encuentran separadas una distancia r. El módulo de la fuerza se puede calcular
utilizando la ley de Coulomb que está dada por la expresión
Q1 Q2
F =κ
r2
donde κ se denomina constante eléctrica del medio y está dada por la Constante de
Coulomb que en el vacio es igual a
N m2
κ = 9 × 10−9 .
C2
suponiendo que las variables involucradas han sido creadas e inicializadas previa-
mente.
-b + b * b % 3 - 4 * a * c / 2 * a
(int)(b * c) % a * -b / c + d - a % d
int s = 0;
int i = 0;
s += i;
i++;
s += i;
i++;
s += i;
i++;
s += i;
i++;
s += i;
i++;
s += i;
i++;
s += i;
¿Si se repiten las dos últimas instrucciones de forma continua, cuál es la expresión
(dependiente de i) que se desea calcular?.
int p = 1;
int b = 2;
int t;
t = p;
p *= b;
t += p;
p *= b;
t += p;
p *= b;
t += p;
p *= b;
t += p;
p *= b;
t += p;
¿Si se repiten las dos últimas instrucciones de forma continua, cuáles son las expre-
siones que se desean calcular con las variable p y t?.
84 CAPÍTULO 5. INTRODUCCIÓN A LOS LENGUAJES DE PROGRAMACIÓN
Capı́tulo 6
Relaciones y funciones
6.1. Relaciones
Una relación R de A en B es un subconjunto del producto cartesiano A × B, es decir,
R se dice relación si R ⊆ A × B. Al conjunto A se le denomina conjunto de salida y al
conjunto B se le denomina conjunto de llegada.
Ejemplo. Sean A = {0, 1, 2} y B = {¨, ©, ª, «}, una de la posibles relaciones que se pueden
definir es R = {(0, ¨), (0, «), (2, «), (2, ©)}, el cual es un subconjunto de parejas ordenadas
pertenecientes al producto cartesiano entre A y B.
Ejemplo. Sean A = {0, 1, 2} y B = {¨, ©, ª, «}, dos conjuntos y sea R = {(0, ¨), (0, «), (2, «), (2, ©)},
una relación definida de A en B, el conjunto DomR = {0, 2} es el dominio de la relación y
los elementos 0 y 2 son las preimágenes de la relación R.
Ejemplo. Sean A = {0, 1, 2} y B = {¨, ©, ª, «} dos conjuntos y sea R = {(0, ¨), (0, «), (2, «), (2, ©)}
una relación definida de A en B, el conjunto RanR = {¨, ©, «} es el rango de la relación y
los elementos ¨, © y « son las imágenes de la relación R.
a R b ⇔ (a, b) ∈ R
R
A B
¨
0
©
1
ª
2
«
Figura 6.1. Representación de la relación R = {(0, ¨), (0, «), (2, «), (2, ©)} mediante diagramas
Sagitales.
Hay relaciones que se pueden establecer entre elementos del mismo conjunto, es decir,
una relación que cumpla que R ⊆ A × A
Ejemplo. Si se tiene el conjunto A = {¨, ©, ª, «}, se puede construir la relación R =
{(¨, ©), (©, ¨), (ª, «), («, ª)}. En la figura 6.2 se muestra una representación de esta
relación.
6.1. RELACIONES 87
R
A A
¨ ¨
© ©
ª ª
« «
Figura 6.2. Representación de la relación R = {(¨, ©), (©, ¨), (ª, «), («, ª)} mediante diagra-
mas Sagitales.
Una de las caracterı́sticas más importantes e interesantes que poseen las relaciones que
están definidas sobre el mismo conjunto, son las propiedades que pueden cumplir; las cuales
permiten definir los conceptos de relaciones de orden y de equivalencia entre los elementos
de un conjunto. Dichas propiedades son las siguientes:
Ejemplo. Dada la relación R = {(0, 0), (0, 1), (1, 1), (1, 2), (2, 2)} construida sobre el mis-
mo conjunto A = {0, 1, 2} se puede afirmar que
• La relación R es reflexiva pues están todas las parejas de los elementos vinculados
consigo mismos (0, 0), (1, 1) y (2, 2).
Ejemplo. Dada la relación R = {(0, 0), (0, 1), (1, 1), (1, 2), (2, 2)} construida sobre el mis-
mo conjunto A = {0, 1, 2} se puede afirmar que
• La relación R no es simétrica pues está la pareja (0, 1) pero no está la pareja (1, 0).
En este caso es suficiente con un caso que no se de para decir que una relación no
cumple la propiedad.
Ejemplo. Dada la relación R = {(0, 0), (0, 1), (1, 1), (1, 2), (2, 2)} construida sobre el mis-
mo conjunto A = {0, 1, 2} se puede afirmar que
• La relación R es antisimétrica pues cumple con la definición, ya que las tres parejas
(0, 0), (1, 1) y (2, 2) son de la forma (a, a) que cumplen con la definición, y para las
otras parejas (0, 1) y (1, 2) no están presentes las parejas (1, 0) o (2, 1), por lo que
también se cumplen con la definición de antisimetrı́a.
Ejemplo. Dada la relación R = {(0, 0), (0, 1), (1, 1), (1, 2), (2, 2)} construida sobre el mis-
mo conjunto A = {0, 1, 2} se puede afirmar que
• La relación R no es transitiva pues están las parejas (0, 1) y (1, 2), pero no está la
pareja (0, 2).
El hecho de que una relación no sea simétrica no quiere decir que la relación sea anti-
simétrica y viceversa.
Ejemplo. Si se tiene el conjunto A = {0, 1, 2}, y sobre éste se define la relación R =
{(0, 0), (0, 1), (1, 0), (1, 2), (2, 2)}, se tiene que la relación no es simétrica pues la pareja
(1, 2) está, pero la pareja (2, 1) no está, ni es antisimétrica pues las parejas (0, 1) y (1, 0)
están, y es sabido que 1 ≠ 0.
Ejemplo. Si se tiene el conjunto A = {0, 1, 2}, y sobre éste se define la relación R =
{(0, 0), (1, 1), (2, 2)}, se tiene que la relación es tanto simétrica como antisimétrica. ¿Por
qué?.
Una relación R definida sobre el mismo conjunto, se dice que es una relación de orden 1 ,
si y sólo si, es reflexiva, antisimétrica y transitiva. Una relación de orden se suele notar
con el sı́mbolo ≤A .
Ejemplo. Si se tiene el conjunto A = {0, 1, 2}, y la relación R = {(0, 1), (0, 2), (0, 0), (1, 1), (1, 2), (2, 2)}
esta es una relación de orden, pues es reflexiva, antisimétrica y transitiva.
1
También se suele denominar relación de orden parcial.
6.1. RELACIONES 89
0 1 2
Una relación de orden total, es una relación de orden donde para todo a, b ∈ A se cumple
al menos una de las desigualdades a ≤A b o b ≤A a.
Una relación R se dice que es una relación de equivalencia, si y sólo si, es reflexiva,
simétrica y transitiva. El sı́mbolo utilizado para decir que una relación es equivalente es
≡A .
Dado el conjunto A = {0, 1, 2} y una relación R definida sobre A de la siguiente ma-
nera R = {(0, 0), (0, 1), (1, 0), (1, 1), (2, 2)}, se puede observar que R es una relación de
equivalencia, pues:
Las relaciones de equivalencia tienen una particular caracterı́stica, es que los elementos
que están relacionados se pueden interpretar como que representan el mismo objeto. Ası́,
una relación de equivalencia define una partición del conjunto en grupos de conjuntos con
propiedades similares; tales como que no son vacı́os, que no tienen elementos en común, y
que la unión de todos los grupos es el conjunto inicial. A estos grupos se les conoce como
clases de equivalencia.
Ejemplo. Para el conjunto A = {0, 1, 2} y la relación de equivalencia definida sobre el
mismo conjunto R = {(0, 0), (0, 1), (1, 0), (1, 1), (2, 2)}, aquı́ se observa que se pueden for-
mar los grupos {0, 1} y {2}, los cuales son una partición del conjunto A y que definen dos
90 CAPÍTULO 6. RELACIONES Y FUNCIONES
clases de equivalencia. Obsérvese que los valores 0 y 1, resultan ser equivalentes, es decir,
que representan el mismo objeto.
0 1 2
f (x) = y
para expresar que (x, y) ∈ f . Cuando se desea especificar tanto el conjunto de salida como
el conjunto de llegada se usa la notación dominio–rango
f ∶A→B
x ↦ f (x)
Las funciones también poseen propiedades muy interesantes, ası́ como las de las rela-
ciones de un conjunto en si mismo, las más importantes de estas son:
6.2. FUNCIÓN PARCIAL 91
f
A B
0 ¨
1
©
2
3 ª
4 «
Figura 6.3. Representación de la función f = {(0, ©), (1, ©), (4, ª)} mediante diagramas Sagi-
tales.
f′
A B
¨
0
©
1
ª
2
«
Figura 6.4. Representación de la relación f ′ = {(0, ¨), (1, ¨), (2, ª), (1, «)} mediante diagra-
mas Sagitales.
f
A B
¨
0
©
1
ª
2
«
Figura 6.5. Representación de la función inyectiva f = {(0, «), (2, ¨)} mediante diagramas
Sagitales.
f
A B
0 ¨
1
©
2
3 ª
4 «
Figura 6.6. Representación de la función sobreyectiva f = {(0, ¨), (1, ª), (2, «), (4, ¨)} me-
diante diagramas Sagitales.
f
A B
0 ¨
1
©
2
3 ª
4 «
Figura 6.7. Representación de la función total f = {(0, «), (1, ©), (2, ¨), (3, «), (4, ¨)} median-
te diagramas Sagitales.
f
A B
0 ¨
1 ©
2 ª
3 «
Figura 6.8. Representación de la función biyectiva f = {(0, ª), (1, ©), (2, «), (3, ¨)} mediante
diagramas Sagitales.
f
A B
0
¨
1
2
©
3 ª
4 «
94 CAPÍTULO 6. RELACIONES Y FUNCIONES
Una alternativa para obtener una función total a partir de una función parcial es la de
asignar los valores del conjunto de salida que no pertenecen al dominio a algún valor del
conjunto de llegada, como se muestra a continuación
f′
A B
0 ¨
1
©
2
3 ª
4 «
f′
A B
0 ¨
1 ©
2 ª
3 «
4
div ∶ R × R → R
x
(x, y) ↦ ,
y
se tiene que si la segunda proyección de la pareja del dominio (x, y) es igual a 0, entonces
la función se encuentra indefinida, por lo tanto la función no es total.
Para hallar una función que contenga la anterior y que sea total, se adicional el sı́mbolo
al conjunto de llegada y se extiende la función de la siguiente manera
div ∶ R × R → R ∪ {}
⎧
⎪
⎪, si y = 0;
(x, y) ↦ ⎨ x
⎪
⎪
⎩ y , en otro caso.
6.4. FUNCIONES IMPORTANTES EN COMPUTACIÓN 95
idA ∶ A → A
x ↦ idA (x) = x
idA
A A
¨ ¨
© ©
ª ª
« «
Figura 6.9. Representación de la función identidad idA = {(¨, ¨), (©, ©), (ª, ª), («, «)} me-
diante diagramas Sagitales.
∣x∣ ∶ R → R0,+
⎧
⎪
⎪ x, si x ≥ 0;
x↦⎨
⎪
⎩−x, en otro caso.
⎪
Definición. Potencia
La función potencia de b elevado al exponente n se denota como bn y se define como:
bn ∶ R × Z → R ∪ {}
⎧
⎪ si (b ≠ 0) ∧ (n = 0);
⎪
⎪
⎪
1,
⎪
⎪
⎪
⎪
⎪ b ∗ b ∗ ⋯ ∗ b, si (b ≠ 0) ∧ (n ∈ Z+ );
⎪
⎪
⎪ ´¹¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¸¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹¶
⎪
⎪ n–veces
(b, n) ↦ ⎨ 1
⎪
⎪
⎪ , si (b ≠ 0) ∧ (n ∈ Z− );
⎪
⎪
⎪ b∣n∣
⎪
⎪
⎪ 0, si (b = 0) ∧ (n > 0);
⎪
⎪
⎪
⎪
⎩,
⎪ si (b = 0) ∧ (n ≤ 0).
96 CAPÍTULO 6. RELACIONES Y FUNCIONES
2
Ejemplos. 10 = 1, 20 = 1, 23 = 8, 3−2 = 19 , 0.53 = 0.125, ( 32 ) = 49 , 00 = , 0−1 = .
Definición. Raı́z cuadrada √
La función raı́z cuadrada de x se denota como x y se define como:
√
x ∶ R0,+ → R0,+
x ↦ b, donde b2 = x.
√ √ √ √ √ √ √
Ejemplos. 0 = 0, 1 = 1, 4 = 2, 9 = 3, 25 = 5, 0.25 = 0.5, 49 = 23 ,
√
2 ≈ 1.41421356237309504880168872420969807856967187537694807317667973799⋯.
√ √
En programación se define que x1/2 = x y se puede demostrar que x2 = ∣x∣.
Definición. Logaritmo
La función logaritmo en base b de x se denota como logb x y se define como:
logb x ∶ R+ × R+ → R
(b, x) ↦ y, donde by = x.
Ejemplos. log2 4 = 2, log2 8 = 3, log2 1 = 0 (en general logb 1 = 0), loge e = 1 (en general
logb b = 1), log3 19 = −2, log0.5 0.125 = 3, log0.25 2 = − 12 .
Definición. Piso
La función piso de x se denota como ⌊x⌋ y se define como:
⌊x⌋ ∶ R → Z
x ↦ n, donde (n ∈ Z) ∧ (n ≤ x < n + 1).
f (x) = ⌊x⌋ 2
−4 −3 −2 −1 1 2 3 4
−1
−2
−3
Ejemplos. ⌊−3.141516⌋ = −4, ⌊−3⌋ = −3, ⌊−1.5⌋ = −2, ⌊−0.1⌋ = −1, ⌊0⌋ = 0, ⌊0.1⌋ = 0,
⌊1.5⌋ = 1, ⌊3⌋ = 3, ⌊3.141516⌋ = 3, ⌊1.3⌋ = 1.
6.4. FUNCIONES IMPORTANTES EN COMPUTACIÓN 97
Definición. Techo
La función techo de x se denota como ⌈x⌉ y se define como:
⌈x⌉ ∶ R → Z
x ↦ n, donde (n ∈ Z) ∧ (n − 1 < x ≤ n).
f (x) = ⌈x⌉ 2
−4 −3 −2 −1 1 2 3 4
−1
−2
−3
Ejemplos. ⌈−3.141516⌉ = −3, ⌈−3⌉ = −3, ⌈−1.5⌉ = −1, ⌈−0.1⌉ = 0, ⌈0⌉ = 0, ⌈0.1⌉ = 1, ⌈1.5⌉ = 2,
⌈3⌉ = 3, ⌈3.141516⌉ = 4, ⌈1.3⌉ = 2.
Definición. Truncamiento
La función truncamiento de x se denota como trunc(x) y se define como:
trunc(x) ∶ R → Z
⎧
⎪
⎪⌊x⌋, si x ≥ 0;
x↦⎨
⎪
⎩⌈x⌉,
⎪ si x < 0.
a partir de la definición anterior se tiene que en C++ se cumple que (int)x = trunc(x).
98 CAPÍTULO 6. RELACIONES Y FUNCIONES
f (x) = trunc(x) 2
−4 −3 −2 −1 1 2 3 4
−1
−2
−3
frac(x) ∶ R → [0, 1)
x ↦ ∣x∣ − ⌊∣x∣⌋.
−4 −3 −2 −1 1 2 3 4
f (x) = frac(x) −1
Definición. Redondeo
La función redondeo de x se denota como round(x), retorna el entero más próximo al
número x. Para los reales no negativos retorna el techo si la parte fraccionaria es mayor o
igual a 0.5, retorna el piso si la parte fraccionaria es menor a 0.5. Para los reales negativos
retorna el piso si la parte fraccionaria es mayor o igual a 0.5, retorna el techo si la parte
fraccionaria es menor a 0.5. Formalmente esto se define como:
6.5. COMPOSICIÓN DE FUNCIONES 99
round(x) ∶ R → Z
⎧
⎪ ⌈x⌉, si (x ≥ 0) ∧ ( frac(x) ≥ 0.5);
⎪
⎪
⎪
x ↦ ⎨⌊x⌋, si (x ≥ 0) ∧ ( frac(x) < 0.5);
⎪
⎪
⎪
⎪
⎩− round(−x), si x < 0.
f (x) = round(x) 2
−1
−2
−3
Contexto en matemáticas:
[x] = ⌊x⌋
Contexto en computación:
f ○g ∶A→C
a z→ f (g(a))
100 CAPÍTULO 6. RELACIONES Y FUNCIONES
Una representación que permite entender mejor como opera ésta nueva función, es
utilizando un diagrama conmutativo, como se muestra a continuación:
g
A B
f
f ○g
g f
A B C
1 ¨ a
2 ©
3 b
4 ª
c
5 «
6 _ d
f ○g
f ○g
A C
1 a
2
3 b
4 c
5
6 d
Figura 6.11. Representación mediante diagramas de la función f ○ g =
{(1, a), (2, d), (3, c), (4, c), (6, c)}.
6.5. COMPOSICIÓN DE FUNCIONES 101
g∶R→Z f ∶Z→Z
x ↦ ⌊x⌋ n↦n∗n
f ○g ∶R→Z
x ↦ f (g(x)) = f (⌊x⌋) = ⌊x⌋ ∗ ⌊x⌋
Ejemplo. Al calentar (△) clorato de potasio (KClO3 ) se produce cloruro de potasio (KCl)
y oxı́geno (O2 ), de acuerdo con la siguiente ecuación quı́mica
Solución. Con base en la información de los pesos atómicos del potasio, el cloro y el
oxı́geno, suministrados en la tabla 6.1, se pueden construir una serie de funciones que
permiten calcular la masa de O2 desconocida.
Elemento K Cl O
Peso atómico 39 35 16
Tabla 6.1. Pesos atómicos del Potasio (K), el Cloro (Cl) y el Oxı́geno (O).
Lo primero que se debe tener en cuenta es que la a partir de la masa del KClO3 no
se puede obtener directamente la masa del O2 , para esto debemos realizar los siguientes
pasos:
i. Dada la masa del KClO3 encontrar su equivalente pero en unidades de moles, lo que
se representará de la siguiente manera,
ii. Dado el número de moles con respecto a la masa original del KClO3 , se encuentra su
equivalente en unidades de moles O2 , lo que se representará de la siguiente manera,
102 CAPÍTULO 6. RELACIONES Y FUNCIONES
iii. Dado el número de moles de O2 con respecto a la masa original del KClO3 , se encuentra
la masa equivalente del O2 , lo que se representará de la siguiente manera,
En primera instancia se debe calcular la masa molar de cada sustancia que interviene
en la reacción, ası́ como se muestra a continuación:
• A partir de la tabla 6.1 se puede calcular el Peso Molar (PM) del clorato de potasio
(KClO3 ) de la siguiente manera:
de donde se obtiene que una mol (n) de KClO3 tiene un peso molar de 122g, es decir
1n
que están a razón de 1n ∶ 122g o lo que es lo mismo .
122g
• A partir de la tabla 6.1 se puede calcular el Peso Molar (PM) del oxı́geno (O2 ) de la
siguiente manera:
de donde se obtiene que una mol (n) de O2 tiene un peso molar de 32g, es decir que
1n
están a razón de 1n ∶ 32g o lo que es lo mismo .
32g
i. Para una masa x en gramos de KClO3 con respecto al número de moles f (x) del
KClO3 , éstas cantidades están en la misma proposición directa de la razón 122 ∶ 1, es
x 122 f (x) 1
decir, = , que es equivalente a la proporción = , lo cual se puede
f (x) 1 x 122
modelar mediante la función
f ∶ R0,+ → R0,+
x
x ↦ f (x) = .
122
ii. A partir de la ecuación (6.1) se tiene que dos (2) moles de KClO3 al calentarse producen
dos (2) moles de KCl y tres (3) moles de O2 , de lo cual se obtiene que la razón entre
el número de moles x de KClO3 y el número g(x) de moles de O2 están en la misma
x 2
proporción directa de la razón 2 ∶ 3, es decir, = , que es equivalente a la
g(x) 3
g(x) 3
proporción = , lo cual se puede modelar mediante la función
x 2
g ∶ R0,+ → R0,+
3
x ↦ g(x) = x.
2
iii. Para un número de moles x de O2 con respecto a la masa h(x) del O2 en gramos,
éstas cantidades están en la misma proposición directa de la razón 1 ∶ 32, es decir,
x 1 h(x)
= , que es equivalente a la proporción = 32, lo cual se puede modelar
h(x) 32 x
mediante la función
h ∶ R0,+ → R0,+
x ↦ h(x) = 32x.
iv. Como a partir de la masa del KClO3 no se puede obtener la masa del O2 directamente,
se pueden utilizar las funciones anteriormente descritas y la operación de composición
entre funciones para poder encontrar la equivalencia entre estas masas haciendo uso
de un diagrama conmutativo, como el que se presenta a continuación
f h
h○g○f
masa KClO3 masa O2
f h
ası́ que para hallar la masa del O2 a partir de la masa del KClO3 se puede utilizar la
función
v. Para el caso de calentar 10g de KClO3 , la masa de O2 que se obtiene se puede calcular
mediante el uso de la función (h ○ g ○ f )(x) ası́
24 240
(h ○ g ○ f )(10) = ⋅ 10 = = 3.93443
61 61
en conclusión, la masa de O2 en gramos que se puede obtener a partir de calentar 10g
de KClO3 es 3.93443g de O2 .
i = k + 1;
j = 2 * k;
i = i * k * j;
j = j * k - i;
i = +(k, 1)
j = ∗(2, k)
i = ∗( ∗ (i, k), j) = ∗( ∗ ( + (k, 1), k), ∗(2, k))
j = −( ∗ (j, k), i) = −( ∗ ( ∗ (2, k), k), ∗( ∗ ( + (k, 1), k), ∗(2, k)))
6.6. Ejercicios
5. Dado A un conjunto finito tal que ∣A∣ = n. ¿Cuántas relaciones sobre el mismo
conjunto de A existen?.
i. R1 = {(l, l), (l, n), (n, l), (n, n), (s, u), (u, l), (u, u)}
ii. R2 = {(l, l), (l, n), (n, l)}
iii. R3 = {(l, l), (l, n), (l, u), (n, l),
(n, n), (s, s), (u, l), (u, u)}
iv. R4 = {(n, l), (s, l), (s, n), (u, l), (u, n), (u, s)}
v. R5 = {(l, l), (l, n), (l, s), (l, u), (n, n), (n, s),
(n, u), (s, s), (s, u), (u, u)}
vi. R6 = {(s, u)}
8. De las relaciones del numeral 6. ¿Cuáles son reflexivas?, ¿Cuáles son irreflexivas?,
¿Cuáles son simétricas?, ¿Cuáles son antisimétricas?, ¿Cuáles son transitivas?.
9. De las relaciones del numeral 6. ¿Cuáles son una relación de orden?, ¿Cuáles son una
relación de equivalencia?.
10. Sea A un conjunto finito tal que ∣A∣ = n. ¿Cuántas relaciones sobre el mismo conjunto
A existen que sean reflexivas?
11. Sea A un conjunto finito tal que ∣A∣ = n. ¿Cuántas relaciones sobre el mismo conjunto
A existen que sean irreflexivas?
12. Sea R una relación sobre el conjunto P de todas las palabras sobre un alfabeto,
definida por
13. Sea R una relación sobre el conjunto P de todos los nombres de personas, definida
por
14. Sea R una relación sobre el conjunto P de todas las personas, definida por
15. Sea R una relación sobre el conjunto P de todas las personas, definida por
x R y ⇔ “x y y viven en Colombia”
16. Sea R una relación sobre el conjunto P de todas las personas, definida por
17. Sea R una relación sobre el conjunto P de todas las personas, definida por
Determine si la anterior relación R ¿es una relación de equivalencia?, ¿es una relación
de preorden?, ¿es una relación de orden?.
18. Sea R una relación sobre el conjunto de los números reales R, definida por
a R b ⇔ (a = b) ∨ (a = −b)
m R n ⇔ m2 = n2
m R n ⇔ m2 − n2 es un múltiplo de 3
108 CAPÍTULO 6. RELACIONES Y FUNCIONES
31. De las funciones definidas en el numeral 30. ¿Cuáles son inyectivas?, ¿cuáles son
sobreyectivas?, ¿cuáles son totales?, ¿cuáles son biyecciones?.
i. f1 (x) = x v. f5 (x) = ±x
ii. f2 (x) = x2 vi. f6 (x) = 1/x
√
iii. f3 (x) = x vii. f7 (x) = 1/x2
iv. f4 (x) = ∣x∣ viii. f8 (x) = log2 x
33. De las relaciones definidas en el numeral 32. ¿Cuál es el dominio?, ¿Cuál es el rango?.
34. De las relaciones definidas en el numeral 32 que son funciones. ¿Cuáles son inyecti-
vas?, ¿cuáles son sobreyectivas?, ¿cuáles son totales?, ¿cuáles son biyecciones?.
35. Con respecto al último problema de la sección 6.5, luego de hacer reaccionar 10g de
KClO3 . ¿Cuántos gramos de cloruro de potasio (KCl) se pueden obtener usando la
metodologı́a presentada en el ejemplo?, Comprobar el resultado obtenido aplicando
la ley de conservación de la materia.
110 CAPÍTULO 6. RELACIONES Y FUNCIONES
Capı́tulo 7
Funciones en programación y la estructura
condicional
f ∶R→R
(x) ↦ x2
f = {(x, x2 ) ∶ (x ∈ R)}.
• Primero se escribe el tipo de retorno (rango). Como es real, el tipo de dato es double.
double
double f
• Entre paréntesis se coloca el tipo y la variable de las variables del dominio. En este
caso solamente se tiene la variable x quedando double x y se coloca una llave abierta
{.
• En las siguientes lı́neas se escribe la definición de la función entre las llaves termi-
nando con punto y coma ; cada linea de la función. Dicha definición de función
corresponde al algoritmo ó computo, para generar la imagen calculada de la función
se utiliza la palabra clave return, de la siguiente manera
Otra posible definición de la función podrı́a escribirse almacenando el valor del producto
x * x en una variable de tipo double y retornándolo ası́:
f (x) = y
area circulo ∶ R → R
(r) ↦ 3.14159265 ∗ r ∗ r
Nótese que para definir el valor π se tomó como aproximación el valor 3.14159265. En
vez de elevar el valor del radio al cuadrado se tomó la multiplicación de r ∗ r ya que la
potencia no es una operación matemática básica. En la sección de recursividad se definirá
potencia como una función.
Esta función se traduce al lenguaje C++ paso a paso de la siguiente forma:
• Primero se escribe el tipo de retorno en este caso el conjunto que corresponde al tipo
de dato del área del cı́rculo, como es real el tipo de dato es double.
double
double area_circulo
• Entre paréntesis se coloca el tipo y la variable de las variables del dominio. En este
caso solamente se tiene la variable r de tipo double r y se coloca una llave abierta
{.
• En las siguientes lı́neas se escribe el cálculo del área del cı́rculo y se retorna el valor
calculado.
114 CAPÍTULO 7. FUNCIONES EN PROGRAMACIÓN Y LA ESTRUCTURA CONDICIONAL
Otra posible definición de la función podrı́a escribirse almacenando el valor del área del
cı́rculo en una variable de tipo double y retornándolo ası́:
#include<iostream>
#include<cstdlib>
/*
En esta parte se definen las funciones
*/
int main(){
/*
En esta parte se realiza la lectura de datos,
y los llamados a las funciones
*/
cout << endl;
system("pause"); //windows
return EXIT_SUCCESS;
};
Para el caso del área del cı́rculo, el archivo fuente en C++ serı́a el siguiente, en el cual
se han separado el encabezado del archivo, la función del cálculo del área y la función
principal
#include<iostream>
#include<cstdlib>
int main(){
double radio;
cout << "radio del circulo? = ";
cin >> radio;
cout << "El area del circulo es: ";
cout << area_circulo(radio);
cout << endl;
system("pause"); //windows
return EXIT_SUCCESS;
};
116 CAPÍTULO 7. FUNCIONES EN PROGRAMACIÓN Y LA ESTRUCTURA CONDICIONAL
Como se aprecia en el programa anterior, se utilizan las funciones cin y cout que perte-
necen a la librerı́a de entrada y salida de flujos de datos iostream. Las dos primeras lı́neas
de código permiten al compilador incluir las definiciones de estas funciones en el programa
principal. La función cout lo que hace es mostrar una cadena de caracteres (texto) en la
consola. La instrucción cout << endl, hace que se oblige a generar una nueva lı́nea en la
consola. La función cin lo que hace es asignar el valor que sea digitado en la consola a la
variable de la parte de la izquierda del operador <<. En la instrucción cin >> radio; se
asigna a la variable radio el valor digitado por el usuario. system("pause") lo que hace
es ejecutar el comando pause de Windows que permite pedirle al usuario que presione una
tecla para continuar la ejecución del programa o en este caso por estar antes del retorno
o fin de la función principal para salir de él devolviendo al sistema operativo un valor de
EXIT_SUCCESS para indicar que ejecución del programa fue satisfactoria, es decir, que en
este caso el programa se ejecutó correctamente.
El programa anterior pide al usuario digitar el radio del cı́rculo y almacena el valor de
la lectura en la variable radio. Posteriormente despliega un mensaje y se realiza el llamado
a la función area_circulo. Nótese que los nombres de variables (en este caso radio) en
el programa principal no necesariamente deben coincidir con los de la declaración de la
función (en este caso la función recibe un valor de tipo double llamado r), sin embargo
se debe notar que su tipo de dato sı́ debe ser el mismo.
area rectangulo ∶ R × R → R.
Para el calculo del área de un rectángulo es necesario conocer el largo y el ancho del
rectángulo, a partir de los cuales el área del rectángulo está dada por la expresión Ar = l∗a,
donde las variables están definidas ası́:
area rectangulo ∶ R × R → R
(l, a) ↦ l ∗ a
• Primero se escribe el tipo de retorno en este caso el conjunto que corresponde al tipo
de dato del área del rectángulo, como es real el tipo de dato es double.
double
double area_rectangulo
• En las siguientes lı́neas se escribe el cálculo del área del rectángulo, se retorna el
valor calculado y se cierra la definición de la función.
#include<iostream>
#include<cstdlib>
int main(){
double largo;
double ancho;
cout << "largo? = ";
cin >> largo;
cout << "ancho? = ";
cin >> ancho;
cout << "El area del rectangulo es: ";
cout << area_rectangulo(largo, ancho);
cout << endl;
system("pause");
return EXIT_SUCCESS;
};
r r
b2
a2
b1
a1
r2
r1
Es posible tener programas en los que se deban cubrir diferentes casos, para los cuales
se deberán retornar diferentes valores dadas unas condiciones.
<bloque_prev>
V F
<cond>
<bloque_V> <bloque_F>
<bloque_sigui>
<bloque_prev>
if(<cond>){
<bloque_V>
}else{
<bloque_F>
};
<bloque_sigui>
valor absoluto ∶ R → R
⎧
⎪
⎪ x, si x ≥ 0;
(x) ↦ ⎨
⎪
⎩−x, en otro caso.
⎪
double valor;
V F
x >= 0
return valor;
#include<iostream>
#include<cstdlib>
int main(){
double x;
cout << "x? = ";
cin >> x;
cout << "El valor absoluto es: ";
cout << valor_absoluto(x);
cout << endl;
system("pause");
return EXIT_SUCCESS;
};
Ejemplo. El máximo entre dos números Una función que permite determinar el máximo
de dos números reales, se puede definir como
aquı́ se tienen dos casos, si el número a es mayor que b el valor máximo es a; en otro caso
se debe retornar b. En notación matemática esto puede ser escrito de la siguiente forma
V F
a > b
return a; return b;
La regla de traducción de la función es similar a la anterior, sólo hay que tener en cuenta
la instrucción condicional, y que si no se cumple la condición especificada en el if, se
ejecutará el flujo de instrucciones especificado bajo el alcance de la instrucción else
if(<cond>){
<bloque_1>
}else{
<bloque_2>
};
Ejemplo. La siguiente función permite calcular el valor absoluto de un número real, pero
utilizando el operador condicional ?: en vez del condicional if presentado en un ejemplo
previo
Ejemplo. Una función equivalente a la anterior, que es más compacta y que también
permite calcular el valor absoluto, es la siguiente
<bloque_prev>
V
<cond>
<bloque>
<bloque_sigui>
124 CAPÍTULO 7. FUNCIONES EN PROGRAMACIÓN Y LA ESTRUCTURA CONDICIONAL
<bloque_prev>
if(<cond>){
<bloque>
};
<bloque_sigui>
V
x > 0.0
cout << x;
return x;
Una función en C++ que permite imprimir los números con signos es la siguiente
obsérvese como la ejecución del cuerpo del condicional no afecta las instrucciones que
siguen después del condicional.
7.4. LA ESTRUCTURA DE CONTROL CONDICIONAL SÍ-SINO (IF-ELSE) 125
se puede definir una función que permite calcular la operación condicional de un par de va-
riables booleanas y que retorna el resultado de operar los valores mediante un condicional,
de la siguiente manera
condicional ∶ B × B Ð→ B
aquı́ se tienen dos casos, primero, si el antecedente es verdadero y el consecuente es fal-
so, entonces el resultado de aplicar el condicional el falso, para cualquier otro caso el
condicional es verdadero. En notación matemática esto puede ser escrito de la siguiente
manera
condicional ∶ B × B → B
⎧
⎪
⎪F, si (ξ(p) = V ) ∧ (ξ(q) = F );
(p, q) ↦ ⎨
⎪
⎪
⎩V, en cualquier otro caso.
obsérvese que es posible construir una función que utilice sólo una estructura if sin la
sentencia else que es mucho más sencilla que la función presentada anteriormente,
en esta función se tiene en cuenta que si la premisa p tiene valor true, entonces el resultado
está dado por el valor de la conclusión q, y si el valor de p es false, entonces el condicional
tendrá como valor true.
Otra de las opciones para utilizar una estructura condicional es la de enlazar varias
estructuras condicionales, de tal manera que solamente se pueda ejecutar un grupo de ins-
trucciones dependiendo de cual de las opciones se evalúa verdadero. De la misma manera
que en el caso del condicional tradicional la parte alternativa del final es opcional.
<bloque_prev>
V <cond_1> F
<bloque_1> V <cond_2> F
<bloque_2> ⋯
V <cond_i> F
<bloque_i> ⋯
V <cond_n-1> F
<bloque_n-1> <bloque_n>
<bloque_sigui>
<bloque_prev>
if(<cond_1>){
<bloque_1>
}else if(<cond_2>){
<bloque_2>
}
...
}else if(<cond_i>){
<bloque_i>
}
...
}else if(<cond_n-1>){
<bloque_n-1>
}else{
<bloque_n>
};
<bloque_sigui>
Si ninguna <cond_i> se evalúa verdadero y la parte else existe al final de las estructuras
if enlazadas entonces se ejecutarán las instrucciones del <bloque_n>
Ejemplo. El descuento del dı́a
Una tienda tiene las siguientes promociones
entonces
128 CAPÍTULO 7. FUNCIONES EN PROGRAMACIÓN Y LA ESTRUCTURA CONDICIONAL
pago f inal ∶ N × R → R
⎧
⎪ n ∗ precio, n ≤ 5;
⎪
⎪
⎪
⎪
⎪
⎪n ∗ precio ∗ 0.95, 5 < n ≤ 10;
(n, precio) ↦ ⎨
⎪
⎪
⎪ n ∗ precio ∗ 0.90, 10 < n ≤ 20;
⎪
⎪
⎪
⎪
⎩n ∗ precio ∗ 0.80, en otro caso.
Cuando se tiene una instrucción if enlazada en la cual las condiciones consisten en com-
parar una misma variable con un grupos de valores enteros constantes de forma repetida,
como la que se presenta a continuación
7.4. LA ESTRUCTURA DE CONTROL CONDICIONAL SÍ-SINO (IF-ELSE) 129
if(<var_entera> == <num_1>){
<bloque_1>
}else if(<var_entera> == <num_2>){
<bloque_2>
}
...
}else if(<var_entera> == <num_i>){
<bloque_i>
}
...
}else if(<var_entera> == <num_n-1>){
<bloque_n-1>
}else{
<bloque_n>
};
en este caso se utiliza una instrucción switch, la cual sirve para abreviar una instrucción
if enlazada como la anterior. El aspecto general de una instrucción switch es la siguiente:
• Cada uno de los valores enteros constantes se trata como un caso, especificando la
palabra case seguido de la constante y terminando con : (dos puntos).
• Se termina con una instrucción break que obliga a que se deje de ejecutar la ins-
trucción switch.
switch(<var_entera>){
case <num_1>:
<bloque_1>
break;
case <num_2>:
<bloque_2>
break;
...
case <num_i>:
<bloque_i>
break;
...
case <num_n-1>:
<bloque_n-1>
break;
default:
<bloque_n>
break;
};
Hay que tener presente que todo carácter es representado por un número entero, por
eso es posible utilizar una variable de tipo carácter dentro de una instrucción switch. La
codificación de la anterior función matemática en C++ puede ser la siguiente.
7.4. LA ESTRUCTURA DE CONTROL CONDICIONAL SÍ-SINO (IF-ELSE) 131
Cuando en una instrucción switch varios casos se tratan de la misma forma, entonces
estos se pueden agrupar en uno o varios casos, como se muestra en el siguiente ejemplo.
Es usual que las instructiones que se ejecutan dentro de los casos de una instrucción
switch se retornen directamente cuando se calculen dentro de una función, para estos
casos, en vez de dejar de ejecutar el switch con un break, se puede retornar el valor
directamente mediante el uso de la instrucción return. Si se elije esta opción no se debe
utilizar la instrucción break. A continuación se muestra esta variación de la instrucción
switch.
Ejemplo. Detección de vocales minúsculas III
En este ejemplo se agruparon todos lo casos de las vocales en uno solo y se retornó
directamente el resultado de la evaluación de cada caso.
#include<iostream>
#include<cstdlib>
int main(){
double largo;
double ancho;
cout << "largo? = ";
cin >> largo;
if(largo < 0){
cout << "El largo no es valido";
cout << endl;
system("pause");
return EXIT_FAILURE;
};
cout << "ancho? = ";
cin >> ancho;
if(ancho < 0){
cout << "El ancho no es valido";
cout << endl;
system("pause");
return EXIT_FAILURE;
};
cout << "El area del rectangulo es: ";
cout << area_rectangulo(largo, ancho);
cout << endl;
system("pause");
return EXIT_SUCCESS;
};
7.6. EJERCICIOS 135
7.6. Ejercicios
1. Hacer un programa que dado el área del corral de unas gallinas y el número de
gallinas en el corral determine el área que le corresponde a cada gallina.
2. Construir una función que dados tres números reales calcule el máximo de los tres.
3. Dadas las longitudes de los dos brazos de una palanca y el peso puesto en el brazo
más largo de la palanca, calcular el peso que se puede poner en el brazo más corto
para que la palanca quede en equilibrio.
4. Dadas las longitudes de los dos brazos de una palanca y el peso puesto en el brazo
más corto de la palanca, calcular el peso que se puede poner en el brazo más largo
para que la palanca quede en equilibrio.
5. Dados los pesos que se pueden poner en cada uno de los lados de la palanca y la
longitud total de la palanca determinar la longitud del brazo mas largo para que la
palanca quede en equilibrio.
6. Dados los pesos que se pueden poner en cada uno de los lados de la palanca y la
longitud total de la palanca determinar la longitud del brazo mas corto para que la
palanca quede en equilibrio.
7. Para crear un litro del compuesto D, se requiere que su composición por partes esté
conformada de la siguiente manera, 5 partes deben ser del producto A, 8 partes
deben ser del producto B y 7 partes deben ser del producto C. Si se requiere crear
10 litros del compuesto D. ¿Cuántos litros del producto A se requieren?, ¿Cuántos
litros del producto B se requieren?, ¿Cuántos litros del producto C se requieren?.
8. Si se tienen x litros de A, y litros de B y z litros de C. ¿Cuántos litros del compuesto
D se pueden obtener?.
9. En la convención republicana, se reúnen 100 personas de las cuales x son mujeres
e y son hombres. Si en la convención se dispone de z mesas y se dispone que la
diferencia entre número de hombres y mujeres en cada mesa no debe superar 2.
¿Cuantas sillas para mujeres se deben poner por mesa?, ¿Cuantas sillas por hombre
se deben poner?. Si los votos de las mujeres valen 1.5 veces los votos del hombre.
¿Cuántas mujeres deberı́an estar en la convención para que el candidato sea elegido
por votos de solo mujeres? Si los votos de los hombres valen 1.5 veces los votos de
las mujeres. ¿Cuántas mujeres deberı́an estar en la convención para que el candidato
sea elegido por votos de solo mujeres?
10. Dado el centro y el radio de un cı́rculo, determinar si un punto pertenece o no al
cı́rculo.
11. Dadas tres longitudes positivas, determinar si con esas longitudes se puede construir
un triángulo.
12. Dado un carácter, utilizar una instrucción switch para determinar si el carácter es
un dı́gito o no.
136 CAPÍTULO 7. FUNCIONES EN PROGRAMACIÓN Y LA ESTRUCTURA CONDICIONAL
Capı́tulo 8
Flujos de entrada y salida
8.1. Definición
Un flujo es un objeto desde el cual se puede enviar o recibir información.
• Para el caso de una fuente de entrada de información, ésta puede ser enviada desde
el teclado o desde un archivo o desde una red local de comunicaciones o desde un
nodo de internet, entre otros.
• Para el caso de una fuente de salida de información, ésta tı́picamente es enviada a
la consola (pantalla) o a un archivo o una impresora u otro nodo de internet.
• Los archivos son ejemplos de flujos de doble dirección, generalmente se puede recibir
y se puede enviar información desde y hacia ellos.
En capı́tulos anteriores ya se habı́a hecho uso de los flujos; con el objeto cin se recibı́a
información desde el teclado y con el objeto cout se enviaba información a la consola de
salida en la pantalla. En este capitulo, además de estudiar los flujos cin y cout, se tratará el
tema de usar archivos como ejemplos de flujos de entrada y salida de información distintos
al teclado y la consola.
IOS ⊆ S
S
⊆
IOS
⊆ ⊆
IS OS
⊆ ∈ ⊆ ∈
IFS cin OFS cout
#include<iostream>
#include<cstdlib>
leer T ∶ IS → T
(is) ↦ a, donde a = leer(is)
T leer_T(istream& is){
T a;
is >> a;
return a;
};
La función leer(is) que en C++ se escribe como >>, ésta retorna el dato siguiente que
se encuentre almacenado en el flujo is.
Cuando un flujo se utiliza como parámetro, este se pasa por referencia, es decir, que
fı́sicamente no se pasa un valor como parámetro, como en el caso de los tipos primitivos,
sino que se pasa su dirección de memoria. Para pasar la dirección de memoria de un flujo
se coloca el sı́mbolo & inmediatamente después del tipo de flujo; como en el caso anterior
que se escribio istream&.
Ejemplo. En C++ para leer un dato de tipo entero desde un flujo se utiliza la siguiente
función
1 2
-5 -5
−5
a a
140 CAPÍTULO 8. FLUJOS DE ENTRADA Y SALIDA
−5
a
escribir T ∶ OS × T → OS
(os, a) ↦ os, donde escribir(os, a)
La función escribir(os, a) que en C++ se escribe como <<, ésta escribe en el flujo os el
dato a .
Ejemplo. En C++ para escribir un dato de tipo entero en un flujo se utiliza la siguiente
función
1 2
a a
−5 −5
−5
8.4. FLUJOS DE ENTRADA Y SALIDA DESDE Y HACIA ARCHIVOS 141
4
3
a
-5
−5
−5 -5
Ejemplo. Para utilizar las funciones anteriores, que leen desde el teclado y escriben en la
consola se pueden llamar de la siguiente forma
int main(){
cout << "Digite un entero: ";
int a = leer_int(cin);
cout << "El entero leido es: ";
escribir_int(cout, a);
cout << endl;
system("pause");
return EXIT_SUCCESS;
};
Digite un entero: -5
El entero leido es: -5
Presione una tecla para continuar . . .
#include<fstream>
con lo cual el encabezado de un archivo fuente de un programa en C++ que haga uso de
archivos como flujos tendrá el siguiente aspecto
#include<iostream>
#include<cstdlib>
#include<fstream>
Para declarar que un archivo f pertenece al flujo fuente de entrada IFS (f ∈ IFS),
en C++ se especifica que f pertenece al conjunto ifstream y se debe proporcionar la
ubicación del archivo en el computador donde se ejecute el programa, es necesario que el
archivo exista previamente.
Para crear un flujo de entrada en C++ y especificar la ruta de localización del archivo
que sirve de flujo de entrada se utiliza la siguiente sintaxis
ifstream f("<path>");
C:\\mis documentos\\archivo.txt
/home/user/archivo.txt
Para declarar que un archivo f pertenece al flujo de salida OFS (f ∈ OFS), en C++
se especifica que f pertenece al conjunto ofstream y se debe proporcionar la ubicación
del archivo en el computador donde se ejecute el programa, en este caso no es necesario
que el archivo exista previamente.
Para crear un flujo de salida en C++ y especificar la ruta de localización del archivo
que sirve de flujo de salida se utiliza la siguiente sintaxis
ofstream f("<path>");
Las reglas para la especificación de la ruta de localización son las mismas que se des-
cribieron para los archivos como flujos de entrada.
8.4. FLUJOS DE ENTRADA Y SALIDA DESDE Y HACIA ARCHIVOS 143
Un paso necesario cuando se utilizan archivos como flujos de entrada o salida es que es
necesario cerrar los archivos después de utilizarlos para evitar que al ser abiertos queden
bloqueados para ser usados por otras aplicaciones o que al escribir la información no se
escriba completamente en el archivo. Para hacer esto se llama la función close() con la
sintaxis
f.close();
Ejemplo. Suponga que se dispone del archivo de texto plano entrada.txt con las si-
guiente información
0
1
2
3
4
5
y se quieren leer algunos datos con el fin de copiar los primeros 4 enteros del archivo al
archivo salida.txt, esto se podrı́a hacer utilizando el siguiente programa
#include<iostream>
#include<cstdlib>
#include<fstream>
int main(){
ifstream ifs("entrada.txt");
ofstream ofs("salida.txt");
escribir_char(escribir_int(ofs, leer_int(ifs)), ’\t’);
escribir_char(escribir_int(ofs, leer_int(ifs)), ’\t’);
escribir_char(escribir_int(ofs, leer_int(ifs)), ’\t’);
escribir_int(ofs, leer_int(ifs));
ofs.close();
ifs.close();
cout << endl;
system("pause");
return EXIT_SUCCESS;
};
0 1 2 3
Esta declaración de flujo sobreescribe el archivo cada vez que se ejecuta el programa.
Nótese que cada dato con esta sintaxis se lee hasta encontrar uno de los siguientes carac-
teres especiales: ’\t’, ’\n’, ’ ’. En la tercera lı́nea de la función main se lee el entero 0,
éste se imprime en el flujo de salida y luego se imprime el carácter separador ’\t’, en la
cuarta y la quinta lı́nea se realizan idénticas operaciones con los enteros 1, 2, en la sexta
lı́nea se lee el entero 3 y se imprime en el flujo, pero sin un carácter separador ya que no
se imprimirán más sı́mbolos. A continuación se proceden a cerrar los flujos.
8.5. EJERCICIOS 145
8.5. Ejercicios
1. Modele mediante una función matemática y diseñe una función en C++ que permita
leer un dato de tipo real desde un flujo genérico.
2. Modele mediante una función matemática y diseñe una función en C++ que permita
escribir un dato de tipo real en un flujo genérico.
3. Escriba un programa en C++ que lea un dato de tipo real (p. ej. 3.14159265) desde
el flujo de datos suministrado por el teclado usando la función diseñada anteriormente
en el numeral 1 y que escriba el opuesto aditivo del número en la consola usando la
función diseñada anteriormente en el numeral 2 (p. ej. -3.14159265).
4. Escriba un programa en C++ que lea un dato de tipo real (p. ej. -3.14159265)
desde el flujo de datos suministrado por un archivo de entrada llamado "input.txt"
usando la función diseñada anteriormente en el numeral 1 y que escriba el opuesto
aditivo del número en un archivo de salida llamado "output.txt" usando la función
diseñada anteriormente en el numeral 2 (p. ej. 3.14159265).
5. Modele mediante una función matemática y diseñe una función en C++ que permita
leer un dato de tipo booleano desde un flujo genérico.
6. Modele mediante una función matemática y diseñe una función en C++ que permita
escribir un dato de tipo booleano en un flujo genérico.
7. Escriba un programa en C++ que lea un dato de tipo booleano (p. ej. 0) desde el
flujo de datos suministrado por el teclado usando la función diseñada anteriormente
en el numeral 5 y que escriba la negación del dato leı́do previamente en la consola
usando la función diseñada anteriormente en el numeral 6 (p. ej. 1).
8. Escriba un programa en C++ que lea un dato de tipo booleano (p. ej. 1) desde el
flujo de datos suministrado por un archivo de entrada llamado "input.txt" usando
la función diseñada anteriormente en el numeral 5 y que escriba la negación del dato
leı́do previamente en un archivo de salida llamado "output.txt" usando la función
diseñada anteriormente en el numeral 6 (p. ej. 0).
9. Diseñar y escribir un programa que lea los mismos números enteros del archivo del
ejemplo de la sección 8.4.4, que imprima el primer número en la consola, el segundo
en el archivo de salida, el tercero en la consola y el cuarto en el archivo de salida.
10. Diseñar y escribir un programa que lea los mismos números enteros del archivo del
ejemplo de la sección 8.4.4, que imprima el segundo y el tercero en el archivo de
salida.
11. Diseñar y escribir un programa que lea los mismos números enteros del archivo del
ejemplo de la sección 8.4.4, que imprima los primeros cuatro números tanto en un
archivo de salida como en la consola.
146 CAPÍTULO 8. FLUJOS DE ENTRADA Y SALIDA
12. Modele mediante una función matemática y diseñe una función en C++ que permita
leer un dato de tipo carácter desde un flujo genérico.
13. Modele mediante una función matemática y diseñe una función en C++ que permita
escribir un dato de tipo carácter en un flujo genérico.
14. Supóngase que se dispone de un archivo que contiene los siguientes caracteres sepa-
rados por el sı́mbolo ’\t’
a e i o u ⇔ a e i o u
Diseñar un programa en C++ que lea carácter por carácter desde el flujo de datos
suministrado por el archivo usando la función diseñada anteriormente en el nume-
ral 12, que almacene los carácteres en variables y que luego escriba los carácteres en
orden inverso en un archivo de salida usando la función diseñada anteriormente en
el numeral 13, es decir, el archivo de salida tendrá el siguiente aspecto
u o i e a ⇔ u o i e a
Capı́tulo 9
Funciones recursivas
9.1. Definición
Definición. En 1952 Stephen Kleene definió formalmente en [Kleene 1952] que una “fun-
ción parcial recursiva” de enteros no negativos es cualquier función f definida por un
sistema no contradictorio de ecuaciones de las cuales las partes derechas e izquierdas están
compuestas a partir de:
iii. La constante 0, y
Ejemplo. El siguiente es un sistema que define la función parcial recursiva f (x, y) que
permite computar el producto de x con y.
f (x, 0) = 0
f (x, s(y)) = g(f (x, y), x)
g(x, 0) = x
g(x, s(y)) = s(g(x, y))
Nótese que las ecuaciones podrı́an no determinar el valor de f para cada posible entrada,
y que en ese sentido la definición es lo que se definió como función parcial. Si el sistema
de ecuaciones determina el valor de f para cada entrada, entonces la definición es lo que
se definió como función total. Cuando se usa el término función recursiva, en este caso se
esta hablando de forma implı́cita de que la función recursiva es total.
147
148 CAPÍTULO 9. FUNCIONES RECURSIVAS
El conjunto de funciones que pueden ser definidas recursivamente en esta forma se sabe
que son equivalente a el conjunto de funciones computables por una máquina de Turing o
por medio del lambda calculo.
Ya que este libro es un texto introductorio a la programación, no se tratarán las funcio-
nes recursivas con todo su detalle formal ya que esto está mucho más allá del alcance de
este libro; en cambio se intentará caracterizar más concretamente las funciones recursivas
que usualmente son utilizadas a un nivel introductorio de la programación, mediante la
siguiente definición debilitada de función recursiva. Hay que tener en mente que no se
pretende que esta caracterización sea exhaustiva con respecto al conjunto de todas las
funciones recursivas.
bn = b ∗ b ∗ b ∗ ⋯ ∗ b ∗ b
´¹¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¸¹¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹¶
n–veces
si se usa la propiedad asociativa del producto de números reales, se tiene que
9.2. EJEMPLOS DE PROBLEMAS QUE PUEDEN RESOLVERSE RECURSIVAMENTE 149
bn = b ∗ b ∗ b ∗ ⋯ ∗ b ∗ b = (b ∗ b ∗ ⋯ ∗ b ∗ b) ∗ b
´¹¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¸¹¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹¶ ´¹¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¸¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¶
n–veces n−1–veces
lo que es equivalente a
bn = b ∗ b ∗ b ∗ ⋯ ∗ b ∗ b = (b ∗ b ∗ ⋯ ∗ b ∗ b) ∗ b = bn−1 ∗ b
´¹¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¸¹¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹¶ ´¹¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¸¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¶
n–veces n−1–veces
A partir de esta observación se puede dar una definición recursiva usando funciones.
La declaración de esta función junto con su cuerpo se hará de la siguiente manera
potencia(b, n) = p
b ∶= Base
n ∶= Exponente
p ∶= Potencia bn
entonces
potencia ∶ R × N → R
⎧
⎪
⎪1, si n = 0;
(b, n) ↦ ⎨
⎪
⎩potencia(b, n − 1) ∗ b, en otro caso.
⎪
#include<iostream>
#include<cstdlib>
int main(){
double b;
int n;
cout << "b? = ";
cin >> b;
cout << "n? = ";
cin >> n;
cout << "potencia(b,n) = ";
cout << potencia(b,n);
cout << "\n";
system("pause");
return EXIT_SUCCESS;
};
Para calcular la cantidad de dinero que hay que pagar al cabo de los 12 meses, es suficiente
con tener en cuenta que en el mes 12 se debe pagar lo que se debe en el mes 11 más los
intereses que se producen en ese mes, por ejemplo si pago(11) es el valor del pago en el
mes 11, entonces la cantidad de dinero que hay que pagar en el mes 12 es igual a
ahora para calcular el valor a pagar en el mes 11 se puede hacer un razonamiento similar,
y para todos los meses anteriores hasta el mes cero (0) se hace de manera similar, lo que
genera un esquema recursivo como el que se presenta a continuación
Ası́, si m = $1′ 000.000, i = 0.05 y n = 12, se tiene que el pago al cabo de los 12 meses será
de pago(12) = $1′ 795.856, 326.
A partir de las observaciones anteriores ya se puede construir la regla recursiva con la
que se puede calcular el interés compuesto mes vencido, y si se quiere una regla general
que se pueda utilizar con cualquier monto m, con un interés i, y al cabo de n periodos se
tiene la siguiente función recursiva de tres (3) parámetros
pago(m, i, n) = valor
entonces
cout.precision(10);
#include<iostream>
#include<cstdlib>
int main(){
cout.precision(10);
double m;
double i;
int n;
cout << "m? = ";
cin >> m;
cout << "i? = ";
cin >> i;
cout << "n? = ";
cin >> n;
cout << "pago(m,i,n) = ";
cout << pago(m,i,n);
cout << "\n";
system("pause");
return EXIT_SUCCESS;
};
Suponga que selecciona cuatro cartas distintas de una baraja de poker, que se van a
representar por los sı́mbolos
¨ © ª «
si con estas cartas se forma el conjunto cartas = {¨, ©, ª, «}. ¿De cuántas formas distintas
se pueden organizar las cartas?
Como se van a listar todas las formas posibles en que se pueden organizar las cartas, el
orden si importa. Una estrategia para encontrar el número de listas puede ser el siguiente:
1. Se selecciona una carta del conjunto cartas de forma arbitraria pero fija, por ejemplo
la carta ©.
2. Ya fijada la carta ©, el resto del trabajo consiste en hallar el número de formas dis-
tintas de organizar las cartas restantes, es decir, el conjunto cartas∖{©} = {¨, ª, «}.
©«ª¨
Como la selección de las cartas se hizo de forma arbitraria, entonces, para poder listar
todos los posibles ordenamientos, se tiene que el paso del numeral 1 se puede realizar
de cuatro formas. Por cada una de estas escogéncias se hace la selección de una carta
de un conjunto con un elemento menos, como ocurre en el paso del numeral 3; esto se
puede realizar de tres formas posibles. Por cada par de escogéncias se hace la selección de
una carta de un conjunto con dos elementos menos, como ocurre en el paso del numeral
5; esto se puede realizar de dos formas posibles. Por cada trı́o de escogéncias se hace la
selección de una carta de un conjunto con tres elementos menos. Para este caso el conjunto
restante tiene un solo elemento y por lo tanto sólo hay una posible selección. De lo anterior
se concluye que el número de formas de listar los elementos de un conjunto con cuatro
elementos es
4 ∗ 3 ∗ 2 ∗ 1 = 24
ª «
© ¨©ª«
« ª
¨©«ª
© « ¨ª©«
¨ ª
« © ¨ª«©
© ª ¨«©ª
« ¨«ª©
ª ©
154 CAPÍTULO 9. FUNCIONES RECURSIVAS
ª «
¨ ©¨ª«
« ª
©¨«ª
¨ « ©ª¨«
© ª
« ¨ ©ª«¨
¨ ª ©«¨ª
« ©«ª¨
ª ¨
© «
¨ ª¨©«
« ©
ª¨«©
¨ « ª©¨«
ª ©
« ¨ ª©«¨
¨ © ª«¨©
« ª«©¨
© ¨
© ª
¨ «¨©ª
ª ©
«¨ª©
¨ ª «©¨ª
« ©
ª ¨ «©ª¨
¨ © «ª¨©
ª «ª©¨
© ¨
El listado de las 24 posibles formas en que se pueden organizar las cuatro cartas es el
siguiente
En general, para un conjunto A con cardinal ∣A∣ = n, se tiene que el número de formas
de listar todas lo formas en que se pueden organizar los elementos de A es
n ∗ (n − 1) ∗ (n − 2) ∗ ⋯ ∗ 3 ∗ 2 ∗ 1
este valor depende solamente de n, es una función, se denota por el sı́mbolo n! y se llama
es factorial del número n. Para el caso del conjunto ∅, se puede demostrar que 0! = 1.
n! = n ∗ (n − 1) ∗ (n − 2) ∗ ⋯ ∗ 3 ∗ 2 ∗ 1
A partir de las observaciones anteriores se puede obtener la función recursiva factorial n!,
distinta a la exhibida anteriormente
f act(n) = f
entonces
f act ∶ N → N
⎧
⎪
⎪1, si n = 0;
(n) ↦ ⎨
⎪
⎩n ∗ f act(n − 1), en otro caso.
⎪
#include<iostream>
#include<cstdlib>
int main(){
int n;
cout << "n? = ";
cin >> n;
cout << "fact(n) = ";
cout << fact(n);
cout << "\n";
system("pause");
return EXIT_SUCCESS;
};
fact(5)
*
5 fact(4)
*
4 fact(3)
*
3 fact(2)
*
2 fact(1)
*
1 fact(0)
120 fact(5)
* 5 ∗ 24 = 120
5 fact(4)
* 4 ∗ 6 = 24
4 fact(3)
* 3∗2=6
3 fact(2)
* 2∗1=2
2 fact(1)
* 1∗1=1
1 fact(0)
1
9.2. EJEMPLOS DE PROBLEMAS QUE PUEDEN RESOLVERSE RECURSIVAMENTE 157
fact(5) = 5 * fact(4)
=5 * (4 * fact(3))
=5 * (4 * (3 * fact(2)))
=5 * (4 * (3 * (2 * fact(1))))
=5 * (4 * (3 * (2 * (1 * fact(0)))))
=5 * (4 * (3 * (2 * (1 * 1))))
=5 * (4 * (3 * (2 * 1)))
=5 * (4 * (3 * 2))
=5 * (4 * 6)
=5 * 24
= 120
⎧
⎪
⎪
Simpsons = ⎨
⎪
⎪
⎩
, , ,
⎫
⎪
⎪
⎬
⎪
⎪
⎭
2. Dado el conjunto Simpsons, para la pareja que se va seleccionar se puede escoger o
no a Homero, como se observa a continuación
⎧
⎪
⎪
⎨
⎪
⎪
⎩
, ,
C(4, 2)
,
⎫
⎪
⎪
⎬
⎪
⎪
⎭
⎧
⎪
⎪
⎨
⎪
⎪
⎩
, ,
C(3, 1)
,
⎫
⎪
⎪
⎬
⎪
⎪
⎭
+
⎧
⎪
⎪
⎨
⎪
⎪
⎩
, ,
C(3, 2)
⎫
⎪
⎪
⎬
⎪
⎪
⎭
158 CAPÍTULO 9. FUNCIONES RECURSIVAS
⎧
⎪
⎪
⎨
⎪
⎪
⎩
, ,
C(3, 1)
,
⎫
⎪
⎪
⎬
⎪
⎪
⎭
⎧
⎪
⎪
⎨
⎪
⎪
⎩
,
,
C(2, 0) = 1
,
⎫
⎪
⎪
⎬
⎪
⎪
⎭
+
⎧
⎪
⎪
⎨
⎪
⎪
⎩
,
C(2, 1)
,
⎫
⎪
⎪
⎬
⎪
⎪
⎭
⎧
⎪
⎪
⎨
⎪
⎪
⎩
,
C(2, 1)
,
⎫
⎪
⎪
⎬
⎪
⎪
⎭
⎧
⎪
⎪
⎨
⎪
⎪
⎩
,
C(1, 0) = 1
,
⎫
⎪
⎪
⎬
⎪
⎪
⎭
+
⎧
⎪
⎪
⎨
⎪
⎪
⎩
,
C(1, 1) = 1
⎫
⎪
⎪
⎬
⎪
⎪
⎭
si se escoge a Bart, entonces ya se tiene otra pareja, si no entonces Lisa debe hacer
parte de la siguiente pareja.
5. Si en el numeral 2 no se seleccionó a Homero, entonces ahora se puede escoger o no
a Marge, como se observa a continuación
⎧
⎪
⎪
⎨
⎪
⎪
⎩
, ,
C(3, 2)
⎫
⎪
⎪
⎬
⎪
⎪
⎭
⎧
⎪
⎪
⎨
⎪
⎪
⎩
, ,
C(2, 1)
⎫
⎪
⎪
⎬
⎪
⎪
⎭
+
⎧
⎪
⎪
⎨
⎪
⎪
⎩
,
C(2, 2) = 1
⎫
⎪
⎪
⎬
⎪
⎪
⎭
9.2. EJEMPLOS DE PROBLEMAS QUE PUEDEN RESOLVERSE RECURSIVAMENTE 159
⎧
⎪
⎪
⎨
⎪
⎪
⎩
, ,
C(2, 1)
⎫
⎪
⎪
⎬
⎪
⎪
⎭
⎧
⎪
⎪
⎨
⎪
⎪
⎩
, ,
C(1, 0) = 1
⎫
⎪
⎪
⎬
⎪
⎪
⎭
+
⎧
⎪
⎪
⎨
⎪
⎪
⎩
,
C(1, 1) = 1
⎫
⎪
⎪
⎬
⎪
⎪
⎭
si se escoge a Bart, entonces ya se tiene otra pareja, si no entonces Lisa debe hacer
parte de la última pareja.
⎧
⎪
⎪
⎨
⎪
⎪
⎩
,
⎫
⎪
⎪
⎬
⎪
⎪
⎭
⎧
⎪
⎪
⎨
⎪
⎪
⎩
,
⎫
⎪
⎪
⎬
⎪
⎪
⎭
⎧
⎪
⎪
⎨
⎪
⎪
⎩
,
⎫
⎪
⎪
⎬
⎪
⎪
⎭
⎧
⎪
⎪
⎨
⎪
⎪
⎩
,
⎫
⎪
⎪
⎬
⎪
⎪
⎭
⎧
⎪
⎪
⎨
⎪
⎪
⎩
,
⎫
⎪
⎪
⎬
⎪
⎪
⎭
⎧
⎪
⎪
⎨
⎪
⎪
⎩
,
⎫
⎪
⎪
⎬
⎪
⎪
⎭
C(4, 2)
+
C(3, 1) C(3, 2)
+ +
C(2, 0) C(2, 1) C(2, 1) C(2, 2)
+ +
1 C(1, 0) C(1, 1) C(1, 0) C(1, 1) 1
1 1 1 1
160 CAPÍTULO 9. FUNCIONES RECURSIVAS
C(n, k) = c
entonces
9.2. EJEMPLOS DE PROBLEMAS QUE PUEDEN RESOLVERSE RECURSIVAMENTE 161
C ∶N×N→N
⎧
⎪ si k > n;
⎪
⎪
⎪
0,
(n, k) ↦ ⎨1, si (k = 0) ∨ (n = k);
⎪
⎪
⎪
⎪
⎩C(n − 1, k − 1) + C(n − 1, k), en otro caso.
#include<iostream>
#include<cstdlib>
int main(){
int n;
int k;
cout << "n? = ";
cin >> n;
cout << "k? = ";
cin >> k;
cout << "C(n,k) = ";
cout << C(n,k);
cout << "\n";
system("pause");
return EXIT_SUCCESS;
};
mes1 . ¿Cuál es la cantidad de parejas de conejos en la isla una vez transcurrido un año,
suponiendo que ningún conejo muere?.
Si fn denota la cantidad de parejas de conejos en el mes n, entonces, en el mes cero, en
éste aun no se ha hecho la liberación de la pareja de conejos, por lo tanto la cantidad de
parejas es f0 = 0.
n = 0, f0 = 0
Durante el primer mes, en este se hace la liberación de la primera pareja de conejos, pero
aún no han alcanzado la edad para reproducirse, por lo tanto, no ha habido descendencia,
por lo tanto, f1 = 1.
n = 1, f1 = 1
Durante el segundo mes, ya habı́a una pareja de conejos del mes anterior y éstos aún
no han alcanzado la edad para reproducirse, por lo tanto, no hubo descendencia, de donde
f2 es igual a la cantidad de conejos que habı́an en el mes anterior más la descendencia que
produjeron las parejas de más de dos meses, es decir, f2 = 1.
n = 2, f2 = f1 + f0 = 1 + 0 = 1
Durante el tercer mes, ya habı́a una pareja de conejos del mes anterior y durante el
transcurso de este mismo mes los conejos alcanzaron la madures para reproducirse, por lo
tanto hubo descendencia, de donde f3 es igual a la cantidad de conejos del mes anterior
más la descendencia que se produjo en este mes, es decir, f3 = 2.
n = 3, f3 = f2 + f1 = 1 + 1 = 2 +
Durante el cuarto mes ya habı́an dos parejas de conejos del mes anterior, y la pareja
madura es la que habı́a en el segundo mes, por lo tanto, la descendencia fue generada
sólo por esa pareja, de donde f4 es igual a la cantidad de parejas del mes anterior más la
descendencia que generé la pareja del segundo mes, es decir, f4 = f3 + f2 = 2 + 1 = 3.
n = 4, f4 = f3 + f2 = 2 + 1 = 3 +
1
Este problema fué propuesto originalmente por el italiano Leonardo Pisano Bigollo (1170–1250), más
conocido como Leonardo de Pisa o Fibonacci (que significa hijo de Bonacci, filius Bonacci ) en su libro
Liber abaci publicado en 1202.
9.2. EJEMPLOS DE PROBLEMAS QUE PUEDEN RESOLVERSE RECURSIVAMENTE 163
Durante el quinto mes ya habı́an tres parejas de conejos del mes anterior, y de éstas hay
dos parejas maduras, que son las que habı́an en el tercer mes, por lo tanto, la descendencia
fue generada por esas dos parejas, de donde f5 es igual a la cantidad de parejas del mes
anterior más la descendencia que generen las parejas del tercer mes, es decir, f5 = f4 + f3 =
3 + 2 = 5.
n = 5, f5 = f4 + f3 = 3 + 2 = 5 +
De aquı́ que, transcurrido el primer año, en la isla habrán 144 parejas de conejos.
A los números que son generados utilizando esta regla se les conoce como números de
Fibonacci.
A partir del análisis anterior, se puede diseñar una función recursiva que permite cal-
cular cualquier número de Fibonacci.
f ibo(n) = f
donde se tienen las variables
entonces
f ibo ∶ N → N
⎧
⎪ si n = 0;
⎪
⎪
⎪
0,
(n) ↦ ⎨1, si n = 1;
⎪
⎪
⎪
⎪
⎩f ibo(n − 1) + f ibo(n − 2), en otro caso.
164 CAPÍTULO 9. FUNCIONES RECURSIVAS
#include<iostream>
#include<cstdlib>
int main(){
int n;
cout << "n? = ";
cin >> n;
cout << "Fibonacci(n) = ";
cout << fibo(n);
cout << "\n";
system("pause");
return EXIT_SUCCESS;
};
m=p∗q
donde p, q ∈ N, 1 < p < m y 1 < q < m. Entonces, para saber si un número es primo es
equivalente a verificar que no es compuesto, es decir, que no hay un número k ∈ N, tal que
1 < k < m y que k sea divisor de m.
De lo anterior, para saber si un número m es compuesto hay que ir probando con los
números desde 2 hasta m − 1, y verificar si alguno de ellos es divisor de m; si no es ası́,
entonces m es primo. A partir de esta idea se observa que se tienen a lo más m−2 opciones
de posibles divisores.
Una mejora al algoritmo anterior es observar que para aquellos valores que sean mayores
a ⌈ m2 ⌉ estos no pueden ser divisores, ya que si a > ⌈ m2 ⌉, entonces 2a > 2⌈ m2 ⌉ ≥ 2 m2 = 2, razón
9.2. EJEMPLOS DE PROBLEMAS QUE PUEDEN RESOLVERSE RECURSIVAMENTE 165
por la cual a no es un divisor, pues al multiplicarlo por cualquier numero mayor o igual a
2, el producto siempre excederá a m. A partir de esta idea se observa que se tienen a lo
más ⌈ m2 ⌉ − 1 opciones de posibles divisores válidos.
Una observación adicional que hará más eficiente el algoritmo es la que se puede concluir
a partir del siguiente teorema
Como conclusión del teorema anterior se puede√observar que para un número compuesto
√
m, uno de sus divisores debe ser menor o igual a ⌈ m⌉, de donde se tienen a lo más ⌈ m⌉−1
opciones de posibles divisores válidos.
A partir del teorema anterior, se pueden diseñar las funciones que permiten determinar
si un número es primo o no. Inicialmente es necesario construir una función auxiliar o
ayudante (en inglés helper ) que nos permita responder a la pregunta
√ ¿Dado un par de
enteros positivos n y d, n es múltiplo de algún valor entre d y n inclusive?. La siguiente
función recursiva permite responder a la pregunta anterior.
multiplo(n, d) = valor
donde se establecen las variables
entonces
multiplo ∶ N × P → B
⎧
⎪ si n mód d = 0;
⎪
⎪
⎪
V,
√
(n, d) ↦ ⎨F, si d > n;
⎪
⎪
⎪
⎪
⎩multiplo(n, d + 1), en otro caso.
166 CAPÍTULO 9. FUNCIONES RECURSIVAS
Con el uso de la anterior función se puede diseñar una nueva función que permita
determinar
√ si un entero mayor que 1 es primo o no, la idea es probar los números entre 2
y n usando la función anterior y verificar si n es múltiplo de alguno de estos números, si
se da este caso, entonces el número no es primo, en caso contrario se tendrá que el número
es primo. La siguiente función permite determinar si un número es primo o no
primo(n) = valor
entonces
primo ∶ N ∖ {0, 1} → B
⎧
⎪
⎪V, si n = 2;
(n) ↦ ⎨
⎪
⎩¬multiplo(n, 2), en otro caso.
⎪
#include<iostream>
#include<cstdlib>
#include<cmath>
int main(){
int n;
cout << "n? = ";
cin >> n;
cout << "Es n primo? = ";
cout << primo(n);
cout << "\n";
system("pause");
return EXIT_SUCCESS;
};
multiplo ∶ N × P → B
⎧
⎪ n mód d = 0;
⎪
⎪
⎪
V, si
√
⎪
⎪
⎪F, si d > n;
(n, d) ↦ ⎨
⎪
⎪
⎪ multiplo(n, 3), si d = 2;
⎪
⎪
⎪
⎪
⎩multiplo(n, d + 2), en otro caso.
Pared 1
p1
Pared 2
p2
El gerente de la empresa desea fijar unos carteles del mismo ancho, con la condición de
que tiene que colocar los afiches completos, que abarquen en su totalidad dichas paredes y
que no se solapen. La empresa tiene la capacidad de mandar a imprimir y cortar los afiches
de cualquier ancho. ¿Cuál será el afiche de mayor ancho que puede colocar la empresa de
tal manera que utilice en su totalidad las paredes y que los afiches se peguen completos
sin solaparse?
1. Para saber cuál es el afiche más ancho que se puede colocar en las paredes p1 y p2 ,
se debe observar que la pared más corta es p2 , por lo tanto el afiche más ancho debe
tener por mucho el ancho de esa pared.
2. Si a la pared más ancha p1 se tapa con la pared más corta p2 , se obtiene un resto r1
de pared como el siguiente
p1
p2 r1
3. Como los afiches taparán completa y exactamente la pared p2 , para que estos afiches
también tapen la pared p1 , entonces deben tapar completa y exactamente el resto r1
de la pared. Por lo que para este caso el afiche más ancho debe tener por mucho el
ancho de ese resto r1 de pared.
4. El ancho de r1 pasa a ser entonces el candidato a ser el ancho del afiche, por lo que
es necesario que el afiche que tape la pared r1 también tape la pared p2 . Ası́, si ahora
se tapa pared p2 con la pared r1 tantas veces como sea posible, entonces, se obtiene
9.2. EJEMPLOS DE PROBLEMAS QUE PUEDEN RESOLVERSE RECURSIVAMENTE 169
r1 r1 r2
5. En este caso ocurre lo mismo que en el numeral 3, para tapar la pared p2 se debe
tapar también la pared restante r2 , por lo que el afiche más ancho debe tener por
mucho el ancho de ese resto r2 de pared.
r2 r3
7. En este punto, el análisis es similar a los casos anteriores, pues para tapar la pared
r1 es necesario tapar el resto de pared r3 . Con lo cual se obtiene un nuevo candidato,
el ancho de la pared r3 . Si con esta pared r3 se tapa la pared r2 tantas veces como
sea posible, entonces se obtiene el siguiente cubrimiento total de la pared r2 .
r2
r3 r3
8. Por la construcción anterior, se tiene que un afiche que utilice en su totalidad las
paredes y que se peguen completos sin solaparse está dado por el ancho de la pared
r3 . Un afiche de este ancho será el de mayor tamaño pues siempre se escogió el de
mayor tamaño posible para ir descartando las otras opciones.
9. El aspecto de las paredes con los afiches colocados de acuerdo al resultado obtenido
es el siguiente
170 CAPÍTULO 9. FUNCIONES RECURSIVAS
mcd recur(p, q) = m
donde se tienen las variables
entonces
mcd recur ∶ N × N → N
⎧
⎪
⎪p, si q = 0;
(p, q) ↦ ⎨
⎪
⎪
⎩mcd recur(q, p mód q), en otro caso.
Como se desea que se pueda calcular el máximo común divisor de cualesquiera dos
números naturales, entonces la función anterior se utilizará como una función auxiliar
(helper ), y la siguiente función sı́ permitirá calcular el máximo común divisor de cuales-
quiera dos números, ésta lo que hace es primero encontrar el mayor de los dos números y
luego utilizar la función mcd recur(p, q) de forma correcta.
9.2. EJEMPLOS DE PROBLEMAS QUE PUEDEN RESOLVERSE RECURSIVAMENTE 171
mcd(p, q) = m
donde se tienen las variables
entonces
mcd ∶ N × N → N
⎧
⎪
⎪mcd recur(p, q), si p > q;
(p, q) ↦ ⎨
⎪
⎪
⎩mcd recur(q, p), en otro caso.
Y la función
La codificación en C++ de estas funciones junto con su programa principal es
#include<iostream>
#include<cstdlib>
int main(){
int p;
int q;
cout << "p? = ";
cin >> p;
cout << "q? = ";
cin >> q;
cout << "m.c.d(p,q) = ";
cout << mcd(p,q);
cout << "\n";
system("pause");
return EXIT_SUCCESS;
};
9.4. Ejercicios
1. Modele mediante una función matemática y diseñe un programa recursivo que dados
dos numeros enteros no negativos m y n, indique si el primer numero m es mayor
estrictamente que el segundo número n, que utilice sólo el operador de comparación
de la igualdad (==), la función sucesor (sumar 1), la función predecesor (restar 1) y
la estructura condicional (if, if-else).
2. Modele mediante una función matemática y diseñe un programa recursivo que dados
dos numeros enteros no negativos m y n determine el mayor de los dos números que
utilice sólo el operador de comparación de la igualdad (==), la función sucesor (sumar
1), la función predecesor (restar 1) y la estructura condicional (if, if-else).
3. Modele mediante una función matemática y diseñe un programa recursivo que calcule
la suma de los primeros n números naturales (∑ni=0 i).
4. Modele mediante una función matemática y diseñe un programa recursivo que calcule
la suma de los cuadrados de los primeros n números naturales (∑ni=0 i2 ).
5. Modele mediante una función matemática y diseñe un programa recursivo que calcule
el producto de los primeros n números positivos (∏ni=1 i).
6. Modele mediante una función matemática y diseñe un programa recursivo que calcule
el producto de los cuadrados de los primeros n números positivos (∏ni=1 i2 ).
7. Modele mediante una función matemática y diseñe un programa recursivo que calcule
el logaritmo entero en base 2 de n ([ log2 n]). Por ejemplo, [ log2 1] = 0, [ log2 4] = 2,
[ log2 7] = 2, [ log2 15] = 3.
8. Modele mediante una función matemática y diseñe un programa recursivo que calcule
el logaritmo entero en base b de n ([ logb n]).
9. Modele mediante una función matemática
√ y diseñe un programa
√ recursivo
√ que
√calcule
la√raı́z cuadrada entera de a ([ a]). Por ejemplo, [ 0] = 0, [ 1] = 1, [ 5] = 2,
[ 10] = 3.
10. Modele mediante una función matemática
√ y diseñe un programa recursivo que calcule
la raı́z n-ésima entera de a ([ a]).
n
11. Modele mediante una función matemática y diseñe un programa recursivo que calcule
la función módulo (m mód n = k). Por ejemplo, 0 mód 2 = 0, 4 mód 2 = 0, 3 mód 3 = 0,
10 mód 3 = 1, 14 mód 5 = 4.
12. Modele mediante una función matemática y diseñe un programa que retorne el últi-
mo dı́gito de un número natural n (leı́do de izquierda a derecha). Por ejemplo,
ultimo(13579) = 9.
13. Modele mediante una función matemática y diseñe un programa recursivo que de-
termine la cantidad de dı́gitos que componen un número natural n. Por ejemplo,
longitud(1230321) = 7.
174 CAPÍTULO 9. FUNCIONES RECURSIVAS
14. Modele mediante una función matemática y diseñe un programa recursivo que cal-
cule la suma de los dı́gitos que componen un número natural n. Por ejemplo,
suma digitos(123456) = 21.
15. Modele mediante una función matemática y diseñe un programa recursivo que re-
torne el primer dı́gito de un número natural n (leı́do de izquierda a derecha). Por
ejemplo, primero(86420) = 8.
16. Modele mediante una función matemática y diseñe un programa recursivo que in-
vierta la cifras de un número n dado. Por ejemplo, inversa(654321) = 123456.
17. Modele mediante una función matemática y diseñe un programa recursivo que deter-
mine si un número es capicua. Un número se dice palı́ndromo si al leerlo de izquierda
a derecha es lo mismo que leerlo de derecha a izquierda. Por ejemplo, capicua(1) = V ,
capicua(1234321) = V , capicua(123421) = F .
18. Modele mediante una función matemática y diseñe un programa recursivo que da-
do un número natural n inserte un dı́gito al comienzo del número. Por ejemplo,
inserta(7, 654321) = 7654321.
19. Modele mediante una función matemática y diseñe un programa recursivo que
dado un número natural n elimine el último dı́gito del número. Por ejemplo,
elimina ult(654321) = 65432.
20. Modele mediante una función matemática y diseñe un programa recursivo que
dado un número natural n elimine el primer dı́gito del número. Por ejemplo,
elimina pri(654321) = 54321.
21. Modele mediante una función matemática y diseñe un programa que calcule el mı́ni-
mo común múltiplo de dos números positivos a y b. Por ejemplo, mcm(18, 24) = 72.
22. Modele mediante una función matemática y diseñe un programa que dados dos
número positivos p y q, donde p representa el numerador y q el denominador de la
p p
fracción , imprima primero el numerador de la fracción simplificada a su mı́nima
q q
p
expresión y luego el denominador de la fracción simplificada a su mı́nima expresión.
q
23. Modele mediante una función matemática y diseñe un programa que dados cuatro
número positivos p, q, r y s, donde p representa el numerador y q el denominador
p
de la fracción , y r representa el numerador y s el denominador de la fracción
q
r p r
, imprima primero el numerador de la fracción resultante de la operación +
s q s
simplificada a su mı́nima expresión y luego el denominador de la fracción resultante
p r
de la operación + simplificada a su mı́nima expresión.
q s
<bloque_prev>
<inicia>
<cond>
V
<bloque>
F
<actualiza>
<bloque_sigui>
175
176 CAPÍTULO 10. ESTRUCTURAS DE PROGRAMACIÓN CÍCLICAS
<bloque_prev>
<inicia>
while(<cond>){
<bloque>
<actualiza>
};
<bloque_sigui>
en donde:
<bloque_prev>
int i = 0;
while(i <= 6){
cout << i;
cout << endl;
i = i + 1;
};
<bloque_sigui>
cuando se ejecuta este ciclo lo que se obtiene en la consola de salida es el texto que se
presenta en el cuadro a la derecha
...
<bloque_prev> 0
int i = 0; 1
while(i <= 6){ 2
cout << i; 3
cout << endl; 4
i = i + 1; 5
}; 6
<bloque_sigui> ...
<bloque_prev>
int i = 1;
int j = 100;
while(i < j){
cout << i;
cout << " ";
cout << j;
cout << endl;
i = i * 2;
j = j + 25;
};
<bloque_sigui>
178 CAPÍTULO 10. ESTRUCTURAS DE PROGRAMACIÓN CÍCLICAS
...
<bloque_prev> ...
int i = 1; 1 100
int j = 100; 2 125
while(i < j){ 4 150
cout << i; 8 175
cout << " "; 16 200
cout << j; 32 225
cout << endl; 64 250
i = i * 2; 128 275
j = j + 25; 256 300
}; ...
<bloque_sigui> ...
Obsérvese que las variables i y j terminan el ciclo con los valores 512 y 325, y como
512 no es menor que 325, entonces el ciclo se para y se sale de éste, por esta razón no se
imprimen estos valores.
Para encontrar dicho número hay un algoritmo muy sencillo que permite encontrar el
valor.
El algoritmo consiste en calcular los términos de una progresión geométrica que inicia
con el término x0 = 1 y para la cual los términos siguientes se calculan utilizando la razón
xn
de la progresión r = 1/2, es decir, xn+1 = , esto se realiza mientras cada nuevo término
2
es positivo.
La codificación en C++ de una función que permite hallar el mı́nimo número positivo
representable en la máquina junto con su programa principal es
10.1. LA ESTRUCTURA DE CONTROL DE CICLOS MIENTRAS (WHILE) 179
#include<iostream>
#include<cstdlib>
double min_maquina(){
double Xo = 1.0;
double Xi = Xo / 2;
while(Xi > 0.0){
Xo = Xi;
Xi = Xo / 2.0;
};
return Xo;
};
int main(){
cout << "El numero positivo mas pequeno que se puede\n";
cout << "representar en la maquina es: ";
cout << min_maquina();
cout << endl;
system("pause");
return EXIT_SUCCESS;
};
180 CAPÍTULO 10. ESTRUCTURAS DE PROGRAMACIÓN CÍCLICAS
<bloque_prev>
<inicia>
<cond>
V
<bloque>
F
<actualiza>
<bloque_sigui>
<bloque_prev>
<inicia>
while(<cond>){
<bloque>
<actualiza>
};
<bloque_sigui>
representación sintáctica es más compacta y se separa el control del ciclo del calculo que
se desea realizar con el ciclo.
<bloque_prev>
for(<inicia> ; <cond> ; <actualiza>){
<bloque>
};
<bloque_sigui>
estas dos funciones son equivalentes, ya que ejecutan las mismas modificaciones de las
variables, pues se tiene que el fragmento de código:
En la construcción de estas funciones aparecen dos variable que tienen una connotación
muy importante:
• La variable i juega el rol de una variable contadora ya que permite llevar el conteo
de cuantos ciclos se han efectuado.
La codificación en C++ de una función que permite sumar los primeros n números
naturales positivos junto con su programa principal es
#include<iostream>
#include<cstdlib>
int main(){
int n;
cout << "n? = ";
cin >> n;
cout << "La suma de los primeros n numeros es: ";
cout << suma(n);
cout << endl;
system("pause");
return EXIT_SUCCESS;
};
10.2. LA ESTRUCTURA DE CONTROL DE CICLOS PARA (FOR) 183
n? = 6
La suma de los primeros n numeros es: 21
Presione una tecla para continuar . . .
1
2
3
4
5
6
1 1
2 2
3 3
4 4
5 5
6 6
ahora, si se rota la segunda escalera dos ángulos rectos se obtienen las siguientes figuras
184 CAPÍTULO 10. ESTRUCTURAS DE PROGRAMACIÓN CÍCLICAS
1 6
2 5
3 4
4 3
5 2
6 1
1 + 6 = 7 +
2 + 5 = 7 +
3 + 4 = 7 +
4 + 3 = 7 +
5 + 2 = 7 +
6 + 1 = 7 +
como se observa a continuación, siempre se puede formar un rectángulo tal que uno de sus
lados es igual a n = 6 y el otro es igual a n + 1 = 7, y por la forma en que se construyó el
rectángulo se observa que la suma de los cuadrados de cada escalera es igual a la mitad
de la cantidad total de cuadrados en el rectángulo.
1 + 6 = 7
2 + 5 = 7
3 + 4 = 7
n=6
4 + 3 = 7
5 + 2 = 7
6 + 1 = 7
42
n+1=7
Existe otra estructura cı́clica en programación, ésta se conoce como un ciclo do. Esta
estructura es casi equivalente a la estructura while, ya que usualmente se utiliza cuando
con seguridad y de forma anticipada se sabe que se hará al menos una evaluación del bloque
principal del ciclo. En esta estructura cı́clica la verificación de la condición de parada se
realiza al final del ciclo.
Un ciclo do se puede representar gráficamente mediante un diagrama de flujo de la
siguiente manera.
<bloque_prev>
<inicia>
<bloque>
V
<actualiza>
<cond>
F
<bloque_sigui>
<bloque_prev>
<inicia>
while(<cond>){
<bloque>
<actualiza>
};
<bloque_sigui>
<bloque_prev>
<inicia>
do{
<bloque>
<actualiza>
}while(<cond>);
<bloque_sigui>
• En segunda instancia, por la ley de tricotomı́a de los números reales, se cumple que:
√ √ √
x0 = a ∨ x0 > a ∨ x0 < a
0 √ a
x0 = a=
x0
√
• Si x0 > a entonces
√
x0 > a
√ √ √
x0 a > a a
√
x0 a > a
√ a
a>
x0
√ a
de donde x0 > a> .
x0
( )
a √ x0
0 a
x0
√
• Si x0 < a entonces
√
x0 < a
√ √ √
x0 a < a a
√
x0 a < a
√ a
a<
x0
√ a
de donde x0 < a< .
x0
( )
x0 √ a
0 a
x0
188 CAPÍTULO 10. ESTRUCTURAS DE PROGRAMACIÓN CÍCLICAS
√ a √
• Como se observa en el análisis anterior, la relación de a con x0 y , es que a
x0
siempre o es igual a esos valores (primer caso) o está entre esos valores (segundo y
tercer caso).
√ a
• Si a es igual a x0 y , entonces el problema ya se soluciono y se tiene el valor
√ x0
exacto de a.
√ a
• Si a está entre x0 y , entonces hay que decidir si alguno de esos valores es una
x0 √
aproximación lo suficientemente exacta a a, √ o si una combinación esos valores es
una aproximación lo suficientemente exacta√a a, o si es necesario calcular valores
que se aproximen mejor al valor exacto de a.
√
• Si es necesario calcular valores que se aproximen mejor al valor exacto de a, puede
√ a
observarse que como a está entre x0 y , entonces el punto medio del intervalo
x0
que determinan esos valores 12 (x0 + xa0 ) es un valor que también sirve de aproximación
√
al valor de a, por√lo tanto ese valor se puede tomar como una nueva aproximación
inicial al valor de a.
• Si se sigue el procedimiento de calcular el valor medio del intervalo que se construye
a partir de cada nueva aproximación, entonces lo que se obtiene es una sucesión de
valores
√ x0 , x1 , x2 , . . . , xi , . . . que cada vez se aproximan mejor (que convergen) al valor
de a.
• La sucesión que se obtiene se puede expresar en general de la siguiente manera:
• Una pregunta que hay que hacerse en este momento es ¿hasta cuándo se deben
calcular nuevos valores?.
Una de las caracterı́sticas de estos métodos constructivistas es que es posible que
no se obtenga el valor exacto porque el resultado no se puede representar con finita
memoria o es demasiado grande para la memoria o el tiempo necesario para calcular
el valor exacto es infinito.
Para este ejemplo y muchos de este tipo, hay que conformarse con obtener una
aproximación lo suficientemente precisa que sea útil para resolver el problema que
se ésta solucionado.
10.3. LA ESTRUCTURA DE CONTROL DE CICLOS HACER-MIENTRAS (DO) 189
La codificación en C++ de una función que permite calcular la raı́z cuadrada de cual-
quier número real positivo junto con su programa principal es
#include<iostream>
#include<cstdlib>
La función valor absoluto es necesaria para calcular la distancia entre dos valores.
Como para calcular el error relativo es necesario tener al menos dos aproximaciones, en-
tonces, dado el primer valor inicial es necesario calcular al menos otro valor de la sucesión,
razón por la cual el uso de un ciclo do es muy conveniente.
190 CAPÍTULO 10. ESTRUCTURAS DE PROGRAMACIÓN CÍCLICAS
int main(){
double a;
cout << "a? = ";
cin >> a;
cout << "Una aproximacion de la raiz cuadrada de a es: ";
cout << raiz(a);
cout << endl;
system("pause");
return EXIT_SUCCESS;
};
a? = 2
Una aproximacion de la raiz cuadrada de a es: 1.41421
Presione una tecla para continuar . . .
√
El valor 1.41421 es una aproximación al valor 2 con una precisión del error menor a
10 .
−4
<bloque_prev>
<inicia>
while(<cond>){
<bloque>
<actualiza>
};
<bloque_sigui>
1. Se debe crear una nueva función recHelperFunc() que tendrá tantos parámetros
como variables intervengan en el ciclo while a simular;
2. La variable principal que se desea calcular con el ciclo se debe colocar como primer
parámetro de la función.
4. Dentro del condicional se anexan las instrucciones del <body> y luego las del
<update>.
6. Finalmente se retorna la variable principal que se desea calcular con el ciclo inme-
diatamente después de finalizar el condicional.
7. La porción del código que abarca el ciclo while se reemplaza por una asignación donde
a la variable principal que se desea calcular con el ciclo se le asigna el resultado de
evaluar la función recursiva en las variables que intervienen en el ciclo y que fueron
inicializadas previamente al ciclo; el bloque previo, la inicialización y el bloque siguiente
no se alteran.
<bloque_prev>
<inicia>
while(<cond>){
<bloque>
<actualiza>
};
<bloque_sigui>
<bloque_prev>
<inicia>
var1 = recHelperFunc(var1, var2, ... , varN);
<bloque_sigui>
La función original será modificada eliminando el ciclo while sin eliminar el bloque
<init> y reemplazándola por la instrucción donde se llama la función recursiva con las
variables que intervienen en el ciclo original y se asigna el valor final de la evaluación de
la función recursiva a la variable fact que se deseaba calcular en el ciclo. El aspecto de la
función original modificada como se explicó anteriormente es el siguiente.
teclado, se verifica si se incumple con alguna de las condiciones que deben cumplir las
variables, en caso de que se incumpla, se solicita de nuevo al usuario que vuelva a ingresar
la información y esto se hace hasta que la información ingresada sea correcta.
Ejemplo. Con respecto al algoritmo para el cálculo del área de un rectángulo dada la
definición del tipo de dato podrı́an estarse leyendo largos o anchos negativos. La notación
matemática también permite restringir el dominio y el rango de los conjuntos quedando
la función de la siguiente forma
#include<iostream>
#include<cstdlib>
int main(){
double largo;
double ancho;
do{
cout << "Por favor ingrese el largo del rectangulo" << endl;
cout << "largo? = ";
cin >> largo;
}while(largo < 0);
do{
cout << "Por favor ingrese el ancho del rectangulo" << endl;
cout << "ancho? = ";
cin >> ancho;
}while(ancho < 0);
cout << "El area del rectangulo es: ";
cout << area_rectangulo(largo, ancho);
cout << endl;
system("pause");
return EXIT_SUCCESS;
};
196 CAPÍTULO 10. ESTRUCTURAS DE PROGRAMACIÓN CÍCLICAS
10.7. Ejercicios
1. Imprimir un listado con los números del 1 al 100 cada uno con su respectivo cuadrado.
2. Imprimir un listado con los números impares desde 1 hasta 999 y seguidamente otro
listado con los números pares desde 2 hasta 1000.
3. Imprimir los números pares en forma descendente hasta 2 que son menores o iguales
a un número natural n ≥ 2 dado.
5. Imprimir los números de 1 hasta un número natural n dado, cada uno con su res-
pectivo factorial.
9. Elaborar una función que reciba un número entero, que retorne −1 si el número es
negativo, si el número es positivo debe devolver una clave calculada de la siguiente
manera: se suma cada dı́gito que compone el número y a esa suma se le calcula el
módulo 7. Por ejemplo: para la cifra 513, la clave será 5 + 1 + 3 = 9; 9 mód 7 = 2.
11. Introducir un rango especificado por 2 números enteros, tal que el primero sea menor
al segundo y contar el número de múltiplos de un numero entero leı́do que existe en
el rango. Por ejemplo, si se introduce 2 y 21, el número de múltiplos de 3 es 7, dado
que 3, 6, 9, 12, 15, 18 y 21 son múltiplos de 3 en el rango [2, 21].
12. Diseñar una función que permita calcular el épsilon de la máquina. El epsilon de
máquina es el número decimal más pequeño que sumado a 1 se puede representar
de manera precisa en la máquina (que no es redondeado), es decir, retorna un valor
diferente de 1, éste da una idea de la precisión o número de cifras almacenadas. La
idea es realizar un ciclo en el cual se realiza la operación 1 + para potencias de 2
desde 20 y continuando con potencias cada vez más pequeñas, hasta obtener que el
resultado de la suma no se altere.
13. Diseñar una función que permita calcular una aproximación de la función exponencial
alrededor de 0 para cualquier valor x ∈ R, utilizando los primeros n términos de la
serie de Maclaurin n
xi
exp(x, n) ≈ ∑ .
i=0 i!
10.7. EJERCICIOS 197
14. Diseñar una función que permita calcular una aproximación de la función seno alre-
dedor de 0 para cualquier valor x ∈ R (x dado en radianes), utilizando los primeros
n términos de la serie de Maclaurin
n
(−1)i x2i+1
sen(x, n) ≈ ∑ .
i=0 (2i + 1)!
15. Diseñar una función que permita calcular una aproximación de la función coseno
alrededor de 0 para cualquier valor x ∈ R (x dado en radianes), utilizando los primeros
n términos de la serie de Maclaurin
n
(−1)i x2i
cos(x, n) ≈ ∑ .
i=0 (2i)!
16. Diseñar una función que permita calcular una aproximación de la función logaritmo
natural alrededor de 0 para cualquier valor x ∈ R+ , utilizando los primeros n términos
de la serie de Maclaurin
2i+1
n
1 ⎛ x2 − 1 ⎞
ln(x, n) ≈ ∑ .
i=0 2i + 1 ⎝ x + 1 ⎠
2
17. Diseñar una función que permita calcular una aproximación de la función arco tan-
gente para cualquier valor x ∈ [−1, 1], utilizando los primeros n términos de la serie
de Maclaurin (al evaluar esta función el resultado que se obtiene esta expresado en
radianes)
n
(−1)i x2i+1
arctan(x, n) ≈ ∑ .
i=0 (2i + 1)
198 CAPÍTULO 10. ESTRUCTURAS DE PROGRAMACIÓN CÍCLICAS
Capı́tulo 11
Vectores o arreglos unidimensionales
v = (v1 , v2 , v3 , . . . , vn )
donde el vector está constituido por n componentes de un conjunto genérico V. Si v ∈ Vn ,
entonces el vector se dice que es n-dimensional o de tamaño n.
Ejemplo. El siguiente vector de tamaño 6 pertenece a Z6 y tiene una notación particular
la cual es 06
06 = (0, 0, 0, 0, 0, 0)
En un vector, para referirse a una componente en particular, a ésta se le dice que es
la componente en la posición i o la i-ésima componente, esto significa que el objeto es
la componente ubicada en la posición i, se denota por la expresión vi y se puede ubicar
dentro del vector como se muestra a continuación
componente i-ésima
(v1 , . . . , vi , . . . , vn )
199
200 CAPÍTULO 11. VECTORES O ARREGLOS UNIDIMENSIONALES
• v1 = −1. • v2 = 43 . • v3 = −0.25.
√
• v4 = − 51 . • v5 = 2. • v6 = 0.0.
√
• v7 = π. • v8 = 3 5. • v9 = 0.9.
Vn = V × V × V × ⋯ × V
´¹¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹¸¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¹ ¶
n-veces
se puede obtener el conjunto de los vectores V∗ , el cual se define como la unión de todos
los productos cartesianos del conjunto V, de la siguiente manera
V∗ = ⋃ Vn
n∈N
ası́, el conjunto de los arreglos del tipo de datos T es una colección de variables del tipo
de datos T.
Para definir arreglos se utilizará la notación de memoria dinámica, es decir, si x ∈ T∗
entonces el vector x se creará en tiempo de ejecución del programa.
Si se quiere expresar en C++ que x ∈ T∗ esto se escribe como T* x; y para reservar el
espacio de memoria para todo el arreglo de tipo T, esto se escribe como x = new T[n].
De donde, para crear un arreglo x de tamaño n y de tipo T se utiliza la instrucción
11.2. LOS ARREGLOS O VECTORES EN COMPUTACIÓN 201
T* x = new T[n]
Con esta instrucción se reserva una porción de la memoria M que es utilizada para
almacenar el arreglo y que es bloqueada para que sólo se pueda utilizar para guardar
valores en el arreglo, a menos que el espacio se libere y se pueda utilizar para almacenar
otro tipo de información. A la porción de espacio de memoria que ocupa un arreglo x lo
notaremos como Mx . Gráficamente esto se puede ver ası́:
new T[n]
T T ⋯ T T
Mx
T* x = new T[n]
T T ⋯ T T
x Mx
202 CAPÍTULO 11. VECTORES O ARREGLOS UNIDIMENSIONALES
xi ≡ x[i-1]
⋯
2 2 2 2 2
↑ ↑ ↑ ⋯ ↑ ↑
En lenguajes como SciLab y MatLab, la primera componente del arreglo está ubicada
en la posición 1, y para un arreglo de tamaño n se tiene que la última componente del
arreglo estará ubicada en la posición n, por lo que las posiciones se manejan como en
notación matemática de vectores, es decir, para acceder en SciLab o MatLab a la variable
almacenada en la componente i se utiliza la equivalencia
11.2. LOS ARREGLOS O VECTORES EN COMPUTACIÓN 203
xi ≡ x[i]
En caso de que se quiera acceder a una componente mayor o igual a la n-ésima en C++
entonces el valor almacenado será lo que en ese momento tenga la memoria en el siguiente
campo de la memoria, pero éste será un valor inesperado, por que simplemente no se ha
protegido ese espacio de memoria y la información allı́ es desconocida a priori. Si se quiere
acceder a una componente menor a 0, ocurre algo similar a lo descrito anteriormente.
crear arreglo T ∶ N → T∗
(n) ↦ x, donde x ∈ Tn ⊊ T∗
En C++ se traduce
T* crear_arreglo_T(int n){
return new T[n];
};
Para eliminar un arreglo, se debe entender que lo que ocurre es que la porción del
espacio de la memoria que se utiliza para almacenar las componentes del arreglo se liberan
o se regresan al sistema operativo para que éste disponga de esa memoria para almacenar
nueva información.
204 CAPÍTULO 11. VECTORES O ARREGLOS UNIDIMENSIONALES
Matemáticamente se puede modelar esto como una función que dado el arreglo x y el
tamaño del arreglo n (aunque este último no se requiere, pero se suele utilizar), se retorna
la porción del espacio de la memoria Mx que es utilizado para almacenar el arreglo x, de
esta manera la función se puede escribir ası́
Hay que recordar aquı́ que ℘(M) es el conjunto de todos los subconjuntos de la memoria
M y que dado un arreglo x, Mx es una porción de memoria donde se almacena el arreglo
x, por lo tanto Mx ⊆ M, es decir Mx ∈ ℘(M).
Para traducir esta función a C++ se debe tener en cuenta que la función no retorna un
valor de un tipo de datos, si no que se regresa memoria al sistema operativo, por lo que la
función regresa un espacio que esta vació y queda disponible para utilizarse de nuevo.
El desbloqueo de la memoria y la liberación del espacio utilizado por el arreglo x se
escribe en C++ mediante la instrucción
delete[] x;
T T ⋯ T T
x Mx
delete[] x;
Para decir que se retorna memoria vacı́a al sistema operativo se utiliza como tipo de
dato el vacı́o que en C++ se escribe como void y en el cuerpo de la función se utiliza la
11.3. ARREGLOS Y FLUJOS DE DATOS 205
instrucción return; para indicar que se retorno una porción de espacio que esta vació y
que queda disponible para usarse de nuevo.
Una función que sólo manipula la memoria y que retorna un tipo de dato vacı́o, en
programación se conoce como un procedimiento.
De esta manera, la traducción de la función en C++ se escribe de la siguiente manera
leer arreglo T ∶ IS × T∗ × N → T∗
(is, x, n) ↦ x, donde xi = leer T(is),
∀i = 1, 2, 3, . . . , n.
Ejemplo. En C++ para leer un arreglo de tipo entero se utiliza la siguiente función
1 2
1 1
2 2
3 3 1
5 4 n=5 5 4 n = 5, i=0
3 4
2 3
3 4
4 1 2 5 1 2 3
5 n = 5, i=1 n = 5, i=2
5 6
4 5
5
1 2 3 4 1 2 3 4 5
n = 5, i=3 n = 5, i=4
1 2 3 4 5
n = 5, i=5
escribir arreglo T ∶ OS × T∗ × N → OS
(os, x, n) ↦ os, donde escribir T(os, xi ),
∀i = 1, 2, 3, . . . , n.
Ejemplo. En C++ para escribir un arreglo de tipo entero se utiliza la siguiente función
1 2
n=5 n = 5, i = 0
1 2 3 4 5 1 2 3 4 5
1
3 4
n = 5, i = 0 n = 5, i = 1
1 2 3 4 5 1 2 3 4 5
1 2 1
208 CAPÍTULO 11. VECTORES O ARREGLOS UNIDIMENSIONALES
5 6
n = 5, i = 1 n = 5, i = 2
1 2 3 4 5 1 2 3 4 5
1
2 1 3 2
7 8
n = 5, i = 2 n = 5, i = 3
1 2 3 4 5 1 1 2 3 4 5 1
2
3 2 4 3
9 10
n = 5, i = 3 n = 5, i = 4
1 2 3 4 5 1 2 1 2 3 4 5 1 2
3
4 3 5 4
11 12
n = 5, i = 4 n = 5, i = 5
1 1
1 2 3 4 5 2 3 1 2 3 4 5 2 3
5 4 5 4
13
1 2 3 4 5 1 2 3 4 5
Es posible utilizar lo visto en funciones para realizar diversidad de cálculos que involu-
cren arreglos.
Ejemplo. El cubo de las componentes de arreglos numéricos enteros
11.3. ARREGLOS Y FLUJOS DE DATOS 209
Suponga que un archivo contiene unos datos numéricos enteros tales que consta de 5
datos que se encuentran separados por una tabulación ası́ como se muestra a continuación
1 2 3 4 5
Una función general que permite construir un nuevo arreglo que contiene el cubo de
cada componente de un arreglo dado es
#include<iostream>
#include<cstdlib>
#include<fstream>
int main(){
int n = 5;
ifstream ifs("arreglo_numeros.txt");
ofstream ofs("arreglo_cubos.txt");
int* x = crear_arreglo_int(n);
x = leer_arreglo_int(ifs, x, n);
int* y = cubo_componentes_arreglo(x, n);
escribir_arreglo_int(ofs, y, n);
liberar_arreglo_int(x, n);
liberar_arreglo_int(y, n);
ifs.close();
ofs.close();
cout << "El calculo del arreglo fue exitoso" << endl;
system("pause");
return EXIT_SUCCESS;
};
11.3. ARREGLOS Y FLUJOS DE DATOS 211
1 8 27 64 125
Una función recursiva que permite también calcular el cubo de las componentes de un
arreglo mediante la creación de un nuevo arreglo que almacene el resultado del cálculo, y
una función ayudante o auxiliar donde se realiza el cálculo componente a componente y
se hacen los llamados recursivos para recorrer el arreglo original. Estas funciones pueden
ser escritas de la siguiente manera:
Una posible definición teniendo en cuenta las observaciones anteriores y que el segundo
parámetro de la función representa la longitud del arreglo se presenta a continuación
212 CAPÍTULO 11. VECTORES O ARREGLOS UNIDIMENSIONALES
suma arreglo ∶ R∗ × N → R
⎧
⎪
⎪ x1 , si n = 1;
(x, n) ↦ ⎨
⎪
⎩suma arreglo(x, n − 1) + xn , en otro caso.
⎪
Una función en C++ que calcula la suma de las componentes de un arreglo, que está
escrita usando estructuras cı́clicas y que resulta ser equivalente a la anterior es la siguiente
promedio ∶ R∗ × N → R
(x, n) ↦ suma arreglo(x, n)/n;
Una función en C++ que permite calcular el promedio de los datos numéricos almace-
nados en un arreglo de longitud n es
esta ordenado ∶ Z∗ × N → B
⎧
⎪ si n = 1;
⎪
⎪
⎪
V,
(x, n) ↦ ⎨F, si xn−1 > xn ;
⎪
⎪
⎪
⎪
⎩esta ordenado(x, n − 1), en otro caso.
• Si el arreglo tiene una única componente, entonces el máximo del arreglo es igual al
valor de esa componente.
max arreglo ∶ Z∗ × N → Z
⎧
⎪ x1 , si n = 1;
⎪
⎪
⎪
⎪
⎪
⎪M, donde (M = max arreglo(x, n − 1)) ∧
(x, n) ↦ ⎨
⎪
⎪
⎪ (M > xn );
⎪
⎪
⎪
⎪
⎩xn , en otro caso.
Una función en C++ que permite calcular el máximo de un arreglo, que está escrita
usando estructuras cı́clicas y que resulta ser equivalente a la anterior es la siguiente
• Si el arreglo tiene más de una componente, entonces, la posición del máximo se ob-
tiene calculando la posición del máximo del subarreglo que no contiene la última
componente del arreglo original y si al comparar esa componente con última compo-
nente del arreglo original, entonces la posición del mayor será la posición del máximo
del arreglo original.
La codificación en C++ de una función que permite obtener la posición del máximo de
un arreglo de longitud n se presenta a continuación
216 CAPÍTULO 11. VECTORES O ARREGLOS UNIDIMENSIONALES
pos max ∶ Z∗ × N → Z
⎧
⎪ 1, si n = 1;
⎪
⎪
⎪
⎪
⎪
⎪k, donde (k = pos max(x, n − 1)) ∧
(x, n) ↦ ⎨
⎪
⎪
⎪ (xk > xn );
⎪
⎪
⎪
⎪
⎩n, en otro caso.
La codificación en C++ de una función que permite obtener la posición del máximo de
un arreglo de longitud n se presenta a continuación.
Una función en C++ permite obtener la posición del máximo de un arreglo, que está
escrita usando estructuras cı́clicas y que resulta ser equivalente a la anterior es la siguiente
La codificación en C++ de una función que permite obtener un arreglo ordenado as-
cendentemente a partir de un arreglo dado de longitud n se presenta a continuación.
Esta función hace un llamado a la función que permite obtener la posición del máximo
de un arreglo dado y éste se utiliza para intercambiar el elemento mayor a la última
posición, para realizar esto es necesario utilizar una variable adicional o auxiliar t que
se utiliza para almacenar momentáneamente el valor de una de las componentes mientras
ésta cambia su valor por el de la otra componente, y el valor de la otra componente cambia
al valor almacenado en la variable t. Este procedimiento muy común al ordenar arreglos
se conoce en programación como un swap de variables.
ordenar ∶ Z∗ × N → Z∗
⎧
⎪ si n = 1;
⎪
⎪
⎪
x,
(x, n) ↦ ⎨ordenar(x, n − 1), donde (k = pos max(x, n)) ∧
⎪
⎪
⎪
⎪
⎩ (t = xk ) ∧ (xk = xn ) ∧ (xn = t).
La codificación en C++ de una función que permite obtener un arreglo ordenado as-
cendentemente a partir de un arreglo dado de longitud n se presenta a continuación.
11.4. Ejercicios
Nota: para todos los ejercicios que se solicita se solucionen a continuación, la lectura
de los arreglos se deben hacer a partir de un archivo de entrada y si la salida es un arreglo,
este debe ser escrito en un archivo de salida.
9. Modele mediante una función matemática y desarrolle un algoritmo en C++ que cal-
cule la suma de dos vectores de números reales de igual tamaño. Sean
v = (v1 , v2 , . . . , vn ) y w = (w1 , w2 , . . . , wn ) dos vectores, la suma de v y w (nota-
do v + w) es el vector dado por la expresión
v + w = (v1 + w1 , v2 + w2 , . . . , vn + wn )
220 CAPÍTULO 11. VECTORES O ARREGLOS UNIDIMENSIONALES
10. Modele mediante una función matemática y desarrolle un algoritmo en C++ que cal-
cule la resta de dos vectores de números reales de igual tamaño. Sean
v = (v1 , v2 , . . . , vn ) y w = (w1 , w2 , . . . , wn ) dos vectores, la resta de v y w (notado
v − w) es el vector dado por la expresión
v − w = (v1 − w1 , v2 − w2 , . . . , vn − wn )
11. Modele mediante una función matemática y desarrolle un algoritmo en C++ que
calcule el producto punto de dos vectores de números reales de igual tamaño. Sean
v = (v1 , v2 , . . . , vn ) y w = (w1 , w2 , . . . , wn ) dos vectores, el producto punto de v y w
(notado v ⋅ w) es el número dado por la expresión
n
v ⋅ w = ∑ vi wi = v1 w1 + v2 w2 + ⋯ + vn wn
i=1
12. Modele mediante una función matemática y desarrolle un algoritmo en C++ que cal-
cule el producto directo de dos vectores de reales de igual tamaño. Sean
v = (v1 , v2 , . . . , vn ) y w = (w1 , w2 , . . . , wn ) dos vectores, el producto directo de v
y w (notado v ∗ w) es el vector dado por la expresión
v ∗ w = (v1 w1 , v2 w2 , . . . , vn wn )
14. Hacer un algoritmo que deje al final de un arreglo de números enteros todos los ceros
que aparezcan en dicho arreglo.
Ejemplo.
Ejemplo.
arreglo original: [0, 11, 36, 10, 0, 17, -23, 81, 0, 0, 12, 11, 0]
arreglo salida: [11, 36, 10, 17, -23, 81, 12, 11, 0, 0, 0, 0, 0]
15. Suponga que un arreglo de enteros esta lleno de unos y ceros y que el arreglo re-
presenta un número binario al revés. Hacer un algoritmo que calcule los números en
base decimal que representa dicho arreglo de unos y ceros.
Ejemplo.
11.4. EJERCICIOS 221
Ejemplo.
16. Hacer un algoritmo que dado un número entero no negativo, cree un arreglo de unos
y ceros que representa el número en binario al revés.
Ejemplo.
número: 389.
arreglo: [1, 0, 0, 1, 0, 1, 1, 1, 1], que representa el número 111101001.
Ejemplo.
número: 106.
arreglo: [0, 1, 0, 1, 0, 1, 1], que representa el número 1101010.
17. Hacer un algoritmo que calcule el máximo común divisor para un arreglo de enteros
positivos.
Ejemplo.
18. Hacer un algoritmo que calcule el mı́nimo común múltiplo para un arreglo de enteros
positivos.
Ejemplo.
Hasta ahora se ha trabajado con tipos de datos primitivos y arreglos. Entre los tipos
de datos primitivos se encuentran los caracteres que se definieron matemáticamente como
el conjunto ASCII.
Los caracteres ASCII (American Standard Code for Information Interchange) permiten
representar letras, números, sı́mbolos de agrupación, los otros sı́mbolos del teclado y otros
sı́mbolos no visibles.
En un principio se usaron 7 bits para representar los caracteres ASCII con los cuales
se pueden representar 128 diferentes caracteres, y posteriormente se extendieron a 8 bits
223
224 CAPÍTULO 12. CADENAS DE CARACTERES
con los cuales se pueden representar 256 diferentes caracteres. La tabla completa de todos
los sı́mbolos del conjunto ASCII extendido fueron presentados en la sección 5.2.4.
Para especificar que x ∈ ASCII, en C++ se escribe
char x;
para inicializar un carácter se pueden utilizar los literales de carácter, estos son los carac-
teres entre comillas simples.
Ejemplo.
• Comparación de caracteres.
Ejemplo.
Como se vio en la sección 5.2.4, existen también caracteres especiales, para los cuales
se puede conocer su código ASCII haciendo una conversión de carácter a entero, de la
siguiente manera.
Ejemplo.
’h’ ’o’ ’l’ ’a’ ’ ’ ’m’ ’u’ ’n’ ’d’ ’o’ ’\0’
0 1 2 3 4 5 6 7 8 9 10
int n = 10;
char* texto = new char[n];
texto[0] = ’h’;
texto[1] = ’o’;
texto[2] = ’l’;
texto[3] = ’a’;
texto[4] = ’\t’;
texto[5] = ’\0’;
cout << texto;
Ejemplo. En la tabla 12.1 se presentan las longitudes máximas para nombrar archivos
en distintos sistemas operativos, en la longitud no se tiene en cuenta el sı́mbolo de fin de
cadena, ası́ que el arreglo de caracteres base está definido con un tamaño mas uno (+1)
del que se presenta en la tabla 12.1.
Las funciones de creación permiten construir una cadena de forma genérica con base en
lo que se explicó en la sección anterior y en la sección 11.2.1.1 donde se presentó la forma
12.3. FUNCIONES GENERALES SOBRE CADENAS 227
Sistema Longitud
Descripción
operativo de cadena
Unix/Linux 255
MS-DOS 12 8 para el nombre, 3 para la extensión y 1 para el punto.
Windows 260 Cuando hay que especificar el disco de origen (ej. C:\) se
necesitan 3 caracteres, entonces el máximo del nombre y
su ruta completa se reducen a 257.
Mac OS X 256
Tabla 12.1. Longitud de cadena para nombres de archivos en distintos sistemas operativos.
crear arreglo T ∶ N → T∗
(n) ↦ x, donde x ∈ Tn ⊊ T∗
T* crear_arreglo_T(int n){
return new T[n];
};
para el caso de las cadenas se crea un arreglo de datos de tipo char, es decir, para construir
cadenas se utiliza la función
es importante no olvidar que hay que tener en cuenta que si la cadena debe almacenar
a lo más M sı́mbolos, entonces el argumento de la función de la creación de las cadenas
debe ser M + 1, con el fin de tener en cuenta el carácter de fin de cadena (NUL) que todas
las cadenas deben poseer.
228 CAPÍTULO 12. CADENAS DE CARACTERES
Para las cadenas se puede utilizar la misma función, pero se suele descartar la longitud
del arreglo directamente
En estas funciones es donde se encuentra la principal diferencia entre los arreglos usuales
de tipo carácter y las cadenas de caracteres aquı́ estudiadas. En el caso de las cadenas,
a los usuarios no se les pregunta por el tamaño de la cadena, sino que se predefine un
tamaño lo suficientemente grande como para almacenar la cadena más larga con la que
sea necesario trabajar en la aplicación desarrollada. Adicionalmente, tampoco se leerán
los caracteres uno por uno, sino que se leerán en conjunto, esto se hace mediante el uso de
la función getline de la librerı́a iostream, esto es lo realmente interesante de las cadenas
con respecto a los arreglos de enteros o reales.
La lectura de cadenas se puede modelar mediante la siguiente función matemática
12.3. FUNCIONES GENERALES SOBRE CADENAS 229
En este caso el n debe ser pensado previamente, de tal manera que el tamaño sea lo
suficientemente grande como para almacenar cualquier posible información que el usuario
desee guardar. Obsérvese que no se empleó is >> x pues esta instrucción no podrı́a leer
frases ya que por ejemplo, al leer la frase “hola mundo” quedarı́a únicamente almacenada
la subcadena “hola”, por el contrario la función getline leerá el flujo hasta encontrar
un salto de lı́nea o hasta que se alcance el tamaño del arreglo que puede almacenarse en
la cadena creada inicialmente, en este último caso se almacenará el prefijo de la cadena
que contenga los primeros n − 1 sı́mbolos y el sı́mbolo n será el carácter NUL (\0) de fin de
cadena .
Para imprimir una cadena en un flujo si se puede utilizar el operador << sobre flujos
Como se suele operar en cadenas con la información que sea proporcionada por un
usuario es necesario tener una función especial que nos indique cuantos caracteres hay
230 CAPÍTULO 12. CADENAS DE CARACTERES
dentro de una cadena, esto es contar cuantos caracteres hay antes del carácter NUL, cuando
una cadena tiene longitud nula o igual a cero se dice que la cadena es una cadena vacı́a.
Una función que permite calcular la longitud de una cadena, que hace uso de una
función auxiliar recursiva es
Con la función de longitud se pueden definir funciones interesantes tales como copiar
cadena
12.3. FUNCIONES GENERALES SOBRE CADENAS 231
La librerı́a cstdlib contiene dos funciones que son muy útiles y frecuentemente utili-
zadas, que permiten convertir información almacenada como cadenas a números enteros o
reales de acuerdo a su origen. Estas funciones son:
int atoi(char* <integer>): función que abrevia la frase alphabetic to integer (alfabéti-
co a entero) y que permite obtener un número entero a partir de una cadena, en caso
de que la cadena del argumento <integer> no represente un entero entero válido,
entonces se retorna por defecto el valor 0.
double atof(char* <float>): función que abrevia la frase alphabetic to floating point
(alfabético a punto flotante) y que permite obtener un número real a partir de una
cadena, en caso de que la cadena del argumento <float> no represente un número
real válido, entonces se retorna por defecto el valor 0.0.
En el siguiente ejemplo se crean dos cadenas de tamaño máximo igual a 255, luego se
crea una cadena de tamaño máximo igual a 2, a continuación se solicita al usuario que
ingrese su nombre por teclado, este texto se copia a una nueva cadena, después se solicita
al usuario que ingrese su edad como cadena, ésta se convierte a entero mediante el uso
de la función atoi y luego se imprime en la consola tanto el nombre como su respectiva
edad, ası́ que el código completo de cadenas quedarı́a ası́.
Ejemplo.
232 CAPÍTULO 12. CADENAS DE CARACTERES
#include <iostream>
#include <cstdlib>
int main()
{
int n_nombre = 256;
// Crea una cadena de tamano 255
char* str = crear_cadena(n_nombre);
char* str_copia = crear_cadena(n_nombre);
int n_edad = 3;
// Crea una cadena de tamano 2
char* str_edad = crear_cadena(n_edad);
int edad;
system("pause");
return EXIT_SUCCESS;
};
234 CAPÍTULO 12. CADENAS DE CARACTERES
12.4. Ejercicios
1. Elabore un programa que dada una letra cuente cuantas ocurrencias de esta letra
hay.
2. Elabore un programa que dada una cadena diga si todos los sı́mbolos de la cadena
son letras.
3. Elabore un programa que dada una cadena cuente las consonantes en dicha cadena.
4. Desarrollar un algoritmo que retorne un valor booleano que indique si dos cadenas
son iguales, esto es, que tienen la misma longitud con los mismos sı́mbolos en la
mismas posiciones.
6. Desarrollar un algoritmo que invierta una cadena de caracteres (la cadena invertida
debe quedar guardada en una variable aparte).
• “ala” es palindrome
• “anita lava la tina” No es palindrome, pues al invertirla con espacios no es
exactamente igual a la original.
• “los estudiantes de programación leyeron toda la guı́a” no es palindrome.
• “robas ese sabor” es palindrome
⎡1 3 7 −2 8⎤
⎢ ⎥
⎢ ⎥
X = ⎢9 11 5 6 4⎥
⎢ ⎥
⎢6 −2 −1 1 1⎥
⎣ ⎦
columna j
⎡ x11 ⋯ ⋯ x1m ⎤⎥
⎢ x1j
⎢ ⋮ ⋱ ⋮ ⋱ ⋮ ⎥⎥
⎢
⎢ ⎥
⎢ xi1 ⋯ xij ⋯ xim ⎥⎥
fila i ⎢
⎢ ⎥
⎢ ⋮ ⋱ ⋮ ⋱ ⋮ ⎥⎥
⎢
⎢xn1 ⋯ xnj ⋯ xnm ⎥⎦
⎣
Cuando en una matriz se tiene que el número de filas es igual al número de columnas
se dice que la matriz es cuadrada.
V F
X =[ ]
F V
Una forma de entender la estructura interna de una matriz distinta a la definida pre-
viamente, es la de interpretarla como un arreglo de arreglos, esto es, verla como un arreglo
cuyas componentes son a su vez otros arreglos; como se explica a continuación:
⎡ ⎤
⎡ x11 x12 ⋯ x1m ⎤⎥ ⎢ [ x11 x12 ⋯ x1m ] ⎥
⎢ ⎢ ⎥
⎢ ⋮ ⋮ ⋱ ⋮ ⎥⎥ ⎢ ⋮ ⎥
⎢ ⎢ ⎥
⎢ ⎥ ⎢
= ⎢ [ xi1 xi2 ⋯ xim ] ⎥⎥ n
n ⎢ xi1 xi2 ⋯ xim ⎥
⎢ ⎥ ⎢ ⎥
⎢ ⋮ ⋮ ⋱ ⋮ ⎥⎥ ⎢ ⋮ ⎥
⎢ ⎢ ⎥
⎢x ⋯ xnm ⎥⎦ ⎢[ x ⎥
⎣ n1 n2
x ⎢ n1 xn2 ⋯ xnm ]⎥
⎣ ⎦
m
1
T∗ = ⋃ Tm
m∈N
A partir del concepto de arreglo y usando la definición i) de matrices por vectores fila se
puede ahora definir el conjunto de las matrices T∗∗ como la unión de todos los productos
cartesianos del conjunto de los arreglos del conjunto T, de la siguiente manera
n
T∗∗
= ⋃(⋃ Tm )
m∈N
n∈N
El producto externo debe entenderse como un producto cartesiano que genera vectores
columna y que internamente genera vectores fila, ası́ como en la definición i).
Un elemento genérico del conjunto T∗∗ es de la forma (Tm )n , donde n es el número
de filas y m es el número de columnas. Para abreviar, de aquı́ en adelante se utilizará la
notación
(Tm )n ⇔ Tn×m .
Xij ≡ X[i-1][j-1]
ubicada en la posición (n, m), similar a como se manejan las posiciones en notación ma-
temática de matrices, es decir, para acceder en SciLab o MatLab a la variable almacenada
en la componente(i, j) se utiliza la equivalencia
Xij ≡ X[i][j]
Matemáticamente se definirá una rutina para la creación de una matriz de tipo de datos
T como aquella rutina que dado un n ∈ N, que representa el número de componentes del
arreglo columna, y m ∈ N que correspondiente al tamaño del cada arreglo fila, retornará
una matriz de T∗∗ de la siguiente manera
Primero se crea un vector columna de tamaño n y luego por cada componente de éste
se crea y se asigna un vector fila de tamaño m, ası́ como se presenta a continuación:
À Á Â m
[2 2 ⋯ 2] 1
n ⋮ n ⋮
à m Ä m
[2 2 ⋯ 2] [2 2 ⋯ 2]
2
[2 2 ⋯ 2] [2 2 ⋯ 2] n−2
n ⋮ n ⋮ ⋮
240 CAPÍTULO 13. MATRICES O ARREGLOS BIDIMENSIONALES
Å m Æ m
[2 2 ⋯ 2] [2 2 ⋯ 2]
[2 2 ⋯ 2] [2 2 ⋯ 2]
n−1
n ⋮ ⋮ n ⋮ ⋮ n
[2 2 ⋯ 2] [2 2 ⋯ 2]
[2 2 ⋯ 2]
Ejemplo. Para crear una matriz de tipo entero se tiene la siguiente función
Para eliminar una matriz, ası́ como en el caso de los arreglos, se debe entender que lo
que ocurre es que la porción del espacio de la memoria que se utiliza para almacenar los
arreglos fila de la matriz se regresan al sistema operativo para que este disponga de esa
memoria para almacenar nueva información.
Matemáticamente se puede modelar esto como una función que dada la matriz X, junto
con el número de filas n y el número de columnas m (aunque este último no se requiere,
pero se suele utilizar), se retorna la porción del espacio de la memoria MX , que es utilizado
para almacenar la matriz X. De esta manera la función se puede escribir ası́
13.3. LAS MATRICES EN COMPUTACIÓN 241
La liberación de la matriz se puede hacer liberando cada uno de los arreglos fila que
conforman la matriz y por último se elimina el arreglo columna, ası́ como se presenta a
continuación:
À Á
[2 2 ⋯ 2]
[2 2 ⋯ 2] [2 2 ⋯ 2]
n ⋮ ⋮ n n ⋮ ⋮
n−1
[2 2 ⋯ 2] [2 2 ⋯ 2]
[2 2 ⋯ 2] [2 2 ⋯ 2]
m m
 Ã
n ⋮ ⋮ n ⋮
[2 2 ⋯ 2] n−2 [2 2 ⋯ 2] 2
[2 2 ⋯ 2] [2 2 ⋯ 2]
m m
Ä Å Æ
n ⋮ n ⋮
[2 2 ⋯ 2] 1
m
Para traducir la anterior función a C++ se debe tener en cuenta que la función no
retorna un valor de un tipo de datos, si no que se regresa memoria al sistema operativo,
por lo que la función regresa un espacio que esta vacı́o y listo para utilizarse de nuevo.
El desbloqueo de la memoria y la liberación del espacio utilizado por cada uno de los
arreglos fila Xi se escribe en C++ mediante la instrucción
242 CAPÍTULO 13. MATRICES O ARREGLOS BIDIMENSIONALES
delete[] X[i];
Luego de liberar cada uno de los arreglos fila se debe liberar el arreglo columna que los
contenı́a, esto se escribe en C++ mediante la instrucción
delete[] X;
Al igual que en el caso de los arreglos, para decir que se retorna memoria vacı́a, en C++
esto se escribe como void y en el cuerpo de la función se utiliza la instrucción return;
para indicar que se retorno una porción de espacio que esta vació y que queda listo para
usarse de nuevo.
De esta manera, la traducción de la función en C++ se escribe de la siguiente manera
Dada una matriz de tipo T, es posible realizar operaciones de lectura y escritura sobre
flujos de datos, y dichas operaciones se realizan de la siguiente manera:
Lectura de matrices: para la entrada o lectura de una matriz desde un flujo de datos,
se puede utilizar la siguiente función
En C++ se traduce ası́ (como se mencionó previamente, las matrices en C++ comienzan
en la posición (0, 0))
1 2
2
2 2
3 3
5 5
n = 2, m = 3, n = 2, m = 3,
21 13 8 21 13 8 i = 0, j = 0
3 4
2 3 2 3 5
3 5
5 8
8 13
n = 2, m = 3, n = 2, m = 3,
21 13 i = 0, j = 1 21 i = 0, j = 2
5 6
2 3 5 2 3 5
8 8
13 13 8
21 21
n = 2, m = 3, n = 2, m = 3,
i = 0, j = 3 i = 1, j = 0
244 CAPÍTULO 13. MATRICES O ARREGLOS BIDIMENSIONALES
7 8
2 3 5 2 3 5
13 21
21 8 13 8 13 21
n = 2, m = 3, n = 2, m = 3,
i = 1, j = 1 i = 1, j = 2
9 10
2 3 5 2 3 5
8 13 21 8 13 21
n = 2, m = 3, n = 2, m = 3,
i = 1, j = 3 i = 2, j = 3
Escritura de matrices: para enviar o escribir una matriz en un flujo de datos, se puede
definir la siguiente función
Ejemplo. En C++ para escribir una matriz de tipo entero se utiliza la siguiente función
13.3. LAS MATRICES EN COMPUTACIÓN 245
2
1
2 3 5 2 3 5
8 13 21 8 13 21
n = 2, m = 3, n = 2, m = 3, 2 ↵
↵
i = 0, j = 0
3 4
2 3 5 2 3 5
8 13 21 8 13 21
n = 2, m = 3, 2 ↵ n = 2, m = 3, 3 2 ↵
i = 0, j = 0 i = 0, j = 1
5 6
2 3 5 2 3 5
8 13 21 8 13 21 ↵
↵ 2
n = 2, m = 3, 3 2 n = 2, m = 3, 5 3
i = 0, j = 1 i = 0, j = 2
7 8
2 3 5 2 3 5
8 13 21 ↵ 2
8 13 21 ↵ 2
3
n = 2, m = 3, ↵ 5 3 n = 2, m = 3, 8 ↵ 5
i = 0, j = 3 i = 1, j = 0
246 CAPÍTULO 13. MATRICES O ARREGLOS BIDIMENSIONALES
9 10
2 3 5 2 3 5
↵
8 13 21 ↵ 2 3
8 13 21 2 3
5
n = 2, m = 3, 8 ↵ 5 n = 2, m = 3, 13 8 ↵
i = 1, j = 0 i = 1, j = 1
11 12
2 3 5 ↵ 2 3 5 2 ↵
2
8 13 21 3 5
8 13 21 3 5 ↵
↵ 8
n = 2, m = 3, 13 8 n = 2, m = 3, 21 13
i = 1, j = 1 i = 1, j = 2
13 14
2 3 5 2 ↵ 2 3 5 2 ↵
3 3
8 13 21 5 ↵ 8
8 13 21 5 ↵ 8
n = 2, m = 3, ↵ 21 13 n = 2, m = 3, ↵ 21 13
i = 1, j = 3 i = 2, j = 3
15
↵
2 3 5 ↵ 2 3 5
8 13 21 ↵ 8 13 21
Es posible utilizar lo visto en funciones para realizar diversidad de cálculos que involu-
cren matrices.
Suponga que un archivo contiene unos datos numéricos enteros tales que consta de 5
lı́neas de texto y en cada lı́nea hay dos números escritos que se encuentran separados por
una tabulación ası́ como se muestra a continuación
13.3. LAS MATRICES EN COMPUTACIÓN 247
0 1
2 3
4 5
6 7
8 9
Una función general que permite construir una nueva matriz que contiene el cuadrado
de cada componente de una matriz dada es
#include<iostream>
#include<cstdlib>
#include<fstream>
int main(){
int n = 5;
int m = 2;
ifstream ifs("matriz_numeros.txt");
ofstream ofs("matriz_cuadrados.txt");
int** X = crear_matriz_int(n, m);
X = leer_matriz_int(ifs, X, n, m);
int** Y = cuadrado_componentes_matriz(X, n, m);
escribir_matriz_int(ofs, Y, n, m);
liberar_matriz_int(X, n, m);
liberar_matriz_int(Y, n, m);
ifs.close();
ofs.close();
cout << "El calculo de la matriz fue exitoso" << endl;
system("pause");
return EXIT_SUCCESS;
};
0 1
4 9
16 25
36 49
64 81
Ejemplo. Tablas de multiplicar
Se puede generar una matriz que represente las tablas de multiplicar multiplicando cada
posición (i, j) de la matriz y almacenándola en la matriz:
En C++:
Ejemplo. Determinantes 2 × 2
Dado un sistema de ecuaciones de dos ecuaciones con dos incógnitas
ax + by = c
a x + b′ y = c ′
′
a b x c
[ ′ ′] [ ] = [ ′]
a b y c
ax0 + by0 = c y a′ x 0 + b ′ y 0 = c ′ .
det 2 2 ∶ Z2×2 → Z
X ↦ X11 ∗ X22 − X21 ∗ X12
En C++:
Una de los operaciones básicas sobre las matrices es el producto escalar. En éste se elige
un valor sobre un conjunto numérico (por ejemplo los enteros Z) y se multiplica este valor
por cada componente de la matriz.
⎡ x11 x12 ⋯ x1m ⎤
⎢ ⎥
⎢x ⎥
⎢ 21 x22 ⋯ x2m ⎥
Ası́, si α ∈ Z y X = ⎢ ⎥
⎢ ⋮ ⋮ ⋱ ⋮ ⎥⎥
⎢
⎢xn1 xn2 ⋯ xnm ⎥
⎣ ⎦
entonces
⎡ x11 x12 ⋯ x1m ⎤⎥ ⎡⎢ α ⋅ x11 α ⋅ x12 ⋯ α ⋅ x1m ⎤⎥
⎢
⎢x ⋯ x2m ⎥⎥ ⎢⎢ α ⋅ x21 α ⋅ x22 ⋯ α ⋅ x2m ⎥⎥
⎢ x22
Y = α ∗ X = α ∗ ⎢ 21 ⎥=⎢ ⎥
⎢ ⋮ ⋮ ⋱ ⋮ ⎥⎥ ⎢⎢ ⋮ ⋮ ⋱ ⋮ ⎥⎥
⎢
⎢xn1 xn2 ⋯ xnm ⎥⎦ ⎢⎣α ⋅ xn1 α ⋅ xn2 ⋯ α ⋅ xnm ⎥⎦
⎣
13.3. LAS MATRICES EN COMPUTACIÓN 251
En C++:
13.4. Ejercicios
6. Desarrollar un programa que sume los elementos de una columna dada de una matriz.
7. Desarrollar un programa que sume los elementos de una fila dada de una matriz.
10. Desarrollar un algoritmo que permita multiplicar dos matrices de números reales.
11. Desarrollar un algoritmo que determine si una matriz es mágica. Se dice que una
matriz cuadrada es mágica si la suma de cada una de sus filas, de cada una de sus
columnas y de cada diagonal es igual. Ejemplo:
⎡8 1 6⎤
⎢ ⎥
⎢ ⎥
⎢3 5 7⎥
⎢ ⎥
⎢4 9 2⎥
⎣ ⎦
12. Desarrollar un algoritmo que dado un entero, reemplace en una matriz todos los
números mayores al número dado por un uno y todos los menores o iguales por un
cero.
Si el número dado es: 5 y una matriz en el arreglo es:
⎡8 1 6⎤
⎢ ⎥
⎢ ⎥
⎢3 5 7⎥
⎢ ⎥
⎢4 9 2⎥
⎣ ⎦
La matriz de salida es:
⎡1 0 1⎤
⎢ ⎥
⎢ ⎥
⎢0 0 1⎥
⎢ ⎥
⎢0 1 0⎥
⎣ ⎦
13.4. EJERCICIOS 253
13. Desarrollar un programa que genere una matriz marco cuadrada de tamaño n × n.
Entrada: n = 3
⎡1 1 1⎤
⎢ ⎥
⎢ ⎥
⎢1 0 1⎥
⎢ ⎥
⎢1 1 1⎥
⎣ ⎦
14. Desarrollar un programa que tome un arreglo de tamaño n2 y llene en espiral hacia
adentro una matriz cuadrada de tamaño n.
Ejemplo: arreglo de entrada: [1, 2, 3, 4, 5, 6, 7, 8, 9], la matriz de salida es:
⎡1 2 3⎤
⎢ ⎥
⎢ ⎥
⎢8 9 4⎥
⎢ ⎥
⎢7 6 5⎥
⎣ ⎦
16. Desarrollar un algoritmo que permita hallar la matriz inversa de una matriz cuadra-
da, si ésta existe.
17. Desarrollar un algoritmo que permita calcular el determinante de una matriz cua-
drada, usando el teorema de Laplace (desarrollo por menores y cofactores).
254 CAPÍTULO 13. MATRICES O ARREGLOS BIDIMENSIONALES
Bibliografı́a
Böhm, C. & Jacopini, G. [1966]. Flow Diagrams, Turing Machines and Languages with
only Two Formation Rules, Comm. of the ACM 9(5): 366–371.
Deitel, H. M. & Deitel, P. J. [2004]. Cómo programar en C, C++ y Java, Pearson Educa-
ción.
Kolman, B., Busby, R. C. & Ross, S. [1997]. Estructuras de matemáticas discretas para la
computación, Pearson educación, Prentice-Hall Hispanoamericana.
Savitch, W. A. [2000]. Resolucion de problemas Con C++, 2nd edn, Pearson Educación,
México.