Você está na página 1de 135

Tec. Sup.

Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

PRLOGO
La presente obra se diseo principalmente como un texto de referencia para los
estudiantes de Ingeniera de Sistemas e Informtica de la Universidad Privada de
Oruro, que necesitan de una gua prctica, proporcionndole informacin rpida y
objetiva sobre la metodologa a seguir en la codificacin de programas en C++ y la
Estructura de Datos.

El lenguaje seleccionado en el presente texto es C++ con el editor llamado

Code::Blocks 10.05, un

lenguaje bsico y nada complejo en su comprensin y

utilizacin.

La Obra presente diversos problemas los mismos que han sido seleccionados no
tanto por su utilidad prctica en el campo de la solucin de problemas, sino por la forma y
complejidad que estos despliegan en el proceso de codificacin.

El texto cuenta con problemas que van desde lo ms bsico hasta los ms
complejos para que el programador pueda asimilar tanto el diseo de los problemas
codificados en forma gradual y sistemtica

El texto tambin cuenta con un CD interactivo en el cual se encuentran los


problemas codificados y el instalador del Editor Code::Blocks 10.05. Para que el
estudiante pueda verificar y comprar que los problemas son exactamente iguales a los
que aparecen en el texto.

10

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

11

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

1. DECLARACION DE UNA VARIABLE


Una caracterstica de C++, es la necesidad de declarar las variables que se usarn en un programa.
Esto resulta chocante para los que se aproximan al C++ desde otros lenguajes de programacin
en los que las variables de crean automticamente la primera vez que se usan.
Se trata, es cierto, de una caracterstica de bajo nivel, ms cercana al ensamblador que a
lenguajes de alto nivel, pero en realidad una caracterstica muy importante y til de C++, ya que
ayuda a conseguir cdigos ms compactos y eficaces, y contribuye a facilitar la depuracin y la
deteccin y correccin de errores y a mantener un estilo de programacin elegante.
Uno de los errores ms comunes en lenguajes en los que las variables se crean de forma
automtica se produce al cometer errores ortogrficos. Por ejemplo, en un programa usamos una
variable llamada prueba, y en un punto determinado le asignamos un nuevo valor, pero nos
equivocamos y escribimos prubea. El compilador o intrprete no detecta el error, simplemente
crea una nueva variable, y contina como si todo estuviese bien.
En C++ esto no puede pasar, ya que antes de usar cualquier variable es necesario declararla, y si
por error usamos una variable que no ha sido declarada, se producir un error de compilacin.
1.1 QUE ES UNA VARIABLE?
Es un nombre que representa el valor de un dato. Es una zona o posicin de memoria en la
computadora donde se almacena informacin. Un objeto de datos que el programador define y
nombra explcitamente en un programa. Una variable simple es un objeto elemental de datos con
nombre. El valor o valores de una variable es modificable por operaciones de asignacin; es decir,
el enlace de objeto de datos a valor puede cambiar durante su tiempo de vida. Las operaciones
que se pueden realizar con dos o ms valores exigen que stas sean del mismo tipo de datos. No
se puede sumar una variable carcter a otra numrica y/o viceversa.
1.2 TIPOS DE VARIABLES EN C++
Todos los programas gestionan algunos tipos de informacin que normalmente se pueden
representar utilizando uno de los ocho (8) tipos de datos bsicos de C y C++: texto o char, valores
enteros o int, valores de coma flotante o float, valores en coma flotante de doble precisin o
double (long double), enumerados o enum, sin valor o void, punteros y booleanos.
Int: El tipo de dato int, tiene un tamao de 32 bits y un rango entre -2.147.483.648 y 2.147.483.647.
Este tipo de dato, es usado para nmeros enteros (sin cifras decimales). A continuacin alguna de sus
combinaciones con los modificadores:

short int:

Tiene un tamao de 16 bits y un rango entre -32.768 y 32.767.

unsigned short int:

Tiene un tamao de 16 bits y un rango entre 0 y 65.535.

unsigned int:

Tiene un tamao de 32 bits y un rango entre 0 y 4.294.967.295.

long long int:

Tiene un tamao de 64 bits y un rango entre -9.223.372.775.808 y 9.223.375.775.807.

unsigned long long int:

Tiene un tamao de 64 bits y un rango entre 0 y 18.446.744.073.709.551.615.

12

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

float: El tipo de dato float, tiene un tamao de 32 bits, es usado comnmente en nmeros con 6
o menos cifras decimales. Tiene un rango entre 1.17549 e-38 hasta 3.40282 e+38.
double: El tipo de dato double, tiene un tamao de 64 bits, es usado para nmeros de menos de
15 cifras decimales. Tiene un rango entre 2.22507 e-308 hasta 1.79769 e+308.
long double: Tiene un tamao de 96 bits y una precisin de 18 cifras decimales. Tiene un rango
entre 3.3621 e-4932 hasta 1.18973 e+4932.
bool: El tipo de dato bool, tiene un tamao de 8 bits y un rango entre 0 y 1, en pocas palabras es
cero o es uno (falso o verdadero). Este tipo de dato, es comnmente usado en condicionales o
variables al que se le puede asignar las constantes true (verdadero) y false (falso).

char: Esta constituido por caracteres simples, como (a-z / A-Z / 0-9) y cadenas, como Esto es una
prueba (normalmente, de 8 bits o un byte por carcter, con un rango de 0 a 255).
Las variables del tipo char, son digamos las variables problema del lenguaje C y C++, puesto que
tienen una gran cantidad de restricciones y complicaciones, bastante molestas. Las variables de
tipo char, en C y C++ son consideradas vectores y como quiz sabrs a los vectores se les debe
declarar un tamao mximo, entre corchetes [ ] lo cual restringe un poco al momento de no
saber que tamao podra llegar a tener una cadena de caracteres, y aunque hay formas de evadir
esto, es bastante complicado, desde mi punto de vista personal recomiendo las variables de tipo
string para las cadenas de caracteres, estas estn incluidas en la librera #include <string.h> y son
bastante fciles de usar y muy flexibles a diferencia de los char. Muy bien, de igual forma pondr
como se debe declarar un char y ms abajo mencionare algunas otras molestias que este tipo de
dato genera, pero explicare como se arreglan.
Muy bien, la sintaxis es la siguiente:
char nombre_char [tamao_max];
Tambin es vlido y solo es vlido de esta forma la asignacin por medio del signo = para un
char y es as:
char char_nombre [tamao_max] = cadena;
Muy bien, como veras aqu lo nico que hay extrao es lo del [tamao_max], pues bien, ah se
debe poner un numero entero que no cambia es decir constante que nos indica el tamao
mximo que tendr nuestra cadena de caracteres, si nos pasamos de ese nmero, tendremos
problemas, as que recomiendo poner nmeros grandes si no se sabe el tamao que podra tener,
pero bueno, esto nos podra desperdiciar memoria y recursos o todo lo contrario, nos podran
quedar faltando.

13

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

void: El tipo void, se utiliza para especificar valores que ocupan 0 bits y no tienen valor (este tipo
tambin se puede utilizar para la creacin de punteros genricos).
puntero: El tipo de dato puntero, no contiene informacin en el mismo sentido que el resto de
los tipos de datos; en su lugar, cada puntero contiene la direccin de la posicin de memoria que
almacena el dato actual.
1.3 CMO SE DECLARA UNA VARIABLE EN C++?
El sistema es siempre el mismo, primero se especifica el tipo y a continuacin una lista de
variables y finalmente un punto y coma.
La declaracin de variables es uno de los tipos de sentencia de C++.
La prueba ms clara de esto es que la declaracin terminar con un ";".
Sintaxis:
<tipo> <lista de variables>;

Tambin es posible inicializar las variables dentro de la misma declaracin.


Por ejemplo:
int a = 1234;
bool seguir = true, encontrado;

Declarara las variables a, seguir y encontrado; y adems iniciara los valores de a y seguir con
los valores 1234 y true, respectivamente.
1.4 REGLAS PARA LA DECLARACION DE VARIABLES
Bien pues, ya sabemos que en la programacin tenemos que estar muy atentos a la
sintaxis (Estructura de una Palabra), pues es importantsimo, ya que si no est bien escrito un
comando, no va a funcionar esa lnea en el cdigo del programa y peor an, si esa lnea est
ligada a las lneas de ms adelante pues no funcionar ni sta ni las de ms adelante (Como una
Cadena). Entonces les dir algunas reglas para la declaracin de variables, cuando veamos un
lenguaje de programacin especifico colocar la sintaxis de sus comandos ya que las sintaxis
cambia (La lgica no, sea cambian las palabras pero la forma de realizar el ejercicio sigue
siendo la misma), porque cada lenguaje tiene su dialecto. Comencemos:

14

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Regla 1:
Tener el mismo nombre que una palabra reservada del lenguaje.
Explicacin: Los lenguajes de programacin tienen palabras reservadas, sea que esas palabras
solo pueden ser usadas por el programa, por eso llevan el nombre de reservadas, pues si
supongamos el caso de que un lenguaje de programacin X tiene sus palabras reservadas entre
las cuales est: ingresar, entonces eso quiere decir que el usuario NO debe declarar una
variable con el nombre ingresar, porque va a tener conflictos ms adelante.

Regla 2:
Slo pueden ser letras, dgitos y el guin bajo subguin. Adems debe tener no ms de 40
caracteres.
Explicacin: Pues en los lenguajes de programacin hay sintaxis que deben cumplirse al pie de la
letra, entonces dice que las variables solo pueden llevar letras, nmeros y el subguin.

Ejemplo:
La siguiente variable est bien declarada: programando19
La siguiente variable est mal declarada:

%&programando-19

Vemos que insert caracteres especiales, adems de que uso el guin normal (no el subguin),
por lo tanto puede que el programa entienda que es una resta, entonces est mal declarado
por sintaxis.

Regla 3:
Deben comenzar por un carcter (letra).
Explicacin: Por sintaxis como ya hemos visto, deben cumplir con estas reglas, entonces no se
puede comenzar con un nmero, ya que se debe comenzar por una letra como dice la regla.
Ejemplo:
La siguiente variable est bien declarada: pasoApaso
La siguiente variable est mal declarada:

89pasos

Regla 4:
Deben iniciar con un carcter (no numero) como vimos en la Regla 3, y tambin puede comenzar
con un guin bajo (_).

15

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Ejemplo:
La siguiente variable est bien declarada: _descuento
La siguiente variable est mal declarada:

-descuento

La siguiente variable est mal declarada:

descuento-

Regla 5:
No se les pueden asignar espacios en blanco.
Explicacin: Las variables no pueden llevar espacios en blanco, solo pueden ser separadas por un
signo dedicado a ser usado como un espacio, el cual es el subguin (_), entonces en una variable
cuando vean un subguin, prcticamente estn separando algo (para que no parezca una
ensalada).
Ejemplo:
La siguiente variable est bien declarada: eddy_19
La siguiente variable est mal declarada:

eddy 19

Regla 6:
No pueden llevar acento (tilde).
Ejemplo:
La siguiente variable est bien declarada: numero
La siguiente variable est mal declarada:

nmero

Esas son las Reglas Base, para la buena declaracin de variables.


1.5 PALABRAS CLAVE DEL C++
En C++, como en cualquier otro lenguaje, existen una serie de palabras clave (keywords) que el
usuario no puede utilizar como identificadores (nombres de variables y/o de funciones). Estas
palabras sirven para indicar al computador que realice una tarea muy determinada (desde
evaluar una comparacin, hasta definir el tipo de una variable) y tienen un especial significado
para el compilador. El C++ es un lenguaje muy conciso, con muchas menos palabras clave que
otros lenguajes. A continuacin se presenta la lista de las 32 palabras clave del ANSI C, para las
que ms adelante se dar detalle de su significado (algunos compiladores aaden otras palabras
clave, propias de cada uno de ellos. Es importante evitarlas como identificadores):

16

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

auto

double

int

struct

break

else

long

switch

case

e num

register

typedef

char

extern

return

union

const

float

short

unsigned

continue

for

signed

void

default

goto

sizeof

volatile

do

if

static

while

2. ENTRADA Y SALIDA DE DATOS


Cuando nos referimos a entrada/salida estndar (E/S estndar) queremos decir que los datos o
bien se estn leyendo del teclado, bien se estn escribiendo en el monitor de video. Como se
utilizan muy frecuentemente se consideran como los dispositivos de E/S por default y no
necesitan ser nombrados en las instrucciones de E/S.
En el lenguaje C++ tenemos varias alternativas para ingresar y/o mostrar datos, dependiendo de
la librera que vamos a utilizar para desarrollar el programa, entre estas estn: <iostream> y
<cstdio>.
< IOSTREAM>
Las operaciones de entrada y salida no forman parte del conjunto de sentencias de C++, sino que
pertenecen al conjunto de funciones y clases de la biblioteca estndar de C++. Ellas se incluyen en
los archivos de cabecera <iostream> por lo que siempre que queramos utilizarlas deberemos
introducir la lnea de cdigo:
#include <iostream>.
Esta biblioteca es una implementacin orientada a objetos y est basada en el concepto de flujos.
A nivel abstracto un flujo es un medio de describir la secuencia de datos de una fuente a un
destino o sumidero. As, por ejemplo, cuando se introducen caracteres desde el teclado, se puede
pensar en caracteres que fluyen o se trasladan desde el teclado a las estructuras de datos del
programa.
Los objetos de flujo que vienen predefinidos sern:
cin, que toma caracteres de la entrada estndar (teclado);
cout, pone caracteres en la salida estndar (pantalla);
cerr y clog, ponen mensajes de error en la salida estndar.

17

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Estos objetos se utilizan mediante los operadores << y >>. El operador << se denomina operador
de insercin; y apunta al objeto donde tiene que enviar la informacin. Por lo tanto la sintaxis de
cout ser:
cout<<variable1<<variable2<<.........<<variableN;

No olvidemos que las cadenas de texto son variables y se ponen entre " " (comillas dobles).
Por su parte >> se denomina operador de extraccin, lee informacin del flujo cin (a la izquierda
del operador) y las almacena en las variables indicadas a la derecha).
La sintaxis sera la siguiente:
cin>>variable1>>variable2>>.....>>variableN;

Un ejemplo de cdigo utilizando ambos objetos podra ser el siguiente:


#include <iostream>
using namespace std;
int main ()
{
int num;
cout<<"Introduce un nmero: ";
cin>>num;
cout<<"Usted introdujo: "<<num;
return 0;
}

Que mostrara por pantalla la frase "Introduce un nmero" y posteriormente almacenara el valor
introducido por teclado en la variable num, para luego mostrar por pantalla la frase Usted
introdujo: , seguidamente del dato almacenado en la variable num.
3. OPERADORES, EXPRESIONES Y SENTENCIAS.
3.1 OPERADORES.

Un operador es un carcter o grupo de caracteres que acta sobre una, dos o ms variables para
realizar una determinada operacin con un determinado resultado. Ejemplos tpicos de
operadores son la suma (+), la diferencia (-), el producto (*), etc. Los operadores pueden ser
unarios, binarios y ternarios, segn acten sobre uno, dos o tres operandos, respectivamente. En
C++ existen muchos operadores de diversos tipos (ste es uno de los puntos fuertes del lenguaje),
que se vern a continuacin.
3.1.1 OPERADORES ARITMTICOS
Los operadores aritmticos son los ms sencillos de entender y de utilizar. Todos ellos son
operadores binarios. En C++ se utilizan los cinco operadores siguientes:

18

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Suma: +
Resta: Multiplicacin: *
Divisin: /
Modulo: %

Todos estos operadores se pueden aplicar a constantes, variables y expresiones. El resultado es el


que se obtiene de aplicar la operacin correspondiente entre los dos operandos. El nico
operador que requiere una explicacin adicional es el operador modulo %. En realidad su nombre
completo es resto de la divisin entera. Este operador se aplica solamente a constantes, variables
o expresiones de tipo int. Aclarado esto, su significado es evidente: 23 % 4 es 3, puesto que el
resto de dividir 23 por 4 es 3. Si a % b es cero, a es mltiplo de b.
Como se ver ms adelante, una expresin es un conjunto de variables y constantes y tambin de
otras expresiones ms sencillas relacionadas mediante distintos operadores. Un ejemplo de
expresin en la que intervienen operadores aritmticos es el siguiente polinomio de grado 2 en la
variable x:
5.0 + 3.0*x - x*x/2.0
Las expresiones pueden contener parntesis (...) que agrupan a algunos de sus trminos.
Puede haber parntesis contenidos dentro de otros parntesis. El significado de los parntesis
coincide con el habitual en las expresiones matemticas, con algunas caractersticas importantes
que se vern ms adelante. En ocasiones, la introduccin de espacios en blanco mejora la
legibilidad de las expresiones.
3.1.2 OPERADORES DE ASIGNACIN
Los operadores de asignacin atribuyen a una variable es decir, depositan en la zona de memoria
correspondiente a dicha variable el resultado de una expresin o el valor de otra variable (en
realidad, una variable es un caso particular de una expresin).
El operador de asignacin ms utilizado es el operador de igualdad (=), que no debe ser
confundido con la igualdad matemtica. Su forma general es:
nombre_de_variable = expresion;

cuyo funcionamiento es como sigue: se evala expresin y el resultado se deposita en


nombre_de_variable, sustituyendo cualquier otro valor que hubiera en esa posicin de memoria
anteriormente. Una posible utilizacin de este operador es como sigue:
variable = variable + 1;

19

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Desde el punto de vista matemtico este ejemplo no tiene sentido (Equivale a 0 = 1!), pero s lo
tiene considerando que en realidad el operador de asignacin (=) representa una sustitucin; en
efecto, se toma el valor de variable contenido en la memoria, se le suma una unidad y el valor
resultante vuelve a depositarse en memoria en la zona correspondiente al identificador variable,
sustituyendo al valor que haba anteriormente. El resultado ha sido incrementar el valor de
variable en una unidad.
As pues, una variable puede aparecer a la izquierda y a la derecha del operador (=). Sin embargo,
a la izquierda del operador de asignacin (=) no puede haber nunca una expresin:
Tiene que ser necesariamente el nombre de una variable. Es incorrecto, por tanto, escribir algo
as como:
a + b = c; // incorrecto
Existen otros cuatro operadores de asignacin (+=, -=, *= y /=) formados por los cuatro
operadores aritmticos seguidos por el carcter de igualdad. Estos operadores simplifican algunas
operaciones recurrentes sobre una misma variable. Su forma general es:
variable op= expresion;
Donde op representa cualquiera de los operadores (+ - * /). La expresin anterior es
equivalente a:
variable = variable op expresion;
A continuacin se presentan algunos ejemplos con estos operadores de asignacin:
distancia += 1;
rango /= 2.0
x *= 3.0 * y - 1.0

equivale a:
equivale a:
equivale a:

distancia = distancia + 1;
rango = rango /2.0
x = x * (3.0 * y - 1.0)

3.1.3 OPERADORES INCREMENTALES


Los operadores incrementales (++) y (--) son operadores unarios que incrementan o disminuyen
en una unidad el valor de la variable a la que afectan. Estos operadores pueden ir
inmediatamente delante o detrs de la variable. Si preceden a la variable, sta es incrementada
antes de que el valor de dicha variable sea utilizado en la expresin en la que aparece. Si es la
variable la que precede al operador, la variable es incrementada despus de ser utilizada en la
expresin. A continuacin se presenta un ejemplo de estos operadores:
i = 2;
j = 2;
m = i++; // despus de ejecutarse esta sentencia m=2 e
i=3
n = ++j; // despus de ejecutarse esta sentencia
n=3
y
j=3
Estos operadores son muy utilizados. Es importante entender muy bien por qu los resultados m
y n del ejemplo anterior son diferentes.

20

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

3.1.4 OPERADORES RELACIONALES


Este es un apartado especialmente importante para todas aquellas personas sin experiencia en
programacin. Una caracterstica imprescindible de cualquier lenguaje de programacin es la de
considerar alternativas, esto es, la de proceder de un modo u otro segn se cumplan o no ciertas
condiciones. Los operadores relacionales permiten estudiar si se cumplen o no esas condiciones.
As pues, estos operadores producen un resultado u otro segn se cumplan o no algunas
condiciones que se vern a continuacin.
En el lenguaje natural, existen varias palabras o formas de indicar si se cumple o no una
determinada condicin. En ingls estas formas son (yes, no); (on, off); (true, false), etc. En
Informtica se ha hecho bastante general el utilizar la ltima de las formas citadas: (true, false). Si
una condicin se cumple, el resultado es true; en caso contrario, el resultado es false.
En C++ un 0 representa la condicin de false, y cualquier nmero distinto de 0 equivale a la
condicin true. Cuando el resultado de una expresin es true y hay que asignar un valor
concreto distinto de cero, por defecto se toma un valor unidad. Los operadores relacionales de
C++ son los siguientes:
Igual que: ==
Menor que: <
Mayor que: >
Menor o igual que: <=
Mayor o igual que: >=
Distinto que: !=
Todos los operadores relacionales son operadores binarios (tienen dos operandos), y su forma
general es la siguiente:
expresion1 op expresion2
Donde op es uno de los operadores (==, <, >, <=, >=, !=). El funcionamiento de estos operadores
es el siguiente: se evalan expresion1 y expresion2, y se comparan los valores resultantes. Si la
condicin representada por el operador relacional se cumple, el resultado es 1; si la condicin
no se cumple, el resultado es 0.
A continuacin se incluyen algunos ejemplos de estos operadores aplicados a constantes:
(2==1)
(3<=3)
(3<3)
(1!=1)

// Resultado=0 porque la condicin no se cumple


// Resultado=1 porque la condicin se cumple
// Resultado=0 porque la condicin no se cumple
// Resultado=0 porque la condicin no se cumple

3.1.5 OPERADORES LGICOS


Los operadores lgicos son operadores binarios que permiten combinar los resultados de los
operadores relacionales, comprobando que se cumplen simultneamente varias condiciones, que
se cumple una u otra, etc. El lenguaje C tiene dos operadores lgicos: el operador Y (&&) y el
operador O (||). En ingls son los operadores and y or.
Su forma general es la siguiente:

21

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

expresion1 || expresion2
expresion1 && expresion2
El operador && devuelve un 1 si tanto expresion1 como expresion2 son verdaderas (o distintas
de 0), y 0 en caso contrario, es decir si una de las dos expresiones o las dos son falsas (iguales
a 0); por otra parte, el operador || devuelve 1 si al menos una de las expresiones es cierta. Es
importante tener en cuenta que los compiladores de C++ tratan de optimizar la ejecucin de
estas expresiones, lo cual puede tener a veces efectos no deseados. Por ejemplo:
Para que el resultado del operador && sea verdadero, ambas expresiones tienen que ser
verdaderas; si se evala expresion1 y es falsa, ya no hace falta evaluar expresion2, y de hecho no
se evala. Algo parecido pasa con el operador ||: si expresion1 es verdadera, ya no hace falta
evaluar expresion2.
Los operadores && y || se pueden combinar entre s quizs agrupados entre parntesis, dando
a veces un cdigo de ms difcil interpretacin. Por ejemplo:
(2==1) || (-1==-1)
(2==2) && (3==-1)
((2==2) && (3==3)) || (4==0)
((6==6) || (8==0)) && ((5==5) && (3==2))

// el resultado es 1
// el resultado es 0
// el resultado es 1
// el resultado es 0

3.1.6 OTROS OPERADORES


Adems de los operadores vistos hasta ahora, el lenguaje C dispone de otros operadores. En esta
seccin se describen algunos operadores unarios adicionales.
Operador menos ().
El efecto de este operador en una expresin es cambiar el signo de la variable o expresin que le
sigue. Recurdese que en C++ no hay constantes numricas negativas. La forma general de este
operador es:
- expresin
Operador ms (+).
Este es un nuevo operador unario introducido en el ANSI C, y que tiene como finalidad la de servir
de complemento al operador () visto anteriormente. Se puede anteponer a una variable o
expresin como operador unario, pero en realidad no hace nada.
Operador sizeof( ).
Este es el operador de C con el nombre ms largo. Puede parecer una funcin, pero en realidad es
un operador. La finalidad del operador sizeof( ) es devolver el tamao, en bytes, del tipo de
variable introducida entre los parntesis. Recurdese que este tamao depende del compilador y
del tipo de computador que se est utilizando, por lo que es necesario disponer de este operador
para producir cdigo portable. Por ejemplo:
var_1 = sizeof(double)

// var_1 contiene el tamao


// de una variable doubl

22

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Operador negacin lgica (!).


Este operador devuelve un cero (false) si se aplica a un valor distinto de cero (true), y devuelve un
1 (true) si se aplica a un valor cero (false). Su forma general es:
!expresion
Operador coma (,).
Los operandos de este operador son expresiones, y tiene la forma general:
expresion = expresion_1, expresion_2
En este caso, expresion_1 se evala primero, y luego se evala expresion_2. El resultado global es
el valor de la segunda expresin, es decir de expresion_2. Este es el operador de menos
precedencia de todos los operadores de C++. Como se explicar ms adelante, su uso ms
frecuente es para introducir expresiones mltiples en la sentencia FOR.
Operadores direccin (&) e indireccin (*).
Aunque estos operadores se introduzcan aqu de modo circunstancial, su importancia en el
lenguaje C++ es absolutamente esencial, resultando uno de los puntos ms fuertes y quizs ms
difciles de dominar de este lenguaje.
La forma general de estos operadores es la siguiente:
*expresion;
&variable;
El operador direccin & devuelve la direccin de memoria de la variable que le sigue.
Por ejemplo:
variable_1 = &variable_2;
Despus de ejecutarse esta instruccin variable_1 contiene la direccin de memoria donde se
guarda el contenido de variable_2. Las variables que almacenan direcciones de otras variables se
denominan punteros (o apuntadores), deben ser declaradas como tales, y tienen su propia
aritmtica y modo de funcionar. Se vern con detalle un poco ms adelante.
No se puede modificar la direccin de una variable, por lo que no estn permitidas operaciones
en las que el operador & figura a la izquierda del operador (=), al estilo de:
&variable_1 = nueva_direccion;
El operador indireccin * es el operador complementario del &. Aplicado a una expresin que
represente una direccin de memoria (puntero) permite hallar el contenido o valor almacenado
en esa direccin. Por ejemplo:
variable_3 = *variable_1;

23

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

El contenido de la direccin de memoria representada por la variable de tipo puntero variable_1


se recupera y se asigna a la variable variable_3.
Como ya se ha indicado, las variables puntero y los operadores direccin (&) e indireccin (*)
sern explicados con mucho ms detalle en una seccin posterior.
3.2 EXPRESIONES
Ya han aparecido algunos ejemplos de expresiones del lenguaje C++ en las secciones precedentes.
Una expresin es una combinacin de variables y/o constantes, y operadores. La expresin es
equivalente al resultado que proporciona al aplicar sus operadores a sus operandos. Por ejemplo:
1+5 es una expresin formada por dos operandos (1 y 5) y un operador (el +); esta expresin es
equivalente al valor 6, lo cual quiere decir que all donde esta expresin aparece en el programa,
en el momento de la ejecucin es evaluada y sustituida por su resultado. Una expresin puede
estar formada por otras expresiones ms sencillas, y puede contener parntesis de varios niveles
agrupando distintos trminos. En C++ existen distintos tipos de expresiones.
3.2.1 EXPRESIONES ARITMTICAS
Estn formadas por variables y/o constantes, y distintos operadores aritmticos e incrementales
(+, -, *, /, %, ++, --). Como se ha dicho, tambin se pueden emplear parntesis de tantos niveles
como se desee, y su interpretacin sigue las normas aritmticas convencionales. Por ejemplo, la
solucin de la ecuacin de segundo grado:

Se escribe, en C++ en la forma:

x= (-b + sqrt((b*b)-(4*a*c)))/(2*a);
Donde, estrictamente hablando, slo lo que est a la derecha del operador de asignacin (=) es
una expresin aritmtica. El conjunto de la variable que est a la izquierda del signo (=), el
operador de asignacin, la expresin aritmtica y el carcter (;) constituyen una sentencia. En la
expresin anterior aparece la llamada a la funcin de librera sqrt(), que tiene como valor de
retorno la raz cuadrada de su nico argumento. En las expresiones se pueden introducir espacios
en blanco entre operandos y operadores; por ejemplo, la expresin anterior se puede escribir
tambin de la forma:
x= (-b + sqrt( ( b * b ) - ( 4 * a * c ) ) ) /(2*a);

3.2.2 EXPRESIONES LGICAS


Los elementos con los que se forman estas expresiones son valores lgicos; verdaderos (true, o
distintos de 0) y falsos (false, o iguales a 0), y los operadores lgicos ||, && y !. Tambin se

24

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

pueden emplear los operadores relacionales (<, >, <=, >=, ==, !=) para producir estos valores
lgicos a partir de valores numricos. Estas expresiones equivalen siempre a un valor 1 (true) o a
un valor 0 (false).
Por ejemplo:
a = ((b>c)&&(c>d))||((c==e)||(e==b));
Donde de nuevo la expresin lgica es lo que est entre el operador de asignacin (=) y el (;).
La variable a valdr 1 si b es mayor que c y c mayor que d, si c es igual a e e es igual a b.

3.2.3 EXPRESIONES GENERALES


Una de las caractersticas ms importantes (y en ocasiones ms difciles de manejar) del C++ es su
flexibilidad para combinar expresiones y operadores de distintos tipos en una expresin que se
podra llamar general, aunque es una expresin absolutamente ordinaria de C++.
Recurdese que el resultado de una expresin lgica es siempre un valor numrico (un 1 un 0);
esto permite que cualquier expresin lgica pueda aparecer como sub-expresin en una
expresin aritmtica. Recprocamente, cualquier valor numrico puede ser considerado como un
valor lgico: true si es distinto de 0 y false si es igual a 0. Esto permite introducir cualquier
expresin aritmtica como sub-expresin de una expresin lgica.
Por ejemplo:
(a - b*2.0) && (c != d)
A su vez, el operador de asignacin (=), adems de introducir un nuevo valor en la variable que
figura a su izquierda, deja tambin este valor disponible para ser utilizado en una expresin ms
general. Por ejemplo, supngase el siguiente cdigo que inicializa a 1 las tres variables a, b y c:
a = b = c = 1;
Que equivale a:
a = (b = (c = 1));
En realidad, lo que se ha hecho ha sido lo siguiente. En primer lugar se ha asignado un valor
unidad a c; el resultado de esta asignacin es tambin un valor unidad, que est disponible para
ser asignado a b; a su vez el resultado de esta segunda asignacin vuelve a quedar disponible y se
puede asignar a la variable a.
3.3 SENTENCIAS
Las expresiones de C++ son unidades o componentes elementales de unas entidades de rango
superior que son las sentencias. Las sentencias son unidades completas, ejecutables en s mismas.
Ya se ver que muchos tipos de sentencias incorporan expresiones aritmticas, lgicas o
generales como componentes de dichas sentencias.

25

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

3.3.1 SENTENCIAS SIMPLES


Una sentencia simple es una expresin de algn tipo terminada con un carcter (;). Un caso tpico
son las declaraciones o las sentencias aritmticas. Por ejemplo:
float real;
espacio = espacio_inicial + velocidad * tiempo;
3.3.2 SENTENCIA VACA NULA
En algunas ocasiones es necesario introducir en el programa una sentencia que ocupe un lugar,
pero que no realice ninguna tarea. A esta sentencia se le denomina sentencia vaca y consta de
un simple carcter (;). Por ejemplo:

;
3.3.3 SENTENCIAS COMPUESTAS O BLOQUES
Muchas veces es necesario poner varias sentencias en un lugar del programa donde debera
haber una sola. Esto se realiza por medio de sentencias compuestas. Una sentencia compuesta es
un conjunto de declaraciones y de sentencias agrupadas dentro de llaves {...}. Tambin se
conocen con el nombre de bloques. Una sentencia compuesta puede incluir otras sentencias,
simples y compuestas. Un ejemplo de sentencia compuesta es el siguiente:
{
int i = 1, j = 3, k;
double masa;
masa = 3.0;
k = i + j;
}

4. CONTROL DEL FLUJO DE EJECUCIN


En principio, las sentencias de un programa en C se ejecutan secuencialmente, esto es, cada una a
continuacin de la anterior empezando por la primera y acabando por la ltima. El lenguaje C++
dispone de varias sentencias para modificar este flujo secuencial de la ejecucin.
Las ms utilizadas se agrupan en dos familias: las bifurcaciones, que permiten elegir entre dos o
ms opciones segn ciertas condiciones, y los bucles, que permiten ejecutar repetidamente un
conjunto de instrucciones tantas veces como se desee, cambiando o actualizando ciertos valores.
4.1 BIFURCACIONES
4.1.1 OPERADOR CONDICIONAL
El operador condicional es un operador con tres operandos (ternario) que tiene la siguiente forma
general:
expresion_1 ? expresion_2 : expresion_3;
Explicacin: Se evala expresion_1. Si el resultado de dicha evaluacin es true (=1), se ejecuta
expresion_2; si el resultado es false (=0), se ejecuta expresion_3.

26

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

4.1.2 SENTENCIA IF
Esta sentencia de control permite ejecutar o no una sentencia simple o compuesta segn se
cumpla o no una determinada condicin. Esta sentencia tiene la siguiente forma general:
if (expresion)
sentencia;
Explicacin: Se evala expresion. Si el resultado es true (=1), se ejecuta sentencia; si el
resultado es false (=0), se salta sentencia y se prosigue en la lnea siguiente. Hay que recordar
que sentencia puede ser una sentencia simple o compuesta (bloque { ... }).
EJEMPLO N 1
Realizar un programa que permita determinar si un nmero introducido por teclado es positivo.
#include <iostream>
using namespace std;
int main()
{
int num;
cout<<"Introduzca un numero"<<endl;
cin>>num;
if (num>0)
cout<<"Es positivo";
return 0;
}
4.1.3 SENTENCIA IF ... ELSE
Esta sentencia permite realizar una bifurcacin, ejecutando una parte u otra del programa segn
se cumpla o no una cierta condicin. La forma general es la siguiente:
if (expresion)
sentencia_1;
else
sentencia_2;
Explicacin: Se evala expresion. Si el resultado es true (=1), se ejecuta sentencia_1 y se
prosigue en la lnea siguiente a sentencia_2; si el resultado es false (=0), se salta sentencia_1, se
ejecuta sentencia_2 y se prosigue en la lnea siguiente. Hay que indicar aqu tambin que
sentencia_1 y sentencia_2 pueden ser sentencias simples o compuestas (bloques { ... }).

EJEMPLO N 2
Disear un programa para determinar el mayor de dos nmeros introducidos por teclado.

27

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

#include <iostream>
using namespace std;
int main()
{
int num1,num2;
cout<<"Introduzca el primer numero"<<endl;
cin>>num1;
cout<<"Introduzca el segundo numero"<<endl;
cin>>num2;
if (num1>num2)
cout<<"l mayor es: "<<num1;
else
cout<<"El mayor es: "<<num2;
return 0;
}
4.1.4 SENTENCIA IF ... ELSE MLTIPLE
Esta sentencia permite realizar una ramificacin mltiple, ejecutando una entre varias partes del
programa segn se cumpla una entre n condiciones. La forma general es la siguiente:
if (expresion_1)
sentencia_1;
else if (expresion_2)
sentencia_2;
else if (expresion_3)
sentencia_3;
else if (...)
...
else
sentencia_n;
Explicacin: Se evala expresion_1. Si el resultado es true, se ejecuta sentencia_1. Si el resultado
es false, se salta sentencia_1 y se evala expresion_2. Si el resultado es true se ejecuta
sentencia_2, mientras que si es false se evala expresion_3 y as sucesivamente. Si ninguna de
las expresiones o condiciones es true se ejecuta expresion_n que es la opcin por defecto (puede
ser la sentencia vaca, y en ese caso puede eliminarse junto con la palabra else). Todas las
sentencias pueden ser simples o compuestas. (bloques { ... }).
EJEMPLO N 3
Establecer si dos nmeros introducidos por teclado son consecutivos, ya sea en forma ascendente
o descendente.
#include <iostream>
using namespace std;

28

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

int main()
{
int num1,num2;
cout<<"Introduzca un primer numero"<<endl;
cin>>num1;
cout<<"Introduzca un segundo numero"<<endl;
cin>>num2;
if (num2==(num1+1))
cout<<num1<<" "<<num2<<" Son numeros consecutivos";
else if (num1==(num2+1))
cout<<num1<<" "<<num2<<" Son numeros consecutivos";
else
cout<<num1<<" "<<num2<<" No son numeros consecutivos";
return 0;
}
4.1.5 SENTENCIA SWITCH
La sentencia que se va a describir a continuacin desarrolla una funcin similar a la de la
sentencia if ... else con mltiples ramificaciones, aunque como se puede ver presenta tambin
importantes diferencias. La forma general de la sentencia switch es la siguiente:
switch (expresion)
{
case expresion_cte_1: sentencia_1;
case expresion_cte_2: sentencia_2;
...
case expresion_cte_n: sentencia_n;
}
Explicacin: Se evala expresion y se considera el resultado de dicha evaluacin. Si dicho
resultado coincide con el valor constante expresion_cte_1, se ejecuta sentencia_1 seguida de
sentencia_2, sentencia_3, ..., sentencia. Si el resultado coincide con el valor constante
expresion_cte_2, se ejecuta sentencia_2 seguida de sentencia_3, ..., sentencia. En general, se
ejecutan todas aquellas sentencias que estn a continuacin de la expresion_cte cuyo valor
coincide con el resultado calculado al principio. Si ninguna expresion_cte coincide se ejecuta la
sentencia que est a continuacin de default. Si se desea ejecutar nicamente una sentencia_i (y
no todo un conjunto de ellas), basta poner una sentencia break a continuacin (en algunos casos
puede utilizarse la sentencia return o la funcin exit()). El efecto de la sentencia break es dar por
terminada la ejecucin de la sentencia switch. Existe tambin la posibilidad de ejecutar la misma
sentencia_i para varios valores del resultado de expresion, poniendo varios case expresion_cte
seguidos.
El siguiente ejemplo ilustra las posibilidades citadas:
switch (expresion)
{
case expresion_cte_1: sentencia_1;
break;

29

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

case expresion_cte_2: case expresion_cte_3:sentencia_2;


break;
default: sentencia_3;
}

EJEMPLO N 4
Realizar un men con las cuatro operaciones bsicas de la aritmtica.
#include <iostream>
using namespace std;
int main()
{
int a,b,op;
cout<<"Inserte primer valor: "<<endl;
cin>>a;
cout<<"Inserte segundo valor: "<<endl;
cin>>b;
cout<<endl<<"Seleccione una opcin: "<<endl;
cout<<"1.- Sumar"<<endl;
cout<<"2.- Restar"<<endl;
cout<<"3.- Multiplicar"<<endl;
cout<<"4.- Dividir"<<endl;
cout<<"5.- Salir"<<endl;
cout<<endl<<"Opcion: ";
cin>>op;
switch(op)
{
case 1: cout<<"La suma es: "<<a+b;break;
case 2: cout<<"La resta es: "<<a-b;break;
case 3: cout<<"El producto es: "<<a*b;break;
case 4: cout<<"La division es: "<<a/b;break;
case 5: break;
}
return 0;
}
4.1.6 SENTENCIAS IF ANIDADAS
Una sentencia if puede incluir otros if dentro de la parte correspondiente a su sentencia. A estas
sentencias se les llama sentencias anidadas (una dentro de otra). Por ejemplo:
if (a >= b)
if (b != 0.0)
c = a/b;
En ocasiones pueden aparecer dificultades de interpretacin con sentencias if...else anidadas,
como en el caso siguiente:

30

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

if (a >= b)
if (b != 0.0)
c = a/b;
else
c = 0.0;
En principio se podra plantear la duda de a cul de los dos if corresponde la parte else del
programa. Los espacios en blanco las indentaciones de las lneas parecen indicar que la sentencia
que sigue a else corresponde al segundo de los if, y as es en realidad, pues la regla es que el else
pertenece al if ms cercano. Sin embargo, no se olvide que el compilador de C++ no considera los
espacios en blanco (aunque sea muy conveniente introducirlos para hacer ms claro y legible el
programa), y que si se quisiera que el else perteneciera al primero de los if no bastara cambiar
los espacios en blanco, sino que habra que utilizar llaves, en la forma:
if (a >= b)
{
if (b != 0.0)
c = a/b;
}
else
c = 0.0;
Recurdese que todas las sentencias if e if...else, equivalen a una nica sentencia por la posicin
que ocupan en el programa.
EJEMPLO N 5
Dado tres nmeros enteros determinar cul de ellos es el nmero mayor.
#include <iostream>
using namespace std;
int main()
{
int num1,num2,num3;
cout<<"Primer valor"<<endl;
cin>>num1;
cout<<"Segundo valor"<<endl;
cin>>num2;
cout<<"Tercer valor"<<endl;
cin>>num3;
if (num1>num2)
{
if(num1>num3)
cout<<"El mayor es: "<<num1;
else
cout<<"El mayor es: "<<num3;
}
else

31

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

{
if (num2>num3)
cout<<"El mayor es: "<<num2;
else
cout<<"El mayor es: "<<num3;
}
return 0;
}
4.2 BUCLES
Adems de bifurcaciones, en el lenguaje C++ existen tambin varias sentencias que permiten
repetir una serie de veces la ejecucin de unas lneas de cdigo. Esta repeticin se realiza, bien un
nmero determinado de veces, bien hasta que se cumpla una determinada condicin de tipo
lgico o aritmtico. De modo genrico, a estas sentencias se les denomina bucles. Las tres
construcciones del lenguaje C para realizar bucles son el while, el for y el do...while.
4.2.1 SENTENCIA WHILE
Esta sentencia permite ejecutar repetidamente, mientras se cumpla una determinada condicin,
una sentencia o bloque de sentencias. La forma general es como sigue:
while (expresion_de_control)
sentencia;
Explicacin: Se evala expresion_de_control y si el resultado es false se salta sentencia y se
prosigue la ejecucin. Si el resultado es true se ejecuta sentencia y se vuelve a evaluar
expresion_de_control (evidentemente alguna variable de las que intervienen en
expresion_de_control habr tenido que ser modificada, pues si no el bucle continuara
indefinidamente). La ejecucin de sentencia prosigue hasta que expresion_de_control se hace
false, en cuyo caso la ejecucin contina en la lnea siguiente a sentencia. En otras palabras,
sentencia se ejecuta repetidamente mientras expresion_de_control sea true, y se deja de
ejecutar cuando expresion_de_control se hace false. Obsrvese que en este caso el control para
decidir si se sale o no del bucle est antes de sentencia, por lo que es posible que sentencia no se
llegue a ejecutar ni una sola vez. Todas las sentencias pueden ser simples o compuestas. (bloques
{ ... }).
EJEMPLO N 6
Realizar un programa que suma dos nmeros hasta que los tales sean 0. El programa termina
cuando los datos son 0.
#include<iostream>
using namespace std;
int main()
{
int a, b;
while (cin>>a>>b && a>0 && b>0)
{
cout<<a+b<<endl;

32

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

}
return 0;
}
4.2.2 SENTENCIA FOR
For es quizs el tipo de bucle ms verstil y utilizado del lenguaje C++. Su forma general es la
siguiente:
for (inicializacin; expresion_de_control; actualizacin)
sentencia;
Explicacin: Posiblemente la forma ms sencilla de explicar la sentencia for sea utilizando la
construccin while que sera equivalente. Dicha construccin es la siguiente:
inicializacion;
while (expresion_de_control)
{
sentencia;
actualizacion;
}
Donde sentencia puede ser una nica sentencia terminada con (;), otra sentencia de control
ocupando varias lneas (if, while, for, ...), o una sentencia compuesta o un bloque encerrado entre
llaves {...}. Antes de iniciarse el bucle se ejecuta inicializacin, que es una o ms sentencias que
asignan valores iniciales a ciertas variables o contadores. A continuacin se evala
expresion_de_control y si es false se prosigue en la sentencia siguiente a la construccin for; si es
true se ejecutan sentencia y actualizacin, y se vuelve a evaluar expresion_de_control. El
proceso prosigue hasta que expresion_de_control sea false. La parte de actualizacion sirve para
actualizar variables o incrementar contadores. Un ejemplo tpico puede ser el producto escalar de
dos vectores a y b de dimensin n:
for (pe =0.0, i=1; i<=n; i++)
{
pe += a[i]*b[i];
}
Primeramente se inicializa la variable pe a cero y la variable i a 1; el ciclo se repetir mientras que
i sea menor o igual que n, y al final de cada ciclo el valor de i se incrementar en una unidad. En
total, el bucle se repetir n veces. La ventaja de la construccin for sobre la construccin while
equivalente est en que en la cabecera de la construccin for se tiene toda la informacin sobre
cmo se inicializan, controlan y actualizan las variables del bucle.
Obsrvese que la inicializacin consta de dos sentencias separadas por el operador (,).

EJEMPLO N 7
Disear un programa para generar la tabla de multiplicar de cualquier nmero introducido por
teclado.

33

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

#include <iostream>
using namespace std;
int main()
{
int num;
cout<<"Inserte el numero que desa generar la tabla"<<endl;
cin>>num;
for (int i=1;i<=10;i++)
{
cout<<num<<" * "<<i<<" = "<<num*i<<endl;
}
return 0;
}

4.2.3 SENTENCIA DO ... WHILE


Esta sentencia funciona de modo anlogo a while, con la diferencia de que la evaluacin de
expresion_de_control se realiza al final del bucle, despus de haber ejecutado al menos una vez
las sentencias entre llaves; stas se vuelven a ejecutar mientras expresion_de_control sea true.
La forma general de esta sentencia es:
do
sentencia;
while(expresion_de_control);

Donde sentencia puede ser una nica sentencia o un bloque, y en la que debe observarse que
hay que poner (;) a continuacin del parntesis que encierra a expresion_de_control, entre otros
motivos para que esa lnea se distinga de una sentencia while ordinaria.
EJEMPLO N 8
Realizar un programa que permita determinar la suma de la siguiente seria numrica:
S=2+4+6+8+10+N;
#include <iostream>
using namespace std;
int main()
{
int n,s=0,t=2,a=1;
cout<<"Ultimo termino a generar: "<<endl;
cin>>n;
cout<<endl;
do
{
cout<<t<<'\t';
s+=t;
t+=2;

34

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

if(t-2==n)a=0;
}while (a);
cout<<endl<<endl<<"La suma es: "<<s;
return 0;
}
4.3 GENERACIN DE NMEROS ALEATORIOS
En C++, existe una funcin llamada rand(), que genera nmeros aleatorios. El problema que
tiene esta funcin es que siempre que reinicies el programa, aparecern los mismos nmeros.
Para evitar esto, hay que darle un nmero semilla, el cual operar como base para la
generacin de la secuencia de nmeros. El problema con esto, es que si le damos un nmero
fijo, volvemos al problema anterior, ya que siempre utilizar la misma base definida y por
ende la secuencia ser la misma.
Entonces, lo que necesitamos es darle un nmero semilla dinmico, esto es, que vaya
cambiando cada vez que ejecutemos el programa.
Sabiendo esto, la funcin que da la semilla a rand() es srand(), que recibe como parmetro (lo
que va entre los parntesis) el nmero semilla, que en este caso, ser la hora del sistema en
segundos. As, a menos que el programa se ejecute 2 o ms veces en menos de un segundo,
los nmeros cambiarn.
La funcin para saber la hora actual del sistema es time(NULL).
Sabiendo esto, vamos al cdigo. Haremos un generador de nmeros aleatorios, donde la
cantidad de estos, la decidir el usuario, ingresando esta cantidad por teclado.
As que lo primero que tenemos que hacer es incluir la librera:
#include<cstdlib>
Luego inicializar los nmeros aleatorios incluyendo esto:
srand(time(NULL));
Solo hay que utilizar adems la librera time.h:
#include<time.h>
Luego guardar el nmero aleatorio en alguna parte:
num=rand();
Eso es bsicamente. Para ajustar el rango de nmero aleatorios podemos hacer varias cosas.
Nmero aleatorios entre 0 y 50:
num=rand()%51;
Nmero aleatorios entre 1 y 100:
num=1+rand()%(101-1);

35

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Nmero aleatorios entre 250 y 420:


num=250+rand()%(421-250);
De forma general es:
variable = limite_inferior + rand() % (limite_superior +1 - limite_inferior) ;
EJEMPLO N 9
Realizar un programa que muestre 10 nmeros aleatorios entre 1 y 10:
#include <iostream>
#include <cstdlib>
#include <time.h>
using namespace std;
int main()
{
int num,c;
srand(time(NULL));
for(c=1;c<=10;c++)
{
num=1+rand()%(11-1);//Generando nmeros aleatorio entre 1 y 10
cout<<num<<" ";
}
cin.get();//Espera de tecla
}

36

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

PROBLEMAS PROPUESTOS
Con los fundamentos necesarios de C++ que hemos aprendido, ya ests listo para resolver los
siguientes problemas.
1.
2.
3.
4.
5.

Disear un programa para calcular la suma de dos nmeros A y B


Calcular el rea de un tringulo de base B y altura H
Calcular el rea de un crculo de radio R
Ingresar una nota por teclado y determinar si es de aprobacin o reprobacin
Ingresar un nmero por teclado y determinar si es PAR o IMPAR

6. Determinar si una persona es "Nio 1 a 10 aos", "Adolescente 11 a 17 aos", "Joven


18 a 29 aos", "Adulto 30 a 60 aos", "Tercera Edad 60 a 100 aos", de acuerdo a su
edad que es introducida por teclado.
7. Generar Aleatoriamente dos nmeros enteros entre 0 y 100. Determinar cul es el mayor
de ellos.
8. Introducir tres nmeros por teclado. Determinar cul es el mayor de los tres
9. Visualizar cuatro operaciones aritmticas de dos nmeros cualesquiera introducidos por
teclado.
10. Ingresar un nmero cualquiera, determina si es POSITIVO, NEGATIVO CERO
11. Generar un numero aleatoriamente entre 1 a 1000 y determinar si es PAR o IMPAR
12. Introducir un nmero positivo por teclado. Si es negativo o cero rechazarlo, caso
contrario, determinar si el nmero positivo es par o impar
13. Ingresar un nmero por teclado y determinar si es mltiplo de 10
14. Ingresar una nota por teclado y determinar su grado de aprovechamiento (0-10) Psimo,
(11-20) Muy Malo, (21-30) Malo, (31-40) regular, (41-50) Bueno, (51-60) Muy Bueno, (6170) Excelente
15. Simular un juego con un dado. Si se saca un 1 o un 6 e gana, caso contrario se pierde.
16. Simular un juego con dos dados. Si se saca un siete o un once se gana, caso contrario se
pierde.
17. Visualizar la serie 1,3,5,7,.n
18. Visualizar la serie 1,4,7,10,13,16..n
19. Ingresar un nmero y visualizar su tabla de multiplicar

37

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

38

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

5. INTRODUCCION A LA ESTRUCTURA DE DATOS


Una estructura de datos es una coleccin de datos que pueden ser caracterizados por su
organizacin y las operaciones que se definen en ella.
Las estructuras de datos son muy importantes en los sistemas de computadoras. Los tipos de
datos ms frecuentes utilizados en los diferentes lenguajes de programacin son:
Datos Simples

Estndar

entero (integer)
real (real)
carcter (char)
lgico (boolean)
Definido por el programador subrango (subrange)
(No estndar)
enumerativo (enumerated)

Datos Estructurados

Estticos

arrays (vectores / matrices)


registros (record)
ficheros (archivos)
conjuntos (set)
cadenas (string)
listas (pilas / colas)
listas enlazadas
rboles
grafos

Dinmicos

5.1 ARRAYS UNIDIMENSIONALES: VECTORES


Los vectores son una forma de almacenar datos que permiten contener una serie de valores del
mismo tipo, cada uno de los valores contenidos tiene una posicin asociada que se usar para
accederlos. Est posicin o ndice ser siempre un nmero entero positivo.
En C++ la cantidad de elementos que podr contener un vector es fijo, y en principio se define
cuando se declara el vector. Los vectores se pueden declarar de la siguiente forma:
tipo_elemento nombre[largo];
Esto declara la variable nombre como un vector de tipo_elementos que podr
contener largo cantidad de elementos, y cada uno de estos elemento podr contener un valor de
tipo tipo_elemento.
Por ejemplo:
double valores[128];
En este ejemplo declaramos un vector de 128 elementos del tipo double, los ndices de los
elementos iran entre 0 (para el primer elemento y 127 para el ltimo).
De la misma forma que con las otras declaraciones de variables que hemos visto se le puede
asignar un valor iniciar a los elementos.
O tambin se pueden declarar:
tipo_elemento nombre[largo]={valor_0, valor_1, valor_2};

39

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

En este caso estamos asignndole valores a los primeros 3 elementos del vector nombre. Notar
que largo debe ser mayor o igual a la cantidad de valores que le estamos asignando al vector, en
el caso de ser la misma cantidad no aporta informacin, por lo que el lenguaje nos permite
escribir:
tipo_elemento nombre[]={valor_0, valor_1, valor_2};
Que declarar nombre como el vector de largo 3.
Para acceder a un elemento accederemos a travs de su posicin.
Es decir:
tipo_elemento elemento[largo];
...
elemento[2] = valor_2;
Asumiendo
que
tenemos
guardando valor_2 en elemento[2].

el

vector

anterior

definido

estaramos

5.2. OPERACIONES CON VECTORES.


Un vector, como ya se ha mencionado, es una secuencia ordenada de elementos como:
x[1], x[2],.., x[n];
El lmite inferior no tiene por qu empezar en uno. El vector L.
L[0], L[1], L[2], L[3], L[4], L[5];
Contiene seis elementos, en el que el primer elemento comienza en cero. El vector P, cuyo rango
es 7 y sus lmites inferior y superior son -3 y 3, es:
P[-3, P[-2], P[-1], P[0], P[1], P[2], P[3];

Las operaciones que se pueden realizar con vectores durante el proceso de resolucin de un
problema son:
Asignacin
Lectura / Escritura
Recorrido (Acceso secuencial)
Actualizar (Aadir, borrar, insertar)
Ordenacin
Busqueda.

40

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

A continuacin se presente un programa con todas las operaciones ya mencionadas.


#include
#include
#include
#include
#include
#include
#include
#include

<iostream>
<cstdio>
<cstdlib>
<conio.h>
<vector>
<algorithm>
<string.h>
<time.h>

using namespace std;


int v[500];
int n;
void mostrar()
{
for(int i=0;i<n;i++)
{
cout<<v[i]<<'\t';
}
cout<<endl<<endl<<endl;
system("pause");
system("cls");
}
void crear()
{
if (v[0]!=0)
{
cout<<"Inserte el tamao del vector: ";
cin>>n;
cout<<endl;
memset(v,0,sizeof(v));
cout<<'\t'; mostrar();
system("cls");
}
else
{
cout<<" VECTOR YA CREADO"<<endl<<endl;
cout<<'\t'; mostrar();
system("cls");
}
}
void salir()
{
cout<<"GRACIAS!!! - SOFTWARE DESARROLLADO POR WILFREDO FUENTES"<<endl;;
}
void insertar_posicion()
{
int c,d;
if (v[0]==-1)
{
cout<<"Vector no creado"<<endl;
}
else
{
cout<<"Inserte posicion del vector"<<endl;
cin>>c;
if (c>n)
{
cout<<"Posicion Inexistente"<<endl;
cout<<"Introduzca la posicion del vector de "<<n<<" posiones"<<endl;
cin>>c;
}
cout<<"Introduzca el valor de la posicion"<<endl;
cin>>d;
}
v[c-1]=d;
cout<<endl;
mostrar();
}
void insertar_manual()
{
for(int i=0;i<n;i++)
{
cout<<"Ingrese valor en la posicion "<<i+1<<endl;
cin>>v[i];
}
cout<<endl;
mostrar();
}
void insertar_aleatorio()
{
int al;
srand(time(NULL));
cout<<"Inserte el rango de numeros aleatorios"<<endl;
cin>>al;
for(int i=0;i<n;i++)
{

41

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE
v[i]=1+rand()%(al-1);
}
cout<<endl;
mostrar();
}
void modificar_posicion()
{
int c,d;
if (v[0]==-1)
{
cout<<"Vector no creado"<<endl;
}
else
{
cout<<"Que posicion desea modificar???"<<endl;
cin>>c;
if (c>n)
{
cout<<"Posicion Inexistente"<<endl;
cout<<"Introduzca la posicion del vector de "<<n<<" posiones"<<endl;
cin>>c;
}
cout<<"Introduzca el nuevo valor de la posicion"<<endl;
cin>>d;
}
cout<<"Vector Anterior"<<endl;
mostrar();
v[c-1]=d;
cout<<"Vector Modificado"<<endl;
mostrar();
}
void modificar_global()
{
for(int i=0;i<n;i++)
{
cout<<"Ingrese valores nuevos para la posicion "<<i+1<<endl;
cin>>v[i];
}
cout<<endl;
mostrar();
}
void eliminar_posicion()
{
int e;
if (v[0]==-1)
{
cout<<"Vector no creado"<<endl;
}
else
{
cout<<"Inserte posicion del vector que desea eliminar"<<endl;
cin>>e;
if (e>n)
{
cout<<"Posicion Inexistente"<<endl;
cout<<"Introduzca la posicion del vector de "<<n<<" posiones"<<endl;
cin>>e;
}
}
v[e-1]=0;
cout<<endl;
mostrar();
}

void eliminar_global()
{
if (v[0]==-1)
{
cout<<"No existe vector para eliminar, debe crear Vector"<<'\n'<<endl;
system("pause");
system("cls");
}
else
{
cout<<"Usted Elimino Todo el Vector debera volver a crear otro"<<endl<<'\n';
system("pause");
system("cls");
memset(v,-1,sizeof(v));
}
}
void ordenar_ascendente()
{
cout<<"Vector Anterior"<<endl;
for(int i=0;i<n;i++)
{
cout<<v[i]<<'\t';
}
cout<<endl<<'\n';
cout<<"Vector Ordenado Ascendentemente"<<endl;
for (int i=0;i<6;i++)
{

42

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE
sort(v,v+n);
}
mostrar();
}
void ordenar_descendente()
{
cout<<"Vector Anterior"<<endl;
for(int i=0;i<n;i++)
{
cout<<v[i]<<'\t';
}
cout<<endl<<'\n';
cout<<"Vector Ordenado Descendentemente"<<endl;
for (int i=6;i>=0;i--)
{
sort(v,v+n,greater<int>());
cout<<endl;
}
mostrar();
}

int main()
{
int op;
memset(v,-1,sizeof(v));
while (op!=8)
{
cout<<'\t'<<"========================================="<<endl;
cout<<'\t'<<"
MENU VECTORES
"<<endl;
cout<<'\t'<<"========================================="<<endl;
cout<<'\t'<<"
1.- CREAR
"<<endl;
cout<<'\t'<<"
2.- INSERTAR
"<<endl;
cout<<'\t'<<"
3.- MODIFICAR
"<<endl;
cout<<'\t'<<"
4.- ELIMINAR
"<<endl;
cout<<'\t'<<"
5.- ORDENAR
"<<endl;
cout<<'\t'<<"
6.- MOSTRAR
"<<endl;
cout<<'\t'<<"
7.- SALIR
"<<endl;
cout<<'\t'<<"========================================="<<endl;
cout<<'\t'<<"
OPCION: ";cin>>op;
system("cls");
if (op!=8)
{
switch(op)
{
case 1: crear(); break;
case 2: int b;
if (v[0]==-1)
{
cout<<"El vector no existe"<<endl;
system("pause");
system("cls");
}
else
if (v[0]>0)
{
cout<<"Vetor Lleno"<<endl;
system("pause");
system("cls");
}
else
{
cout<<'\t'<<"========================================="<<endl;
cout<<'\t'<<"
MENU VECTORES - INSERTAR
"<<endl;
cout<<'\t'<<"========================================="<<endl;
cout<<'\t'<<"
1.- POR POSICION
"<<endl;
cout<<'\t'<<"
2.- GLOBAL
"<<endl;
cout<<'\t'<<"
3.- VOLVER
"<<endl;
cout<<'\t'<<"========================================="<<endl;
cout<<'\t'<<"
OPCION: ";cin>>b;
system("cls");
switch(b)
{
case 1: insertar_posicion(); break;
case 2: int h;
cout<<'\t'<<"========================================="<<endl;
cout<<'\t'<<"
MENU VECTORES - GLOBAL
"<<endl;
cout<<'\t'<<"========================================="<<endl;
cout<<'\t'<<"
1.- INSERTAR MANUALMENTE
"<<endl;
cout<<'\t'<<"
2.- INSERTAR ALEATORIAMENTE
"<<endl;
cout<<'\t'<<"
3.- VOLVER
"<<endl;
cout<<'\t'<<"========================================="<<endl;
cout<<'\t'<<"
OPCION: ";cin>>h;
system("cls");
switch(h)
{
case 1: insertar_manual(); break;
case 2: insertar_aleatorio(); break;
case 3: break;
}
break;
case 3: break;
}
}
break;

43

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

case 3: int q;
cout<<'\t'<<"========================================="<<endl;
cout<<'\t'<<"
MENU VECTORES - MODIFICAR
"<<endl;
cout<<'\t'<<"========================================="<<endl;
cout<<'\t'<<"
1.- POR POSICION
"<<endl;
cout<<'\t'<<"
2.- GLOBAL
"<<endl;
cout<<'\t'<<"
3.- VOLVER
"<<endl;
cout<<'\t'<<"========================================="<<endl;
cout<<'\t'<<"
OPCION: ";cin>>q;
system("cls");
switch(q)
{
case 1: modificar_posicion(); break;
case 2: modificar_global(); break;
case 3: break;
}
break;
case 4: int o;
cout<<'\t'<<"========================================="<<endl;
cout<<'\t'<<"
MENU VECTORES - ELIMINAR
"<<endl;
cout<<'\t'<<"========================================="<<endl;
cout<<'\t'<<"
1.- POR POSICION
"<<endl;
cout<<'\t'<<"
2.- GLOBAL
"<<endl;
cout<<'\t'<<"
3.- VOLVER
"<<endl;
cout<<'\t'<<"========================================="<<endl;
cout<<'\t'<<"
OPCION: ";cin>>o;
system("cls");
switch(o)
{
case 1: eliminar_posicion(); break;
case 2: eliminar_global(); break;
case 3: break;
}
break;
case 5: int l;
cout<<'\t'<<"========================================="<<endl;
cout<<'\t'<<"
MENU VECTORES - ORDENAR
"<<endl;
cout<<'\t'<<"========================================="<<endl;
cout<<'\t'<<"
1.- ASCENDENTE
"<<endl;
cout<<'\t'<<"
2.- DESCENDENTE
"<<endl;
cout<<'\t'<<"
3.- VOLVER
"<<endl;
cout<<'\t'<<"========================================="<<endl;
cout<<'\t'<<"
OPCION: ";cin>>l;
system("cls");
switch(l)
{
case 1: ordenar_ascendente(); break;
case 2: ordenar_descendente(); break;
case 3: break;
}
break;
case 6: mostrar(); break;
case 7: salir(); return 0;
}
}
}

return 0;
}

NOTA:
Para el diseo del men se utilizo la nueva librera de C++ llamada STL, la cual facilita al
programador el ahorro de memoria en el cdigo.
ALGUNAS DIFERENCIAS ENTRE LA LIBRERA STL Y LA CLASICA DE C++:
Mtodo de Ordenacin con la librera de C++ Clsica:
int aux;
for (int c2=0;c2<n;c2++
{
if(lista[c2]>lista[c2+1])
{
aux=lista[c2];
lista[c2]=lista[c2+1];
lista[c2+1]=aux;
}
}

44

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Mtodo de Ordenacin con la librera STL:


int v[10];
for(int i=0;i<10;i++)
{
sort(v,v+10);
}
Llenado de un vector con la librera de C++ Clsica:
int v[10];
for(int i=0;i<10;i++)
{
v[i]=0;
cout<<v[i]<< ;
}
Llenado de un vector con la librera STL:
int v[10];
memset(v,0,sizeof(v));
El valor de 0 puede ser remplazado por el valor que se desea llenar en el vector.
5.3. ARRAYS DE VARIAS DIMENCIONES (MATRICES)
Los vectores examinados hasta ahora se denominan arrays unidimensionales y en ellos cada
elemento se define o referencia por un ndice o subndice. Estos vectores son elementos de datos
escritos en una secuencia. Sin embargo, existen grupos de datos que son representados mejor en
forma de tabla o matriz con dos o ms subndices. Ejemplos tpicos de tablas o matrices son:
Tabla de distancias kilomtricas entre ciudades, cuadros horarios de trenes o aviones, informes
de ventas peridicas (mes/unidades vendidas o bien mes/ ventas totales), etc. Se pueden definir
tablas o matrices como arrays multidimensionales, cuyos elementos se pueden referenciar por
dos, tres o ms subndices.
5.4. ARRAYS BIDIMENSIONALES (TABLAS/MATRICES)
Una matriz es un vector de vectores o un tambin llamado array bidimensional. La manera de
declarar una matriz en C++ es similar a un vector:
tipo_elemento nombre[filas][columnas];
Las matrices tambin pueden ser de distintos tipos de datos como: int, char, float, double,etc.
Las matrices en C++ se almacenan al igual que los vectores en posiciones consecutivas de
memoria. Usualmente uno se hace la idea que una matriz es como un tablero. Pero internamente
el manejo es como su definicin lo indica, un vector de vectores, es decir, los vectores estn uno
detrs de los otros juntos.

45

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

La forma de acceder a los elementos de la matriz es utilizando su nombre e indicando los dos
subndices que van en los corchetes. Si Coloco int matriz[2][3]=10; estoy asignando al cuarto
elemento de la tercera fila el valor 10. No olvidar que tanto filas como columnas se enumeran a
partir de 0.
Ejemplo:
0,0
1,0
2,0
3,0

0,1
1,1
2,1
3,1

0,2
1,2
2,2
3,2

0,3
1,3
2,3
3,3

FILA

COLUMNA
5.5 PUNTEROS
No, no salgas corriendo todava. Aunque vamos a empezar con un tema que suele asustar a los
estudiantes de C++, no es algo tan terrible como se cuenta. Como se suele decir de los leones: no
son tan fieros como los pintan.
Los punteros proporcionan la mayor parte de la potencia al C++, y marcan la principal diferencia
con otros lenguajes de programacin.
Una buena comprensin y un buen dominio de los punteros pondr en tus manos una
herramienta de gran potencia. Un conocimiento mediocre o incompleto te impedir desarrollar
programas eficaces.
Por eso le dedicaremos mucha atencin y mucho espacio a los punteros. Es muy importante
comprender bien cmo funcionan y cmo se usan.
Creo que todos sabemos lo que es un puntero, fuera del mbito de la programacin. Usamos
punteros para sealar cosas sobre las que queremos llamar la atencin, como marcar puntos en
un mapa o detalles en una presentacin en pantalla. A menudo, usamos el dedo ndice para
sealar direcciones o lugares sobre los que estamos hablando o explicando algo. Cuando un dedo
no es suficiente, podemos usar punteros. Antiguamente esos punteros eran una vara de madera,
pero actualmente se usan punteros laser, aunque la idea es la misma. Un puntero tambin es el
smbolo que representa la posicin del ratn en una pantalla grfica. Estos punteros tambin se
usan para sealar objetos: enlaces, opciones de men, botones, etc. Un puntero sirve, pues, para
apuntar a los objetos a los que nos estamos refiriendo.
Pues en C++ un puntero es exactamente lo mismo. Probablemente habrs notado que a lo largo
del curso nos hemos referido a variables, constantes, etc como objetos. Esto ha sido intencionado
por el siguiente motivo:
C++ est diseado para la programacin orientada a objetos (POO), y en ese paradigma, todas las
entidades que podemos manejar son objetos.
Los punteros en C++ sirven para sealar objetos, y tambin para manipularlos.

46

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Para entender qu es un puntero veremos primero cmo se almacenan los datos en un


ordenador.
La memoria de un ordenador est compuesta por unidades bsicas llamadas bits. Cada bit slo
puede tomar dos valores, normalmente denominados alto y bajo, 1 y 0. Pero trabajar con bits
no es prctico, y por eso se agrupan.
Cada grupo de 8 bits forma un byte u octeto. En realidad el microprocesador, y por lo tanto
nuestro programa, slo puede manejar directamente bytes o grupos de dos o cuatro bytes. Para
acceder a los bits hay que acceder antes a los bytes.
Cada byte de la memoria de un ordenador tiene una direccin, llamada direccin de memoria.
Los microprocesadores trabajan con una unidad bsica de informacin, a la que se denomina
palabra (en ingls word). Dependiendo del tipo de microprocesador una palabra puede estar
compuesta por uno, dos, cuatro, ocho o diecisis bytes. Hablaremos en estos casos de
plataformas de 8, 16, 32, 64 128 bits. Se habla indistintamente de direcciones de memoria,
aunque las palabras sean de distinta longitud. Cada direccin de memoria contiene siempre
un byte. Lo que suceder cuando las palabras sean, por ejemplo, de 32 bits es que accederemos a
posiciones de memoria que sern mltiplos de 4.
Por otra parte, la mayor parte de los objetos que usamos en nuestros programas no caben en una
direccin de memoria. La solucin utilizada para manejar objetos que ocupen ms de un byte es
usar posiciones de memoria correlativas. De este modo, la direccin de un objeto es la direccin
de memoria de la primera posicin que contiene ese objeto.
Dicho de otro modo, si para almacenar un objeto se precisan cuatro bytes, y la direccin de
memoria de la primera posicin es n, el objeto ocupar las posiciones desde n a n+3, y la
direccin del objeto ser, tambin, n.
Todo esto sucede en el interior de la mquina, y nos importa relativamente poco. Pero podemos
saber qu tipo de plataforma estamos usando averiguando el tamao del tipo int, y para ello hay
que usar el operador sizeof, por ejemplo:
cout << "Plataforma de " << 8*sizeof(int) << " bits";

Ahora veamos cmo funcionan los punteros. Un puntero es un tipo especial de objeto que
contiene, ni ms ni menos que, la direccin de memoria de un objeto. Por supuesto, almacenada
a partir de esa direccin de memoria puede haber cualquier clase de objeto: un char, un int,
un float, un array, una estructura, una funcin u otro puntero. Seremos nosotros los responsables
de decidir ese contenido, al declarar el puntero.
De hecho, podramos decir que existen tantos tipos diferentes de punteros como tipos de objetos
puedan ser referenciados mediante punteros. Si tenemos esto en cuenta, los punteros que
apunten a tipos de objetos distintos, sern tipos diferentes. Por ejemplo, no podemos asignar a
un puntero a char el valor de un puntero a int.
Intentemos ver con mayor claridad el funcionamiento de los punteros. Podemos considerar la
memoria del ordenador como un gran array, de modo que podemos acceder a cada celda de
memoria a travs de un ndice. Podemos considerar que la primera posicin del array es la 0 celda
[0].

47

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Si usamos una variable para almacenar el ndice, por ejemplo:


indice=0, entonces celda[0] == celda[indice].
Finalmente, si prescindimos de la notacin de los arrays, podemos ver que el ndice se comporta
exactamente igual que un puntero.
El puntero indice podra tener por ejemplo, el valor 3, en ese caso, el valor apuntado
por indice tendra el valor 'val3'.
Las celdas de memoria tienen una existencia fsica, es decir son algo real y existirn siempre,
independientemente del valor del puntero. Existirn incluso si no existe el puntero.
De forma recproca, la existencia o no existencia de un puntero no implica la existencia o la
inexistencia del objeto. De la misma forma que el hecho de no sealar a un rbol, no implica la
inexistencia del rbol. Algo ms oscuro es si tenemos un puntero para rboles, que no est
sealando a un rbol. Un puntero de ese tipo no tendra uso si estamos en medio del mar: tener
ese puntero no crea rboles de forma automtica cuando sealemos con l. Es un puntero, no
una varita mgica.
Del mismo modo, el valor de la direccin que contiene un puntero no implica que esa direccin
sea vlida, en el sentido de que no tiene por qu contener la direccin de un objeto del tipo
especificado por el puntero.
Supongamos que tenemos un mapa en la pared, y supongamos tambin que existen diferentes
tipos de punteros lser para sealar diferentes tipos de puntos en el mapa (ya s que esto suena
raro, pero usemos la imaginacin). Creamos un puntero para sealar ciudades. Nada ms crearlo
(o encenderlo), el puntero sealar a cualquier sitio, podra sealar incluso a un punto fuera del
mapa. En general, daremos por sentado que una vez creado, el puntero no tiene por qu apuntar
a una ciudad, y aunque apunte al mapa, podra estar sealando a un mar o a un ro.
Con los punteros en C++ ocurre lo mismo. El valor inicial del puntero, cuando se declara, podra
estar fuera del mapa, es decir, contener direcciones de memoria que no existen. Pero, incluso
sealando a un punto de la memoria, es muy probable que no seale a un objeto del tipo
adecuado. Debemos considerar esto como el caso ms probable, y no usar jams un puntero que
no haya sido inicializado correctamente.
Dentro del array de celdas de memoria existirn zonas que contendrn programas y datos, tanto
del usuario como del propio sistema operativo o de otros programas, el sistema operativo se
encarga de gestionar esa memoria, prohibiendo o protegiendo determinadas zonas.
Pero el propio puntero, como objeto que es, tambin se almacenar en memoria, y por lo tanto,
tambin tendr una direccin de memoria. Cuando declaramos un puntero estaremos reservando
la memoria necesaria para almacenarlo, aunque, como pasa con el resto del los objetos, el
contenido de esa memoria contendr basura.
En principio, debemos asignar a un puntero, o bien la direccin de un objeto existente, o bien la
de uno creado explcitamente durante la ejecucin del programa o un valor conocido que indique
que no seala a ningn objeto, es decir el valor 0. El sistema operativo, cuanto ms avanzado es,
mejor suele controlar la memoria. Ese control se traduce en impedir el acceso a determinadas
direcciones reservadas por el sistema.

48

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

5.5.1. DECLARACIN DE PUNTEROS


Los punteros se declaran igual que el resto de los objetos, pero precediendo el identificador
con un asterisco (*).
El valor de todas las variables que manejamos en nuestros programas se almacenan en
memoria y tienen una direccin. Un puntero es una variable especial que apunta a la
direccin de memoria de una variable. El puntero tiene a su vez su propia direccin. Todas
estas direcciones tienen un formato hexadecimal.
Los punteros son herramientas muy poderosas con muchas utilidades y enormes ventajas
como veremos ms adelante. A grandes rasgos, un puntero me permite desplazarme en la
memoria, apuntar, re direccionar a ciertas variables, funciones, mtodos, objetos sin
necesidad de mover grandes bloques de datos, lo cual nos ahorra muchsimo el consumo de
memoria en los programas.
Sintaxis:
<tipo> *<identificador>;
Ejemplos:
int *pEntero;
char *pCaracter;
struct stPunto *pPunto;

Los punteros slo pueden apuntar a objetos de un tipo determinado, en el


ejemplo, pEntero slo puede apuntar a un objeto de tipo int.
La forma:
<tipo>* <identificador>;
Con el (*) junto al tipo, en lugar de junto al identificador del objeto, tambin est permitida.
De hecho, tambin es legal la forma:
<tipo> * <identificador>;
Veamos algunos matices. Tomemos el primer ejemplo:
int

*pEntero;

Equivale a:
int*

pEntero;

49

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Otro detalle importante es que, aunque las tres formas de situar el asterisco en la declaracin
son equivalentes, algunas de ellas pueden inducirnos a error, sobre todo si se declaran varios
objetos en la misma lnea:
int* x, y;
En este caso, x es un puntero a int, pero y no es ms que un objeto de tipo int. Colocar el
asterisco junto al tipo puede que indique ms claramente que estamos declarando un
puntero, pero hay que tener en cuenta que slo afecta al primer objeto declarado, si
quisiramos declarar ambos objetos como punteros aint tendremos que hacerlo de otro
modo:
int* x,
// O:
int *x,
// O:
int* x;
int* y;

*y;
*y;

5.5.2. OBTENER PUNTEROS A OBJETOS


Los punteros apuntan a objetos, por lo tanto, lo primero que tenemos que saber hacer con
nuestros punteros es asignarles direcciones de memoria vlidas de objetos.
Para averiguar la direccin de memoria de cualquier objeto usaremos el operador de
direccin (&), que leeremos como "direccin de".
Por supuesto, los tipos tienen que ser "compatibles", no podemos almacenar la direccin de
un objeto de tipo char en un puntero de tipo int.
Por ejemplo:
int A;
int *pA;
pA = &A;

Segn este ejemplo, pA es un puntero a int que apunta a la direccin donde se almacena el
valor del entero A.
5.5.3. OBJETO APUNTADO POR UN PUNTERO
La operacin contraria es obtener el objeto referenciado por un puntero, con el fin de
manipularlo, ya sea modificando su valor u obteniendo el valor actual.
Para manipular el objeto apuntado por un puntero usaremos el operador de indireccin, que
es un asterisco (*).
En C++ es muy habitual que el mismo smbolo se use para varias cosas diferentes, este es el
caso del asterisco, que se usa como operador de multiplicacin, para la declaracin de
punteros y, como vemos ahora, como operador de indireccin.

50

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Como operador de indireccin slo est permitido usarlo con punteros, y podemos leerlo
como "objeto apuntado por".
Por ejemplo:
int *pEntero;
int x = 10;
int y;
pEntero = &y;
*pEntero = x; // (1)

En (1) asignamos al objeto apuntado por pEntero en valor del objeto x. Como pEntero apunta
al objeto y, esta sentencia equivale (segn la secuencia del programa), a asignar a y el valor
de x.
5.5.4. DIFERENCIA ENTRE PUNTEROS Y OTROS OBJETOS
Debemos tener muy claro, en el ejemplo anterior, que pEntero es un objeto del tipo "puntero
a int", pero que *pEntero NO es un objeto de tipo int, sino una expresin.
Por qu decimos esto?
Pues porque, como pasa con todos los objetos en C++, cuando se declaran slo se reserva
espacio para almacenarlos, pero no se asigna ningn valor inicial, (recuerda que nuestro
puntero para rboles no crea rbol cada vez que sealemos con l). El contenido del objeto
permanecer sin cambios, de modo que el valor inicial del puntero ser aleatorio e
indeterminado. Debemos suponer que contiene una direccin no vlida.
Si pEntero apunta a un objeto de tipo int, *pEntero ser el contenido de ese objeto, pero no
olvides que*pEntero es un operador aplicado a un objeto de tipo "puntero a int". Es
decir, *pEntero es una expresin, no un objeto.
Declarar un puntero no crear un objeto del tipo al que apunta. Por ejemplo: int *pEntero; no
crea un objeto de tipo int en memoria. Lo que crea es un objeto que puede contener la
direccin de memoria de un entero.
Podemos decir que existe fsicamente un objeto pEntero, y tambin que ese
objeto puede (aunque esto no es siempre cierto) contener la direccin de un objeto de
tipo int.
Como todos los objetos, los punteros tambin contienen "basura" cuando son declarados. Es
costumbre dar valores iniciales nulos a los punteros que no apuntan a ningn sitio concreto:
int *pEntero = 0; // Tambin podemos asignar el valor NULL
char *pCaracter = 0;

51

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

NULL es una constante, que est definida como cero en varios ficheros de cabecera, como
"cstdio" o "iostream". Sin embargo, hay muchos textos que recomiendan usar el valor 0 para
asignar a punteros nulos, al menos en C++.
6. LISTAS ABIERTAS.
6.1. DEFINICIN
La forma ms simple de estructura dinmica es la lista abierta. En esta forma los nodos se
organizan de modo que cada uno apunta al siguiente, y el ltimo no apunta a nada, es decir, el
puntero del nodo siguiente vale NULL.
En las listas abiertas existe un nodo especial: el primero. Normalmente diremos que nuestra lista
es un puntero a ese primer nodo y llamaremos a ese nodo la cabeza de la lista. Eso es porque
mediante ese nico puntero podemos acceder a toda la lista.
Cuando el puntero que usamos para acceder a la lista vale NULL, diremos que la lista est vaca.
El nodo tpico para construir listas tiene esta forma:
struct nodo \{
int dato;
struct nodo *siguiente;
};

En el ejemplo, cada elemento de la lista slo contiene un dato de tipo entero, pero en la prctica
no hay lmite en cuanto a la complejidad de los datos a almacenar.
6.2. DECLARACIONES DE TIPOS PARA MANEJAR LISTAS EN C++
Normalmente se definen varios tipos que facilitan el manejo de las listas, en C, la declaracin de
tipos puede tener una forma parecida a esta:
typedef struct _nodo \{
int dato;
struct _nodo *siguiente;
} tipoNodo;
typedef tipoNodo *pNodo;
typedef tipoNodo *Lista;

tipoNodo es el tipo para declarar nodos, evidentemente.


pNodo es el tipo para declarar punteros a un nodo.
Lista es el tipo para declarar listas, como puede verse, un puntero a un nodo y una lista son la
misma cosa. En realidad, cualquier puntero a un nodo es una lista, cuyo primer elemento es el
nodo apuntado.

Lista enlazada

52

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Es muy importante que nuestro programa nunca pierda el valor del puntero al primer elemento,
ya que si no existe ninguna copia de ese valor, y se pierde, ser imposible acceder al nodo y no
podremos liberar el espacio de memoria que ocupa.
6.3. OPERACIONES BSICAS CON LISTAS
Con las listas tendremos un pequeo repertorio de operaciones bsicas que se pueden realizar:
Aadir o insertar elementos.
Buscar o localizar elementos.
Borrar elementos.
Moverse a travs de una lista, anterior, siguiente, primero.
Cada una de estas operaciones tendr varios casos especiales, por ejemplo, no ser lo mismo
insertar un nodo en una lista vaca, o al principio de una lista no vaca, o la final, o en una posicin
intermedia.
6.4. INSERTAR ELEMENTOS EN UNA LISTA ABIERTA
Veremos primero los casos sencillos y finalmente construiremos un algoritmo genrico para la
insercin de elementos en una lista.
6.4.1. INSERTAR UN ELEMENTO EN UNA LISTA VACA
Este es, evidentemente, el caso ms sencillo. Partiremos de que ya tenemos el nodo a insertar
y, por supuesto un puntero que apunte a l, adems el puntero a la lista valdr NULL:

Lista vaca

El proceso es muy simple, bastar con que:


1. nodo->siguiente apunte a NULL.
2. Lista apunte a nodo.
6.4.2. INSERTAR UN ELEMENTO EN LA PRIMERA POSICIN DE UNA LISTA

Insertar al principio

Podemos considerar el caso anterior como un caso particular de ste, la nica diferencia es
que en el caso anterior la lista es una lista vaca, pero siempre podemos, y debemos
considerar una lista vaca como una lista.
De nuevo partiremos de un nodo a insertar, con un puntero que apunte a l, y de una lista, en
este caso no vaca:

53

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Insertado al principio

El proceso sigue siendo muy sencillo:


1. Hacemos que nodo->siguiente apunte a Lista.
2. Hacemos que Lista apunte a nodo.
6.4.3. INSERTAR UN ELEMENTO EN LA LTIMA POSICIN DE UNA LISTA
Este es otro caso especial. Para este caso partiremos de una lista no vaca:

Insertar al final

El proceso en este caso tampoco es excesivamente complicado:


1. Necesitamos un puntero que seale al ltimo elemento de la lista. La manera de
conseguirlo es empezar por el primero y avanzar hasta que el nodo que tenga como
siguiente el valor NULL.
2. Hacer que nodo->siguiente sea NULL.
3. Hacer que ultimo->siguiente sea nodo.

Insertado al final

6.4.4. INSERTAR UN ELEMENTO A CONTINUACIN DE UN NODO CUALQUIERA DE UNA LISTA


De nuevo podemos considerar el caso anterior como un caso particular de este. Ahora el
nodo "anterior" ser aquel a continuacin del cual insertaremos el nuevo nodo:

Insertar dentro

Suponemos que ya disponemos del nuevo nodo a insertar, apuntado por nodo, y un puntero
al nodo a continuacin del que lo insertaremos.

54

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

El proceso a seguir ser:


1. Hacer que nodo->siguiente seale a anterior->siguiente.
2. Hacer que anterior->siguiente seale a nodo.

Insertado dentro

6.5. LOCALIZAR ELEMENTOS EN UNA LISTA ABIERTA


Muy a menudo necesitaremos recorrer una lista, ya sea buscando un valor particular o un nodo
concreto. Las listas abiertas slo pueden recorrerse en un sentido, ya que cada nodo apunta al
siguiente, pero no se puede obtener, por ejemplo, un puntero al nodo anterior desde un nodo
cualquiera si no se empieza desde el principio.
Para recorrer una lista procederemos siempre del mismo modo, usaremos un puntero auxiliar
como ndice:
1. Asignamos al puntero ndice el valor de Lista.
2. Abriremos un bucle que al menos debe tener una condicin, que el ndice no sea NULL.
3. Dentro del bucle asignaremos al ndice el valor del nodo siguiente al ndice actual.
Por ejemplo, para mostrar todos los valores de los nodos de una lista, podemos usar el siguiente
bucle en C++:
typedef struct _nodo \{
int dato;
struct _nodo *siguiente;
} tipoNodo;
typedef tipoNodo *pNodo;
typedef tipoNodo *Lista;
...
pNodo indice;
...
indice = Lista;
while(indice) \{
printf("%d\n", indice->dato);
indice = indice->siguiente;
}
...

Supongamos que slo queremos mostrar los valores hasta que encontremos uno que sea mayor
que 100, podemos sustituir el bucle por:
...
indice = Lista;
while(indice && indice->dato <= 100) \{
printf("%d\n", indice->dato);
indice = indice->siguiente;

55

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

}
...

Si analizamos la condicin del bucle, tal vez encontremos un posible error: Qu pasara si ningn
valor es mayor que 100, y alcancemos el final de la lista?. Podra pensarse que cuando indice sea
NULL, si intentamos acceder a indice->dato se producir un error.
En general eso ser cierto, no puede accederse a punteros nulos. Pero en este caso, ese acceso
est dentro de una condicin y forma parte de una expresin "and". Recordemos que cuando se
evala una expresin "and", se comienza por la izquierda, y la evaluacin se abandona cuando una
de las expresiones resulta falsa, de modo que la expresin "indice->dato <= 100" nunca se
evaluar si indice es NULL.
Si hubiramos escrito la condicin al revs, el programa nunca funcionara bien. Esto es algo muy
importante cuando se trabaja con punteros.
6.6. ELIMINAR ELEMENTOS EN UNA LISTA ABIERTA
De nuevo podemos encontrarnos con varios casos, segn la posicin del nodo a eliminar.
6.6.1. ELIMINAR EL PRIMER NODO DE UNA LISTA ABIERTA

Eliminar primer nodo

Es el caso ms simple. Partiremos de una lista con uno o ms nodos, y usaremos un puntero
auxiliar, nodo:
1. Hacemos que nodo apunte al primer elemento de la lista, es decir a Lista.
2. Asignamos a Lista la direccin del segundo nodo de la lista: Lista->siguiente.
3. Liberamos la memoria asignada al primer nodo, el que queremos eliminar.
Si no guardamos el puntero al primer nodo antes de actualizar Lista, despus nos resultara
imposible liberar la memoria que ocupa. Si liberamos la memoria antes de actualizar Lista,
perderemos el puntero al segundo nodo.

Primer nodo eliminado

Si la lista slo tiene un nodo, el proceso es tambin vlido, ya que el valor de Lista->siguiente
es NULL, y despus de eliminar el primer nodo la lista quedar vaca, y el valor de Lista ser
NULL.
De hecho, el proceso que se suele usar para borrar listas completas es eliminar el primer
nodo hasta que la lista est vaca.

56

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

6.6.2. ELIMINAR UN NODO CUALQUIERA DE UNA LISTA ABIERTA


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

Eliminar un nodo

El proceso es parecido al del caso anterior:


1. Hacemos que nodo apunte al nodo que queremos borrar.
2. Ahora, asignamos como nodo siguiente del nodo anterior, el siguiente al que queremos
eliminar: anterior->siguiente = nodo->siguiente.
3. Eliminamos la memoria asociada al nodo que queremos eliminar.

Nodo eliminado

Si el nodo a eliminar es el ltimo, es procedimiento es igualmente vlido, ya que anterior


pasar a ser el ltimo, y anterior->siguiente valdr NULL.
6.7. MOVERSE A TRAVS DE UNA LISTA ABIERTA
Slo hay un modo de moverse a travs de una lista abierta, hacia delante.
An as, a veces necesitaremos acceder a determinados elementos de una lista abierta. Veremos
ahora como acceder a los ms corrientes: el primero, el ltimo, el siguiente y el anterior.
6.7.1. PRIMER ELEMENTO DE UNA LISTA
El primer elemento es el ms accesible, ya que es a ese a que apunta el puntero que define la
lista. Para obtener un puntero al primer elemento bastar con copiar el puntero Lista.
6.7.2. ELEMENTO SIGUIENTE A UNO CUALQUIERA
Supongamos que tenemos un puntero nodo que seala a un elemento de una lista. Para
obtener un puntero al siguiente bastar con asignarle el campo "siguiente" del nodo, nodo>siguiente.
6.7.3. ELEMENTO ANTERIOR A UNO CUALQUIERA
Ya hemos dicho que no es posible retroceder en una lista, de modo que para obtener un
puntero al nodo anterior a uno dado tendremos que partir del primero, e ir avanzando hasta
que el nodo siguiente sea precisamente nuestro nodo.
6.7.4. LTIMO ELEMENTO DE UNA LISTA
Para obtener un puntero al ltimo elemento de una lista partiremos de un nodo cualquiera,
por ejemplo el primero, y avanzaremos hasta que su nodo siguiente sea NULL.

57

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

6.7.5. SABER SI UNA LISTA EST VACA


Basta con comparar el puntero Lista con NULL, si Lista vale NULL la lista est vaca.
6.8. BORRAR UNA LISTA COMPLETA
El algoritmo genrico para borrar una lista completa consiste simplemente en borrar el primer
elemento sucesivamente mientras la lista no est vaca.
6.9. EJEMPLO DE LISTA ABIERTA ORDENADA EN C
Supongamos que queremos construir una lista para almacenar nmeros enteros, pero de modo
que siempre est ordenada de menor a mayor. Para hacer la prueba aadiremos los valores 20,
10, 40, 30. De este modo tendremos todos los casos posibles. Al comenzar, el primer elemento se
introducir en una lista vaca, el segundo se insertar en la primera posicin, el tercero en la
ltima, y el ltimo en una posicin intermedia.
Insertar un elemento en una lista vaca es equivalente a insertarlo en la primera posicin. De
modo que no incluiremos una funcin para asignar un elemento en una lista vaca, y haremos que
la funcin para insertar en la primera posicin nos sirva para ese caso tambin.
6.9.1. ALGORITMO DE INSERCIN
1. El primer paso es crear un nodo para el dato que vamos a insertar.
2. Si Lista es NULL, o el valor del primer elemento de la lista es mayor que el del nuevo,
insertaremos el nuevo nodo en la primera posicin de la lista.
3. En caso contrario, buscaremos el lugar adecuado para la insercin, tenemos un puntero
"anterior". Lo inicializamos con el valor de Lista, y avanzaremos mientras anterior>siguiente no sea NULL y el dato que contiene anterior->siguiente sea menor o igual que
el dato que queremos insertar.
4. Ahora ya tenemos anterior sealando al nodo adecuado, as que insertamos el nuevo
nodo a continuacin de l.
void Insertar(Lista *lista, int v) \{
pNodo nuevo, anterior;
/* Crear un nodo nuevo */
nuevo = (pNodo)malloc(sizeof(tipoNodo));
nuevo->valor = v;
/* Si la lista est vaca */
if(ListaVacia(*lista) || (*lista)->valor > v) \{
/* Aadimos la lista a continuacin del nuevo nodo */
nuevo->siguiente = *lista;
/* Ahora, el comienzo de nuestra lista es en nuevo nodo */
*lista = nuevo;
} else \{
/* Buscar el nodo de valor menor a v */
anterior = *lista;
/* Avanzamos hasta el ltimo elemento o hasta que el siguiente tenga
un valor mayor que v */
while(anterior->siguiente && anterior->siguiente->valor <= v)
anterior = anterior->siguiente;
/* Insertamos el nuevo nodo despus del nodo anterior */

58

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

nuevo->siguiente = anterior->siguiente;
anterior->siguiente = nuevo;
}
}

6.9.2. ALGORITMO PARA BORRAR UN ELEMENTO


Despus probaremos la funcin para buscar y borrar, borraremos los elementos 10, 15, 45, 30
y 40, as probaremos los casos de borrar el primero, el ltimo y un caso intermedio o dos
nodos que no existan.
Recordemos que para eliminar un nodo necesitamos disponer de un puntero al nodo
anterior.
1. Lo primero ser localizar el nodo a eliminar, si es que existe. Pero sin perder el puntero al
nodo anterior. Partiremos del nodo primero, y del valor NULL para anterior. Y
avanzaremos mientras nodo no sea NULL o mientras que el valor almacenado en nodo
sea menor que el que buscamos.
2. Ahora pueden darse tres casos:
3. Que el nodo sea NULL, esto indica que todos los valores almacenados en la lista son
menores que el que buscamos y el nodo que buscamos no existe. Retornaremos sin
borrar nada.
4. Que el valor almacenado en nodo sea mayor que el que buscamos, en ese caso tambin
retornaremos sin borrar nada, ya que esto indica que el nodo que buscamos no existe.
5. Que el valor almacenado en el nodo sea igual al que buscamos.
6. De nuevo existen dos casos:
7. Que anterior sea NULL. Esto indicara que el nodo que queremos borrar es el primero, as
que modificamos el valor de Lista para que apunte al nodo siguiente al que queremos
borrar.
8. Que anterior no sea NULL, el nodo no es el primero, as que asignamos a anterior>siguiente la direccin de nodo->siguiente.
9. Despus de 7 u 8, liberamos la memoria de nodo.
void Borrar(Lista *lista, int v) \{
pNodo anterior, nodo;
nodo = *lista;
anterior = NULL;
while(nodo && nodo->valor < v) \{
anterior = nodo;
nodo = nodo->siguiente;
}
if(!nodo || nodo->valor != v) return;
else \{ /* Borrar el nodo */
if(!anterior) /* Primer elemento */
*lista = nodo->siguiente;
else /* un elemento cualquiera */

59

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

anterior->siguiente = nodo->siguiente;
free(nodo);
}
}

6.9.3. CODIGO COMPLETO


#include <cstdlib>
#include <cstdio>
typedef struct _nodo \{
int valor;
struct _nodo *siguiente;
} tipoNodo;

typedef tipoNodo *pNodo;


typedef tipoNodo *Lista;
/* Funciones con listas: */
void Insertar(Lista *l, int v);
void Borrar(Lista *l, int v);
int ListaVacia(Lista l);
void BorrarLista(Lista *);
void MostrarLista(Lista l);
int main() \{
Lista lista = NULL;
pNodo p;
Insertar(&lista,
Insertar(&lista,
Insertar(&lista,
Insertar(&lista,

20);
10);
40);
30);

MostrarLista(lista);
Borrar(&lista,
Borrar(&lista,
Borrar(&lista,
Borrar(&lista,
Borrar(&lista,

10);
15);
45);
30);
40);

MostrarLista(lista);
BorrarLista(&lista);
getchar();
return 0;
}
void Insertar(Lista *lista, int v) \{

60

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

pNodo nuevo, anterior;


/* Crear un nodo nuevo */
nuevo = (pNodo)malloc(sizeof(tipoNodo));
nuevo->valor = v;
/* Si la lista est vaca */
if(ListaVacia(*lista) || (*lista)->valor > v) \{
/* Aadimos la lista a continuacin del nuevo nodo */
nuevo->siguiente = *lista;
/* Ahora, el comienzo de nuestra lista es en nuevo nodo */
*lista = nuevo;
} else \{
/* Buscar el nodo de valor menor a v */
anterior = *lista;
/* Avanzamos hasta el ltimo elemento o hasta que el siguiente tenga
un valor mayor que v */
while(anterior->siguiente && anterior->siguiente->valor <= v)
anterior = anterior->siguiente;
/* Insertamos el nuevo nodo despus del nodo anterior */
nuevo->siguiente = anterior->siguiente;
anterior->siguiente = nuevo;
}
}
void Borrar(Lista *lista, int v) \{
pNodo anterior, nodo;
nodo = *lista;
anterior = NULL;
while(nodo && nodo->valor < v) \{
anterior = nodo;
nodo = nodo->siguiente;
}
if(!nodo || nodo->valor != v) return;
else \{ /* Borrar el nodo */
if(!anterior) /* Primer elemento */
*lista = nodo->siguiente;
else /* un elemento cualquiera */
anterior->siguiente = nodo->siguiente;
free(nodo);
}
}
int ListaVacia(Lista lista) \{
return (lista == NULL);
}
void BorrarLista(Lista *lista) \{
pNodo nodo;
while(*lista) \{
nodo = *lista;
*lista = nodo->siguiente;
free(nodo);

61

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

}
}
void MostrarLista(Lista lista) \{
pNodo nodo = lista;
if(ListaVacia(lista)) printf("Lista vaca\n");
else \{
while(nodo) \{
printf("%d -> ", nodo->valor);
nodo = nodo->siguiente;
}
printf("\n");
}
}

6.10. EJEMPLO DE LISTA ABIERTA EN C++ USANDO CLASES


Usando clases el programa cambia bastante, aunque los algoritmos son los mismos.
Para empezar, necesitaremos dos clases, una para nodo y otra para lista. Adems la clase para
nodo debe ser amiga de la clase lista, ya que sta debe acceder a los miembros privados de nodo.
class nodo \{
public:
nodo(int v, nodo *sig = NULL) \{
valor = v;
siguiente = sig;
}
private:
int valor;
nodo *siguiente;
friend class lista;
};
typedef nodo *pnodo;
class lista \{
public:
lista() \; }
~lista();
void Insertar(int v);
void Borrar(int v);
bool ListaVacia() \; }
void Mostrar();
void Siguiente();
void Primero();
void Ultimo();
bool Actual() \; }
int ValorActual() \
private:

62

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

pnodo primero;
pnodo actual;
};

Hemos hecho que la clase para lista sea algo ms completa que la equivalente en C, aprovechando
las prestaciones de las clases. En concreto, hemos aadido funciones para mantener un puntero a
un elemento de la lista y para poder moverse a travs de ella.
Los algoritmos para insertar y borrar elementos son los mismos que expusimos para el ejemplo C,
tan slo cambia el modo de crear y destruir nodos.
6.11. CDIGO DEL EJEMPLO COMPLETO
#include <iostream>
using namespace std;
class nodo \{
public:
nodo(int v, nodo *sig = NULL)
\{
valor = v;
siguiente = sig;
}
private:
int valor;
nodo *siguiente;
friend class lista;
};
typedef nodo *pnodo;
class lista \{
public:
lista() \; }
~lista();
void Insertar(int v);
void Borrar(int v);
bool ListaVacia() \; }
void Mostrar();
void Siguiente() \
void Primero() \
void Ultimo() \
bool Actual() \; }
int ValorActual() \
private:
pnodo primero;
pnodo actual;
};
lista::~lista() \{

63

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

pnodo aux;
while(primero) \{
aux = primero;
primero = primero->siguiente;
delete aux;
}
actual = NULL;
}
void lista::Insertar(int v) \{
pnodo anterior;
// Si la lista est vaca
if(ListaVacia() || primero->valor > v) \{
// Asignamos a lista un nuevo nodo de valor v y
// cuyo siguiente elemento es la lista actual
primero = new nodo(v, primero);
} else \{
// Buscar el nodo de valor menor a v
anterior = primero;
// Avanzamos hasta el ltimo elemento o hasta que el siguiente tenga
// un valor mayor que v
while(anterior->siguiente && anterior->siguiente->valor <= v)
anterior = anterior->siguiente;
// Creamos un nuevo nodo despus del nodo anterior, y cuyo siguiente
// es el siguiente del anterior
anterior->siguiente = new nodo(v, anterior->siguiente);
}
}
void lista::Borrar(int v) \{
pnodo anterior, nodo;
nodo = primero;
anterior = NULL;
while(nodo && nodo->valor < v) \{
anterior = nodo;
nodo = nodo->siguiente;
}
if(!nodo || nodo->valor != v) return;
else \{ // Borrar el nodo
if(!anterior) // Primer elemento
primero = nodo->siguiente;
else // un elemento cualquiera
anterior->siguiente = nodo->siguiente;
delete nodo;
}
}
void lista::Mostrar() \{
nodo *aux;
aux = primero;
while(aux) \{

64

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

cout << aux->valor << "-> ";


aux = aux->siguiente;
}
cout << endl;
}
int main() \{
lista Lista;
Lista.Insertar(20);
Lista.Insertar(10);
Lista.Insertar(40);
Lista.Insertar(30);
Lista.Mostrar();
cout << "Lista de elementos:" << endl;
Lista.Primero();
while(Lista.Actual()) \{
cout << Lista.ValorActual() << endl;
Lista.Siguiente();
}
Lista.Primero();
cout << "Primero: " << Lista.ValorActual() << endl;
Lista.Ultimo();
cout << "Ultimo: " << Lista.ValorActual() << endl;
Lista.Borrar(10);
Lista.Borrar(15);
Lista.Borrar(45);
Lista.Borrar(30);
Lista.Borrar(40);
Lista.Mostrar();
cin.get();
return 0;
}

7. PILAS
7.1. DEFINICIN
Una pila es un tipo especial de lista abierta en la que slo se pueden insertar y eliminar nodos en
uno de los extremos de la lista. Estas operaciones se conocen como "push" y "pop",
respectivamente "empujar" y "tirar". Adems, las escrituras de datos siempre son inserciones de
nodos, y las lecturas siempre eliminan el nodo ledo.
Estas caractersticas implican un comportamiento de lista LIFO (Last In First Out), el ltimo en
entrar es el primero en salir.
El smil del que deriva el nombre de la estructura es una pila de platos. Slo es posible aadir
platos en la parte superior de la pila, y slo pueden tomarse del mismo extremo.
El nodo tpico para construir pilas es el mismo que vimos en el captulo anterior para la
construccin de listas:
struct nodo \{
int dato;

65

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

struct nodo *siguiente;


};

7.2. DECLARACIONES DE TIPOS PARA MANEJAR PILAS EN C++


Los tipos que definiremos normalmente para manejar pilas sern casi los mismos que para
manejar listas, tan slo cambiaremos algunos nombres:
typedef struct _nodo \{
int dato;
struct _nodo *siguiente;
} tipoNodo;
typedef tipoNodo *pNodo;
typedef tipoNodo *Pila;

tipoNodo es el tipo para declarar nodos, evidentemente.


pNodo es el tipo para declarar punteros a un nodo.
Pila es el tipo para declarar pilas.

Pila

Es evidente, a la vista del grfico, que una pila es una lista abierta. As que sigue siendo muy
importante que nuestro programa nunca pierda el valor del puntero al primer elemento, igual
que pasa con las listas abiertas.
Teniendo en cuenta que las inserciones y borrados en una pila se hacen siempre en un extremo,
lo que consideramos como el primer elemento de la lista es en realidad el ltimo elemento de la
pila.
7.3. OPERACIONES BSICAS CON PILAS
Las pilas tienen un conjunto de operaciones muy limitado, slo permiten las operaciones de
"push" y "pop":
Push: Aadir un elemento al final de la pila.
Pop: Leer y eliminar un elemento del final de la pila.
7.4. PUSH, INSERTAR ELEMENTO
Las operaciones con pilas son muy simples, no hay casos especiales, salvo que la pila est vaca.
7.4.1. PUSH EN UNA PILA VACA
Partiremos de que ya tenemos el nodo a insertar y, por supuesto un puntero que apunte a l,
adems el puntero a la pila valdr NULL:

66

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Push en vaca

El proceso es muy simple, bastar con que:


1. nodo->siguiente apunte a NULL.
2. Pila apunte a nodo.
7.4.2. PUSH EN UNA PILA NO VACA

Push en pila no vaca

Podemos considerar el caso anterior como un caso particular de ste, la nica diferencia es que
podemos y debemos trabajar con una pila vaca como con una pila normal.
De nuevo partiremos de un nodo a insertar, con un puntero que apunte a l, y de una pila, en
este caso no vaca:

Resultado

El proceso sigue siendo muy sencillo:


1. Hacemos que nodo->siguiente apunte a Pila.
2. Hacemos que Pila apunte a nodo.
7.5. POP, LEER Y ELIMINAR UN ELEMENTO

Pop

Ahora slo existe un caso posible, ya que slo podemos leer desde un extremo de la pila.
Partiremos de una pila con uno o ms nodos, y usaremos un puntero auxiliar, nodo:

Resultado

67

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

1. Hacemos que nodo apunte al primer elemento de la pila, es decir a Pila.


2. Asignamos a Pila la direccin del segundo nodo de la pila: Pila->siguiente.
3. Guardamos el contenido del nodo para devolverlo como retorno, recuerda que la operacin
pop equivale a leer y borrar.
4. Liberamos la memoria asignada al primer nodo, el que queremos eliminar.
Si la pila slo tiene un nodo, el proceso sigue siendo vlido, ya que el valor de Pila->siguiente es
NULL, y despus de eliminar el ltimo nodo la pila quedar vaca, y el valor de Pila ser NULL.
7.6 EJEMPLO DE PILA EN C++ USANDO CLASES
Al igual que pasaba con las listas, usando clases el programa cambia bastante. Las clases para
pilas son versiones simplificadas de las mismas clases que usamos para listas.
Para empezar, necesitaremos dos clases, una para nodo y otra para pila. Adems la clase para
nodo debe ser amiga de la clase pila, ya que sta debe acceder a los miembros privados de nodo.

class nodo \{
public:
nodo(int v, nodo *sig = NULL) \{
valor = v;
siguiente = sig;
}
private:
int valor;
nodo *siguiente;
friend class pila;
};
typedef nodo *pnodo;
class pila \{
public:
pila() : ultimo(NULL) \{}
~pila();
void Push(int v);
int Pop();
private:
pnodo ultimo;
};

68

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

7.6.1. CDIGO DEL EJEMPLO COMPLETO


#include <iostream>
using namespace std;
class nodo \{
public:
nodo(int v, nodo *sig = NULL) \{
valor = v;
siguiente = sig;
}
private:
int valor;
nodo *siguiente;
friend class pila;
};
typedef nodo *pnodo;
class pila \{
public:
pila() : ultimo(NULL) \{}
~pila();
void Push(int v);
int Pop();
private:
pnodo ultimo;
};
pila::~pila() \{
while(ultimo) Pop();
}
void pila::Push(int v) \{
pnodo nuevo;
/* Crear un nodo nuevo */
nuevo = new nodo(v, ultimo);
/* Ahora, el comienzo de nuestra pila es en nuevo nodo */
ultimo = nuevo;
}
int pila::Pop() \{
pnodo nodo; /* variable auxiliar para manipular nodo */
int v;
/* variable auxiliar para retorno */
if(!ultimo) return 0; /* Si no hay nodos en la pila retornamos 0 */
/* Nodo apunta al primer elemento de la pila */
nodo = ultimo;
/* Asignamos a pila toda la pila menos el primer elemento */

69

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

ultimo = nodo->siguiente;
/* Guardamos el valor de retorno */
v = nodo->valor;
/* Borrar el nodo */
delete nodo;
return v;
}
int main() \{
pila Pila;
Pila.Push(20);
cout << "Push(20)"
Pila.Push(10);
cout << "Push(10)"
cout << "Pop() = "
Pila.Push(40);
cout << "Push(40)"
Pila.Push(30);
cout << "Push(30)"
cout << "Pop() = "
cout << "Pop() = "
Pila.Push(90);
cout << "Push(90)"
cout << "Pop() = "
cout << "Pop() = "

<< endl;
<< endl;
<< Pila.Pop() << endl;
<< endl;
<< endl;
<< Pila.Pop() << endl;
<< Pila.Pop() << endl;
<< endl;
<< Pila.Pop() << endl;
<< Pila.Pop() << endl;

cin.get();
return 0;
}

7.7 EJEMPLO DE PILA EN C++ USANDO PLANTILLAS


Veremos ahora un ejemplo sencillo usando plantillas. Ya que la estructura para pilas es ms
sencilla que para listas abiertas, nuestro ejemplo tambin ser ms simple.
Seguimos necesitando dos clases, una para nodo y otra para pila. Pero ahora podremos usar esas
clases para construir listas de cualquier tipo de datos.
7.7.1. CDIGO DEL EJEMPLO COMPLETO
Veremos primero las declaraciones de las dos clases que necesitamos:
template<class TIPO> class pila;

template<class TIPO>
class nodo \{
public:
nodo(TIPO v, nodo<TIPO> *sig = NULL) \{
valor = v;
siguiente = sig;
}
private:
TIPO valor;
nodo<TIPO> *siguiente;

70

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

friend class pila<TIPO>;


};
template<class TIPO>
class pila \{
public:
pila() : ultimo(NULL) \{}
~pila();
void Push(TIPO v);
TIPO Pop();
private:
nodo<TIPO> *ultimo;
};

La implementacin de las funciones es la misma que para el ejemplo de la pgina anterior.


template<class TIPO>
pila<TIPO>::~pila() \{
while(ultimo) Pop();
}
template<class TIPO>
void pila<TIPO>::Push(TIPO v) \{
nodo<TIPO> *nuevo;
/* Crear un nodo nuevo */
nuevo = new nodo<TIPO>(v, ultimo);
/* Ahora, el comienzo de nuestra pila es en nuevo nodo */
ultimo = nuevo;
}
template<class TIPO>
TIPO pila<TIPO>::Pop() \{
nodo<TIPO> *Nodo; /* variable auxiliar para manipular nodo */
TIPO v;
/* variable auxiliar para retorno */
if(!ultimo) return 0; /* Si no hay nodos en la pila retornamos 0 */
/* Nodo apunta al primer elemento de la pila */
Nodo = ultimo;
/* Asignamos a pila toda la pila menos el primer elemento */
ultimo = Nodo->siguiente;
/* Guardamos el valor de retorno */
v = Nodo->valor;
/* Borrar el nodo */
delete Nodo;
return v;
}

71

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Eso es todo, ya slo falta usar nuestras clases para un ejemplo prctico:
#include <iostream>
#include "CCadena.h"
using namespace std;
template<class TIPO> class pila;
template<class TIPO>
class nodo \{
public:
nodo(TIPO v, nodo<TIPO> *sig = NULL) \{
valor = v;
siguiente = sig;
}
private:
TIPO valor;
nodo<TIPO> *siguiente;
friend class pila<TIPO>;
};
template<class TIPO>
class pila \{
public:
pila() : ultimo(NULL) \{}
~pila();
void Push(TIPO v);
TIPO Pop();
private:
nodo<TIPO> *ultimo;
};
template<class TIPO>
pila<TIPO>::~pila() \{
while(ultimo) Pop();
}
template<class TIPO>
void pila<TIPO>::Push(TIPO v) \{
nodo<TIPO> *nuevo;
/* Crear un nodo nuevo */
nuevo = new nodo<TIPO>(v, ultimo);
/* Ahora, el comienzo de nuestra pila es en nuevo nodo */
ultimo = nuevo;
}
template<class TIPO>
TIPO pila<TIPO>::Pop() \{

72

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

nodo<TIPO> *Nodo; /* variable auxiliar para manipular nodo */


TIPO v;
/* variable auxiliar para retorno */
if(!ultimo) return 0; /* Si no hay nodos en la pila retornamos 0 */
/* Nodo apunta al primer elemento de la pila */
Nodo = ultimo;
/* Asignamos a pila toda la pila menos el primer elemento */
ultimo = Nodo->siguiente;
/* Guardamos el valor de retorno */
v = Nodo->valor;
/* Borrar el nodo */
delete Nodo;
return v;
}
int main() \{
pila<int> iPila;
pila<float> fPila;
pila<double> dPila;
pila<char> cPila;
pila<Cadena> sPila;
// Prueba con <int>
iPila.Push(20);
iPila.Push(10);
cout << iPila.Pop() << ",";
iPila.Push(40);
iPila.Push(30);
cout << iPila.Pop()
cout << iPila.Pop()
iPila.Push(90);
cout << iPila.Pop()
cout << iPila.Pop()

<< ",";
<< ",";
<< ",";
<< endl;

// Prueba con <float>


fPila.Push(20.01);
fPila.Push(10.02);
cout << fPila.Pop() << ",";
fPila.Push(40.03);
fPila.Push(30.04);
cout << fPila.Pop()
cout << fPila.Pop()
fPila.Push(90.05);
cout << fPila.Pop()
cout << fPila.Pop()

<< ",";
<< ",";
<< ",";
<< endl;

// Prueba con <double>


dPila.Push(0.0020);
dPila.Push(0.0010);
cout << dPila.Pop() << ",";
dPila.Push(0.0040);
dPila.Push(0.0030);

73

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

cout << dPila.Pop()


cout << dPila.Pop()
dPila.Push(0.0090);
cout << dPila.Pop()
cout << dPila.Pop()

<< ",";
<< ",";
<< ",";
<< endl;

// Prueba con <Cadena>


cPila.Push('x');
cPila.Push('y');
cout << cPila.Pop() << ",";
cPila.Push('a');
cPila.Push('b');
cout << cPila.Pop()
cout << cPila.Pop()
cPila.Push('m');
cout << cPila.Pop()
cout << cPila.Pop()

<< ",";
<< ",";
<< ",";
<< endl;

// Prueba con <char *>


sPila.Push("Hola");
sPila.Push("somos");
cout << sPila.Pop() << ",";
sPila.Push("programadores");
sPila.Push("buenos");
cout << sPila.Pop()
cout << sPila.Pop()
sPila.Push("!!!!");
cout << sPila.Pop()
cout << sPila.Pop()

<< ",";
<< ",";
<< ",";
<< endl;

cin.get();
return 0;
}

8. COLAS
8.1. DEFINICIN
Una cola es un tipo especial de lista abierta en la que slo se pueden insertar nodos en uno de los
extremos de la lista y slo se pueden eliminar nodos en el otro. Adems, como sucede con las
pilas, las escrituras de datos siempre son inserciones de nodos, y las lecturas siempre eliminan el
nodo ledo.
Este tipo de lista es conocido como lista FIFO (First In First Out), el primero en entrar es el
primero en salir.
El smil cotidiano es una cola para comprar, por ejemplo, las entradas del cine. Los nuevos
compradores slo pueden colocarse al final de la cola, y slo el primero de la cola puede comprar
la entrada.
El nodo tpico para construir pilas es el mismo que vimos en los captulos anteriores para la
construccin de listas y pilas:

74

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

struct nodo \{
int dato;
struct nodo *siguiente;
};

8.2. DECLARACIONES DE TIPOS PARA MANEJAR COLAS EN C++


Los tipos que definiremos normalmente para manejar colas sern casi los mismos que para
manejar listas y pilas, tan slo cambiaremos algunos nombres:
typedef struct _nodo \{
int dato;
struct _nodo *siguiente;
} tipoNodo;
typedef tipoNodo *pNodo;
typedef tipoNodo *Cola;

tipoNodo es el tipo para declarar nodos, evidentemente.


pNodo es el tipo para declarar punteros a un nodo.
Cola es el tipo para declarar colas.

Cola

Es evidente, a la vista del grfico, que una cola es una lista abierta. As que sigue siendo muy
importante que nuestro programa nunca pierda el valor del puntero al primer elemento, igual
que pasa con las listas abiertas. Adems, debido al funcionamiento de las colas, tambin
deberemos mantener un puntero para el ltimo elemento de la cola, que ser el punto donde
insertemos nuevos nodos.
Teniendo en cuenta que las lecturas y escrituras en una cola se hacen siempre en extremos
distintos, lo ms fcil ser insertar nodos por el final, a continuacin del nodo que no tiene nodo
siguiente, y leerlos desde el principio, hay que recordar que leer un nodo implica eliminarlo de la
cola.
8.3. OPERACIONES BSICAS CON COLAS
De nuevo nos encontramos ante una estructura con muy pocas operaciones disponibles. Las colas
slo permiten aadir y leer elementos:
Aadir: Inserta un elemento al final de la cola.
Leer: Lee y elimina un elemento del principio de la cola.

75

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

8.4. AADIR UN ELEMENTO


Las operaciones con colas son muy sencillas, prcticamente no hay casos especiales, salvo que la
cola est vaca.
8.4.1. AADIR ELEMENTO EN UNA COLA VACA

Cola vaca

Partiremos de que ya tenemos el nodo a insertar y, por supuesto un puntero que apunte a l,
adems los punteros que definen la cola, primero y ltimo que valdrn NULL:

Elemento encolado

El proceso es muy simple, bastar con que:


1. Hacer que nodo->siguiente apunte a NULL.
2. Que el puntero primero apunte a nodo.
3. Y que el puntero ltimo tambin apunte a nodo.
8.4.2. AADIR ELEMENTO EN UNA COLA NO VACA

Cola no vaca

De nuevo partiremos de un nodo a insertar, con un puntero que apunte a l, y de una cola, en
este caso, al no estar vaca, los punteros primero y ltimo no sern nulos:

Elemento encolado

76

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

El proceso sigue siendo muy sencillo:


1. Hacemos que nodo->siguiente apunte a NULL.
2. Despus que ultimo->siguiente apunte a nodo.
3. Y actualizamos ltimo, haciendo que apunte a nodo.
8.4.3. AADIR ELEMENTO EN UNA COLA, CASO GENERAL
Para generalizar el caso anterior, slo necesitamos aadir una operacin:
1. Hacemos que nodo->siguiente apunte a NULL.
2. Si ultimo no es NULL, hacemos que ultimo->siguiente apunte a nodo.
3. Y actualizamos ltimo, haciendo que apunte a nodo.
4. Si primero es NULL, significa que la cola estaba vaca, as que haremos que primero apunte
tambin a nodo.
8.5. LEER UN ELEMENTO DE UNA COLA, IMPLICA ELIMINARLO
Ahora tambin existen dos casos, que la cola tenga un solo elemento o que tenga ms de uno.
8.5.1. LEER UN ELEMENTO EN UNA COLA CON MS DE UN ELEMENTO
Usaremos un puntero a un nodo auxiliar:

Cola con ms de un elemento

1. Hacemos que nodo apunte al primer elemento de la cola, es decir a primero.


2. Asignamos a primero la direccin del segundo nodo de la pila: primero->siguiente.
3. Guardamos el contenido del nodo para devolverlo como retorno, recuerda que la operacin
de lectura en colas implican tambin borrar.
4. Liberamos la memoria asignada al primer nodo, el que queremos eliminar.

Elemento desencolado

77

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

8.5.2. LEER UN ELEMENTO EN UNA COLA CON UN SOLO ELEMENTO

Cola con un elemento

Tambin necesitamos un puntero a un nodo auxiliar:


1. Hacemos que nodo apunte al primer elemento de la pila, es decir a primero.

Elemento desencolado

2. Asignamos NULL a primero, que es la direccin del segundo nodo terico de la cola: primero>siguiente.
3. Guardamos el contenido del nodo para devolverlo como retorno, recuerda que la operacin
de lectura en colas implican tambin borrar.
4. Liberamos la memoria asignada al primer nodo, el que queremos eliminar.
5. Hacemos que ultimo apunte a NULL, ya que la lectura ha dejado la cola vaca.
8.5.3. LEER UN ELEMENTO EN UNA COLA CASO GENERAL
1. Hacemos que nodo apunte al primer elemento de la pila, es decir a primero.
2. Asignamos a primero la direccin del segundo nodo de la pila: primero->siguiente.
3. Guardamos el contenido del nodo para devolverlo como retorno, recuerda que la operacin
de lectura en colas implican tambin borrar.
4. Liberamos la memoria asignada al primer nodo, el que queremos eliminar.
5. Si primero es NULL, hacemos que ultimo tambin apunte a NULL, ya que la lectura ha dejado
la cola vaca.
8.6 EJEMPLO DE COLA EN C++ USANDO CLASES
Ya hemos visto que las colas son casos particulares de listas abiertas, pero ms simples. Como en
los casos anteriores, veremos ahora un ejemplo de cola usando clases.
Para empezar, y como siempre, necesitaremos dos clases, una para nodo y otra para cola.
Adems la clase para nodo debe ser amiga de la clase cola, ya que sta debe acceder a los
miembros privados de nodo.
class nodo \{
public:
nodo(int v, nodo *sig = NULL) \{

78

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

valor = v;
siguiente = sig;
}
private:
int valor;
nodo *siguiente;
friend class cola;
};
typedef nodo *pnodo;
class cola \{
public:
cola() : ultimo(NULL), primero(NULL) \{}
cola();
void Anadir(int v);
int Leer();
private:
pnodo primero, ultimo;
};

8.6.1. CDIGO DEL EJEMPLO COMPLETO


#include <iostream>
using namespace std;
class nodo \{
public:
nodo(int v, nodo *sig = NULL) \{
valor = v;
siguiente = sig;
}
private:
int valor;
nodo *siguiente;
friend class cola;
};
typedef nodo *pnodo;
class cola \{
public:
cola() : ultimo(NULL), primero(NULL) \{}
~cola();
void Push(int v);

79

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

int Pop();
private:
pnodo ultimo;
};
cola::~cola() \{
while(primero) Leer();
}
void cola::Anadir(int v) \{
pnodo nuevo;
/* Crear un nodo nuevo */
nuevo = new nodo(v);
/* Si la cola no estaba vaca, aadimos el nuevo a continuacin de ultimo */
if(ultimo) ultimo->siguiente = nuevo;
/* Ahora, el ltimo elemento de la cola es el nuevo nodo */
ultimo = nuevo;
/* Si primero es NULL, la cola estaba vaca, ahora primero apuntar tambin al
nuevo nodo */
if(!primero) primero = nuevo;
}
int cola::Leer() \{
pnodo nodo; /* variable auxiliar para manipular nodo */
int v;
/* variable auxiliar para retorno */
/* Nodo apunta al primer elemento de la pila */
nodo = primero;
if(!nodo) return 0; /* Si no hay nodos en la pila retornamos 0 */
/* Asignamos a primero la direccin del segundo nodo */
primero = nodo->siguiente;
/* Guardamos el valor de retorno */
v = nodo->valor;
/* Borrar el nodo */
delete nodo;
/* Si la cola qued vaca, ultimo debe ser NULL tambin*/
if(!primero) ultimo = NULL;
return v;
}
int main() \{
cola Cola;
Cola.Anadir(20);
cout << "Aadir(20)" << endl;
Cola.Anadir(10);
cout << "Aadir(10)" << endl;
cout << "Leer: " << Cola.Leer() << endl;
Cola.Anadir(40);
cout << "Aadir(40)" << endl;
Cola.Anadir(30);
cout << "Aadir(30)" << endl;

80

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

cout << "Leer: " << Cola.Leer()


cout << "Leer: " << Cola.Leer()
Cola.Anadir(90);
cout << "Aadir(90)" << endl;
cout << "Leer: " << Cola.Leer()
cout << "Leer: " << Cola.Leer()

<< endl;
<< endl;

<< endl;
<< endl;

cin.get();
return 0;
}

9. ARBOLES
9.1 DEFINICIN
Un rbol es una estructura no lineal en la que cada nodo puede apuntar a uno o varios nodos.
Tambin se suele dar una definicin recursiva: un rbol es una estructura en compuesta por un
dato y varios rboles.
Esto son definiciones simples. Pero las caractersticas que implican no lo son tanto.

rbol

Definiremos varios conceptos. En relacin con otros nodos:


Nodo hijo: cualquiera de los nodos apuntados por uno de los nodos del rbol. En el ejemplo,
'L' y 'M' son hijos de 'G'.
Nodo padre: nodo que contiene un puntero al nodo actual. En el ejemplo, el nodo 'A' es
padre de 'B', 'C' y 'D'.
Los rboles con los que trabajaremos tienen otra caracterstica importante: cada nodo slo puede
ser apuntado por otro nodo, es decir, cada nodo slo tendr un padre. Esto hace que estos
rboles estn fuertemente jerarquizados, y es lo que en realidad les da la apariencia de rboles.
En cuanto a la posicin dentro del rbol:
Nodo raz: nodo que no tiene padre. Este es el nodo que usaremos para referirnos al rbol. En
el ejemplo, ese nodo es el 'A'.
Nodo hoja: nodo que no tiene hijos. En el ejemplo hay varios: 'F', 'H', 'I', 'K', 'L', 'M', 'N' y 'O'.
Nodo rama: aunque esta definicin apenas la usaremos, estos son los nodos que no
pertenecen a ninguna de las dos categoras anteriores. En el ejemplo: 'B', 'C', 'D', 'E', 'G' y 'J'.

81

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Otra caracterstica que normalmente tendrn nuestros rboles es que todos los nodos contengan
el mismo nmero de punteros, es decir, usaremos la misma estructura para todos los nodos del
rbol. Esto hace que la estructura sea ms sencilla, y por lo tanto tambin los programas para
trabajar con ellos.
Tampoco es necesario que todos los nodos hijos de un nodo concreto existan. Es decir, que
pueden usarse todos, algunos o ninguno de los punteros de cada nodo.
Un rbol en el que en cada nodo o bien todos o ninguno de los hijos existe, se llama rbol
completo.
En una cosa, los rboles se parecen al resto de las estructuras que hemos visto: dado un nodo
cualquiera de la estructura, podemos considerarlo como una estructura independiente. Es decir,
un nodo cualquiera puede ser considerado como la raz de un rbol completo.
Existen otros conceptos que definen las caractersticas del rbol, en relacin a su tamao:
Orden: es el nmero potencial de hijos que puede tener cada elemento de rbol. De este
modo, diremos que un rbol en el que cada nodo puede apuntar a otros dos es de orden dos,
si puede apuntar a tres ser de orden tres, etc.
Grado: el nmero de hijos que tiene el elemento con ms hijos dentro del rbol. En el rbol
del ejemplo, el grado es tres, ya que tanto 'A' como 'D' tienen tres hijos, y no existen
elementos con ms de tres hijos.
Nivel: se define para cada elemento del rbol como la distancia a la raz, medida en nodos. El
nivel de la raz es cero y el de sus hijos uno. As sucesivamente. En el ejemplo, el nodo 'D'
tiene nivel 1, el nodo 'G' tiene nivel 2, y el nodo 'N', nivel 3.
Altura: la altura de un rbol se define como el nivel del nodo de mayor nivel. Como cada
nodo de un rbol puede considerarse a su vez como la raz de un rbol, tambin podemos
hablar de altura de ramas. El rbol del ejemplo tiene altura 3, la rama 'B' tiene altura 2, la
rama 'G' tiene altura 1, la 'H' cero, etc.
Los rboles de orden dos son bastante especiales, de hecho les dedicaremos varios captulos.
Estos rboles se conocen tambin como rboles binarios.
Frecuentemente, aunque tampoco es estrictamente necesario, para hacer ms fcil moverse a
travs del rbol, aadiremos un puntero a cada nodo que apunte al nodo padre. De este modo
podremos avanzar en direccin a la raz, y no slo hacia las hojas.
Es importante conservar siempre el nodo raz ya que es el nodo a partir del cual se desarrolla el
rbol, si perdemos este nodo, perderemos el acceso a todo el rbol.
El nodo tpico de un rbol difiere de los nodos que hemos visto hasta ahora para listas, aunque
slo en el nmero de nodos. Veamos un ejemplo de nodo para crear rboles de orden tres:
struct nodo \{
int dato;
struct nodo *rama1;
struct nodo *rama2;
struct nodo *rama3;
};

82

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

O generalizando ms:
#define ORDEN 5
struct nodo \{
int dato;
struct nodo *rama[ORDEN];
};

9.2 DECLARACIONES DE TIPOS PARA MANEJAR RBOLES EN C++


Para C++, y basndonos en la declaracin de nodo que hemos visto ms arriba, trabajaremos con
los siguientes tipos:
typedef struct _nodo \{
int dato;
struct _nodo *rama[ORDEN];
} tipoNodo;
typedef tipoNodo *pNodo;
typedef tipoNodo *Arbol;

Al igual que hicimos con las listas que hemos visto hasta ahora, declaramos un tipo tipoNodo para
declarar nodos, y un tipo pNodo para es el tipo para declarar punteros a un nodo.
rbol es el tipo para declarar rboles de orden ORDEN.

rbol

El movimiento a travs de rboles, salvo que implementemos punteros al nodo padre, ser
siempre partiendo del nodo raz hacia un nodo hoja. Cada vez que lleguemos a un nuevo nodo
podremos optar por cualquiera de los nodos a los que apunta para avanzar al siguiente nodo.
En general, intentaremos que exista algn significado asociado a cada uno de los punteros dentro
de cada nodo, los rboles que estamos viendo son abstractos, pero las aplicaciones no tienen por
qu serlo. Un ejemplo de estructura en rbol es el sistema de directorios y ficheros de un sistema
operativo. Aunque en este caso se trata de rboles con nodos de dos tipos, nodos directorio y
nodos fichero, podramos considerar que los nodos hoja son ficheros y los nodos rama son
directorios.
Otro ejemplo podra ser la tabla de contenido de un libro, por ejemplo de este mismo curso,
dividido en captulos, y cada uno de ellos en subcaptulos. Aunque el libro sea algo lineal, como

83

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

una lista, en el que cada captulo sigue al anterior, tambin es posible acceder a cualquier punto
de l a travs de la tabla de contenido.
Tambin se suelen organizar en forma de rbol los organigramas de mando en empresas o en el
ejrcito, y los rboles genealgicos.
9.3 OPERACIONES BSICAS CON RBOLES
Salvo que trabajemos con rboles especiales, como los que veremos ms adelante, las inserciones
sern siempre en punteros de nodos hoja o en punteros libres de nodos rama. Con estas
estructuras no es tan fcil generalizar, ya que existen muchas variedades de rboles.
De nuevo tenemos casi el mismo repertorio de operaciones de las que disponamos con las listas:
Aadir o insertar elementos.
Buscar o localizar elementos.
Borrar elementos.
Moverse a travs del rbol.
Recorrer el rbol completo.
Los algoritmos de insercin y borrado dependen en gran medida del tipo de rbol que estemos
implementando, de modo que por ahora los pasaremos por alto y nos centraremos ms en el
modo de recorrer rboles.
9.4 RECORRIDOS POR RBOLES
El modo evidente de moverse a travs de las ramas de un rbol es siguiendo los punteros, del
mismo modo en que nos movamos a travs de las listas.
Esos recorridos dependen en gran medida del tipo y propsito del rbol, pero hay ciertos
recorridos que usaremos frecuentemente. Se trata de aquellos recorridos que incluyen todo el
rbol.
Hay tres formas de recorrer un rbol completo, y las tres se suelen implementar mediante
recursividad. En los tres casos se sigue siempre a partir de cada nodo todas las ramas una por
una.
Supongamos que tenemos un rbol de orden tres, y queremos recorrerlo por completo.
Partiremos del nodo raz:
RecorrerArbol(raiz);

La funcin RecorrerArbol, aplicando recursividad, ser tan sencilla como invocar de nuevo a la
funcin RecorrerArbol para cada una de las ramas:
void RecorrerArbol(Arbol a) \{
if(a == NULL) return;
RecorrerArbol(a->rama[0]);
RecorrerArbol(a->rama[1]);
RecorrerArbol(a->rama[2]);
}

84

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Lo que diferencia los distintos mtodos de recorrer el rbol no es el sistema de hacerlo, sino el
momento que elegimos para procesar el valor de cada nodo con relacin a los recorridos de cada
una de las ramas.

rbol

Los tres tipos son:


9.4.1. PRE-ORDEN
En este tipo de recorrido, el valor del nodo se procesa antes de recorrer las ramas:
void PreOrden(Arbol a) \{
if(a == NULL) return;
Procesar(dato);
RecorrerArbol(a->rama[0]);
RecorrerArbol(a->rama[1]);
RecorrerArbol(a->rama[2]);
}

Si seguimos el rbol del ejemplo en pre-orden, y el proceso de los datos es sencillamente


mostrarlos por pantalla, obtendremos algo as:
ABEKFCGLMDHIJNO
9.4.2. IN-ORDEN
En este tipo de recorrido, el valor del nodo se procesa despus de recorrer la primera rama y
antes de recorrer la ltima. Esto tiene ms sentido en el caso de rboles binarios, y tambin
cuando existen ORDEN-1 datos, en cuyo caso procesaremos cada dato entre el recorrido de cada
dos ramas (este es el caso de los rboles-b):
void InOrden(Arbol a) \{
if(a == NULL) return;
RecorrerArbol(a->rama[0]);
Procesar(dato);
RecorrerArbol(a->rama[1]);
RecorrerArbol(a->rama[2]);

85

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Si seguimos el rbol del ejemplo en in-orden, y el proceso de los datos es sencillamente


mostrarlos por pantalla, obtendremos algo as:
KEBFALGMCHDINJO
9.4.3. POST-ORDEN
En este tipo de recorrido, el valor del nodo se procesa despus de recorrer todas las ramas:
void PostOrden(Arbol a) \{
if(a == NULL) return;
RecorrerArbol(a->rama[0]);
RecorrerArbol(a->rama[1]);
RecorrerArbol(a->rama[2]);
Procesar(dato);
}

Si seguimos el rbol del ejemplo en post-orden, y el proceso de los datos es sencillamente


mostrarlos por pantalla, obtendremos algo as:
KEFBLMGCHINOJDA
9.5 ELIMINAR NODOS EN UN RBOL
El proceso general es muy sencillo en este caso, pero con una importante limitacin, slo
podemos borrar nodos hoja:
El proceso sera el siguiente:
1. Buscar el nodo padre del que queremos eliminar.
2. Buscar el puntero del nodo padre que apunta al nodo que queremos borrar.
3. Liberar el nodo.
4. padre->nodo[i] = NULL;.
Cuando el nodo a borrar no sea un nodo hoja, diremos que hacemos una "poda", y en ese caso
eliminaremos el rbol cuya raz es el nodo a borrar. Se trata de un procedimiento recursivo,
aplicamos el recorrido Post-Orden, y el proceso ser borrar el nodo.
El procedimiento es similar al de borrado de un nodo:
1. Buscar el nodo padre del que queremos eliminar.
2. Buscar el puntero del nodo padre que apunta al nodo que queremos borrar.
3. Podar el rbol cuyo padre es nodo.
4. padre->nodo[i] = NULL;.
En el rbol del ejemplo, para podar la rama 'B', recorreremos el subrbol 'B' en post-orden,
eliminando cada nodo cuando se procese, de este modo no perdemos los punteros a las ramas
apuntadas por cada nodo, ya que esas ramas se borrarn antes de eliminar el nodo.
De modo que el orden en que se borrarn los nodos ser:
KEFyB

86

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

9.6 RBOLES ORDENADOS


A partir del siguiente captulo slo hablaremos de rboles ordenados, ya que son los que tienen
ms inters desde el punto de vista de TAD, y los que tienen ms aplicaciones genricas.
Un rbol ordenado, en general, es aquel a partir del cual se puede obtener una secuencia
ordenada siguiendo uno de los recorridos posibles del rbol: in-orden, pre-orden o post-orden.
En estos rboles es importante que la secuencia se mantenga ordenada aunque se aadan o se
eliminen nodos.
Existen varios tipos de rboles ordenados, que veremos a continuacin:
rboles binarios de bsqueda (ABB): son rboles de orden 2 que mantienen una secuencia
ordenada si se recorren en in-orden.
rboles AVL: son rboles binarios de bsqueda equilibrados, es decir, los niveles de cada rama
para cualquier nodo no difieren en ms de 1.
rboles perfectamente equilibrados: son rboles binarios de bsqueda en los que el nmero
de nodos de cada rama para cualquier nodo no difieren en ms de 1. Son por lo tanto rboles
AVL tambin.
rboles 2-3: son rboles de orden 3, que contienen dos claves en cada nodo y que estn
tambin equilibrados. Tambin generan secuencias ordenadas al recorrerlos en in-orden.
rboles-B: caso general de rboles 2-3, que para un orden M, contienen M-1 claves.
10. ARBOLES BINARIOS DE BUSQUEDA
10.1 DEFINICIN
Se trata de rboles de orden 2 en los que se cumple que para cada nodo, el valor de la clave de la
raz del subrbol izquierdo es menor que el valor de la clave del nodo y que el valor de la clave
raz del subrbol derecho es mayor que el valor de la clave del nodo.

rbol binario de bsqueda

10.2 OPERACIONES EN ABB


El repertorio de operaciones que se pueden realizar sobre un ABB es parecido al que
realizbamos sobre otras estructuras de datos, ms alguna otra propia de rboles:

87

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Buscar un elemento.
Insertar un elemento.
Borrar un elemento.
Movimientos a travs del rbol:
Izquierda.
Derecha.
Raz.
Informacin:
Comprobar si un rbol est vaco.
Calcular el nmero de nodos.
Comprobar si el nodo es hoja.
Calcular la altura de un nodo.
Calcular la altura de un rbol.

10.3 BUSCAR UN ELEMENTO


Partiendo siempre del nodo raz, el modo de buscar un elemento se define de forma recursiva.
Si el rbol est vaco, terminamos la bsqueda: el elemento no est en el rbol.
Si el valor del nodo raz es igual que el del elemento que buscamos, terminamos la bsqueda
con xito.
Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos la bsqueda
en el rbol izquierdo.
Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos la bsqueda
en el rbol derecho.
El valor de retorno de una funcin de bsqueda en un ABB puede ser un puntero al nodo
encontrado, o NULL, si no se ha encontrado.
10.4 INSERTAR UN ELEMENTO
Para insertar un elemento nos basamos en el algoritmo de bsqueda. Si el elemento est en el
rbol no lo insertaremos. Si no lo est, lo insertaremos a continuacin del ltimo nodo visitado.
Necesitamos un puntero auxiliar para conservar una referencia al padre del nodo raz actual. El
valor inicial para ese puntero es NULL.
Padre = NULL
nodo = Raz
Bucle: mientras actual no sea un rbol vaco o hasta que se encuentre el elemento.
Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos
la bsqueda en el rbol izquierdo: Padre=nodo, nodo=nodo->izquierdo.
Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos
la bsqueda en el rbol derecho: Padre=nodo, nodo=nodo->derecho.
Si nodo no es NULL, el elemento est en el rbol, por lo tanto salimos.
Si Padre es NULL, el rbol estaba vaco, por lo tanto, el nuevo rbol slo contendr el
nuevo elemento, que ser la raz del rbol.

88

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Si el elemento es menor que el Padre, entonces insertamos el nuevo elemento como un


nuevo rbol izquierdo de Padre.
Si el elemento es mayor que el Padre, entonces insertamos el nuevo elemento como un
nuevo rbol derecho de Padre.
Este modo de actuar asegura que el rbol sigue siendo ABB.
10.5 BORRAR UN ELEMENTO
Para borrar un elemento tambin nos basamos en el algoritmo de bsqueda. Si el elemento no
est en el rbol no lo podremos borrar. Si est, hay dos casos posibles:
1. Se trata de un nodo hoja: en ese caso lo borraremos directamente.
2. Se trata de un nodo rama: en ese caso no podemos eliminarlo, puesto que perderamos todos
los elementos del rbol de que el nodo actual es padre. En su lugar buscamos el nodo ms a
la izquierda del subrbol derecho, o el ms a la derecha del subrbol izquierdo e
intercambiamos sus valores. A continuacin eliminamos el nodo hoja.
Necesitamos un puntero auxiliar para conservar una referencia al padre del nodo raz actual. El
valor inicial para ese puntero es NULL.
Padre = NULL
Si el rbol est vaco: el elemento no est en el rbol, por lo tanto salimos sin eliminar ningn
elemento.
Si el valor del nodo raz es igual que el del elemento que buscamos, estamos ante uno de los
siguientes casos:
El nodo raz es un nodo hoja:
Si 'Padre' es NULL, el nodo raz es el nico del rbol, por lo tanto el puntero al
rbol debe ser NULL.
Si raz es la rama derecha de 'Padre', hacemos que esa rama apunte a NULL.
Si raz es la rama izquierda de 'Padre', hacemos que esa rama apunte a NULL.
Eliminamos el nodo, y salimos.
El nodo no es un nodo hoja:
Buscamos el 'nodo' ms a la izquierda del rbol derecho de raz o el ms a la
derecha del rbol izquierdo. Hay que tener en cuenta que puede que slo
exista uno de esos rboles. Al mismo tiempo, actualizamos 'Padre' para que
apunte al padre de 'nodo'.
Intercambiamos los elementos de los nodos raz y 'nodo'.
Borramos el nodo 'nodo'. Esto significa volver a (1), ya que puede suceder
que 'nodo' no sea un nodo hoja. (Ver ejemplo 3)
Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos la bsqueda
en el rbol izquierdo.
Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos la bsqueda
en el rbol derecho.

89

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

EJEMPLO 1: BORRAR UN NODO HOJA


En el rbol de ejemplo, borrar el nodo 3.
1. Localizamos el nodo a borrar, al tiempo que mantenemos un puntero a 'Padre'.
2. Hacemos que el puntero de 'Padre' que apuntaba a 'nodo', ahora apunte a NULL.
3. Borramos el 'nodo'.

Borrar un nodo hoja

EJEMPLO 2: BORRAR UN NODO RAMA CON INTERCAMBIO DE UN NODO HOJA.


En el rbol de ejemplo, borrar el nodo 4.
1. Localizamos el nodo a borrar ('raz').
2. Buscamos el nodo ms a la derecha del rbol izquierdo de 'raz', en este caso el 3, al tiempo
que mantenemos un puntero a 'Padre' a 'nodo'.
3. Intercambiamos los elementos 3 y 4.
4. Hacemos que el puntero de 'Padre' que apuntaba a 'nodo', ahora apunte a NULL.
5. Borramos el 'nodo'.

Borrar con intercambio de nodo hoja

EJEMPLO 3: BORRAR UN NODO RAMA CON INTERCAMBIO DE UN NODO RAMA.


Para este ejemplo usaremos otro rbol. En ste borraremos el elemento 6.

90

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

rbol binario de bsqueda

1. Localizamos el nodo a borrar ('raz').


2. Buscamos el nodo ms a la izquierda del rbol derecho de 'raz', en este caso el 12, ya que el
rbol derecho no tiene nodos a su izquierda, si optamos por la rama izquierda, estaremos en
un caso anlogo. Al mismo tiempo que mantenemos un puntero a 'Padre' a 'nodo'.
3. Intercambiamos los elementos 6 y 12.
4. Ahora tenemos que repetir el bucle para el nodo 6 de nuevo, ya que no podemos eliminarlo.

Borrar con intercambio de nodo rama (1)

5. Localizamos de nuevo el nodo a borrar ('raz').


6. Buscamos el nodo ms a la izquierda del rbol derecho de 'raz', en este caso el 16, al mismo
tiempo que mantenemos un puntero a 'Padre' a 'nodo'.
7. Intercambiamos los elementos 6 y 16.
8. Hacemos que el puntero de 'Padre' que apuntaba a 'nodo', ahora apunte a NULL.
9. Borramos el 'nodo'.

91

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Borrar con intercambio de nodo rama (2)

Este modo de actuar asegura que el rbol sigue siendo ABB.


10.6 MOVIMIENTOS A TRAVS DEL RBOL
No hay mucho que contar. Nuestra estructura se referenciar siempre mediante un puntero al
nodo Raz, este puntero no debe perderse nunca.
Para movernos a travs del rbol usaremos punteros auxiliares, de modo que desde cualquier
puntero los movimientos posibles sern: moverse al nodo raz de la rama izquierda, moverse al
nodo raz de la rama derecha o moverse al nodo Raz del rbol.
10.7 INFORMACIN
Hay varios parmetros que podemos calcular o medir dentro de un rbol. Algunos de ellos nos
darn idea de lo eficientemente que est organizado o el modo en que funciona.
10.7.1. COMPROBAR SI UN RBOL EST VACO.
Un rbol est vaco si su raz es NULL.
10.7.2. CALCULAR EL NMERO DE NODOS.
Tenemos dos opciones para hacer esto, una es llevar siempre la cuenta de nodos en el rbol al
mismo tiempo que se aaden o eliminan elementos. La otra es, sencillamente, contarlos.
Para contar los nodos podemos recurrir a cualquiera de los tres modos de recorrer el rbol: inorden, pre-orden o post-orden, como accin sencillamente incrementamos el contador.
10.7.3. COMPROBAR SI EL NODO ES HOJA.
Esto es muy sencillo, basta con comprobar si tanto el rbol izquierdo como el derecho estn
vacos. Si ambos lo estn, se trata de un nodo hoja.
10.7.4. CALCULAR LA ALTURA DE UN NODO.
No hay un modo directo de hacer esto, ya que no nos es posible recorrer el rbol en la direccin
de la raz. De modo que tendremos que recurrir a otra tcnica para calcular la altura.

92

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Lo que haremos es buscar el elemento del nodo de que queremos averiguar la altura. Cada vez
que avancemos un nodo incrementamos la variable que contendr la altura del nodo.
Empezamos con el nodo raz apuntando a Raz, y la 'Altura' igual a cero.
Si el valor del nodo raz es igual que el del elemento que buscamos, terminamos la bsqueda
y el valor de la altura es 'Altura'.
Incrementamos 'Altura'.
Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos la bsqueda
en el rbol izquierdo.
Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos la bsqueda
en el rbol derecho.
10.7.5. CALCULAR LA ALTURA DE UN RBOL.
La altura del rbol es la altura del nodo de mayor altura. Para buscar este valor tendremos que
recorrer todo el rbol, de nuevo es indiferente el tipo de recorrido que hagamos, cada vez que
cambiemos de nivel incrementamos la variable que contiene la altura del nodo actual, cuando
lleguemos a un nodo hoja compararemos su altura con la variable que contiene la altura del rbol
si es mayor, actualizamos la altura del rbol.
Iniciamos un recorrido del rbol en postorden, con la variable de altura igual a cero.
Cada vez que empecemos a recorrer una nueva rama, incrementamos la altura para ese
nodo.
Despus de procesar las dos ramas, verificamos si la altura del nodo es mayor que la variable
que almacena la altura actual del rbol, si es as, actualizamos esa variable.
10.8 RBOLES DEGENERADOS
Los rboles binarios de bsqueda tienen un gran inconveniente. Por ejemplo, supongamos que
creamos un ABB a partir de una lista de valores ordenada:
2, 4, 5, 8, 9, 12
Difcilmente podremos llamar a la estructura resultante un rbol:

rbol binario de bsqueda degenerado

93

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Esto es lo que llamamos un rbol binario de bsqueda degenerado.


10.9. DECLARACIN DE CLASE ARBOL ABB
Declaramos dos clases, una para nodo y otra para ArbolABB, la clase nodo la declararemos como
parte de la clase ArbolABB, de modo que no tendremos que definir relaciones de amistad, y
evitamos que otras clases o funciones tengan acceso a los datos internos de nodo.
class ArbolABB \{
private:
//// Clase local de Lista para Nodo de ArbolBinario:
class Nodo \{
public:
// Constructor:
Nodo(const int dat, Nodo *izq=NULL, Nodo *der=NULL) :
dato(dat), izquierdo(izq), derecho(der) \{}
// Miembros:
int dato;
Nodo *izquierdo;
Nodo *derecho;
};
// Punteros de la lista, para cabeza y nodo actual:
Nodo *raz;
Nodo *actual;
int contador;
int altura;
public:
// Constructor y destructor bsicos:
ArbolABB() : raz(NULL), actual(NULL) \{}
~ArbolABB() \
// Insertar en rbol ordenado:
void Insertar(const int dat);
// Borrar un elemento del rbol:
void Borrar(const int dat);
// Funcin de bsqueda:
bool Buscar(const int dat);
// Comprobar si el rbol est vaco:
bool Vacio(Nodo *r) \
// Comprobar si es un nodo hoja:
bool EsHoja(Nodo *r) \
// Contar nmero de nodos:
const int NumeroNodos();
const int AlturaArbol();
// Calcular altura de un int:
int Altura(const int dat);
// Devolver referencia al int del nodo actual:
int &ValorActual() \

94

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

// Moverse al nodo raz:


void Raiz() \
// Aplicar una funcin a cada elemento del rbol:
void InOrden(void (*func)(int&) , Nodo *nodo=NULL, bool r=true);
void PreOrden(void (*func)(int&) , Nodo *nodo=NULL, bool r=true);
void PostOrden(void (*func)(int&) , Nodo *nodo=NULL, bool r=true);
private:
// Funciones auxiliares
void Podar(Nodo* &);
void auxContador(Nodo*);
void auxAltura(Nodo*, int);
};

10.10. DEFINICIN DE LAS FUNCIONES MIEMBRO


Las definiciones de la funcin miembro de la clase no difieren demasiado de las que creamos en
C. Tan solo se han sustituido algunos punteros por referencias, y se usa el tipo bool cuando es
aconsejable.
Por ejemplo, en las funciones de recorrido de rboles, la funcin invocada acepta ahora una
referencia a un entero, en lugar de un puntero a un entero.
11. GRAFOS
11.1. INTRODUCCIN
El origen de la palabra grafo es griego y su significado etimolgico es "trazar". Aparece con gran
frecuencia como respuesta a problemas de la vida cotidiana, algunos ejemplos podran ser los
siguientes: un grfico de una serie de tareas a realizar indicando su secuenciacin (un
organigrama), grafos matemticos que representan las relaciones binarias, una red de carreteras,
la red de enlaces ferroviarios o areos o la red elctrica de una ciudad, (ver la figura 1). En cada
caso es conveniente representar grficamente el problema dibujando un grafo como un conjunto
de puntos (nodos o vrtices) con lneas conectndolos (arcos).

De aqu se podra deducir que un grafo es bsicamente un objeto geomtrico aunque en realidad
sea un objeto combinatorio, es decir, un conjunto de puntos y un conjunto de lneas tomado de
entre el conjunto de lneas que une cada par de vrtices. Por otro lado, debido a su generalidad y

95

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

a la gran diversidad de formas que pueden usarse, resulta complejo tratar con todas las ideas
relacionadas con un grafo.
Para facilitar el estudio de este tipo de dato, a continuacin se realizar un estudio de la teora de
grafos desde el punto de vista de las ciencias de la computacin, considerando que dicha teora
es compleja y amplia, aqu slo se realizar una introduccin a la misma, describindose el grafo
como un tipo de dato y mostrndose los problemas tpicos y los algoritmos que permiten
solucionarlos usando un ordenador.
Los grafos son estructuras de datos no lineales que tienen una naturaleza generalmente
dinmica, u estudio podra dividirse en dos grandes bloques; grafos dirigidos y grafos no dirigidos
(pueden ser considerados un caso particular de los anteriores).
Un ejemplo de grafo dirigido lo constituye la red de aguas de una ciudad ya que cada tubera slo
admite que el agua la recorra en un nico sentido, por el contrario, la red de carreteras de un pas
representa en general un grafo no dirigido, puesto que una misma carretera puede ser recorrida
en ambos sentidos. No obstante, podemos dar unas definiciones generales para ambos tipos.
A continuacin daremos definiciones de los dos tipos de grafos y de los conceptos que llevan
asociados.
11.2. NOTACIN Y CONCEPTOS
Un grafo G es un conjunto en el que hay definida una relacin binaria, es decir, G = (V,A) tal que V
es un conjunto de objetos a los que denominaremos vrtices o nodos y A V x V es una relacin
binaria a cuyos elementos denominaremos arcos o aristas.
Dados x, y V, puede ocurrir que:
(x, y)

(x, y)

A, en cuyo caso diremos que x e y estn unidos mediante un arco y,


A, en cuyo caso diremos que no lo estn.

Si las aristas tienen asociada una direccin (las aristas (x,y) y (y,x) no son equivalentes) diremos
que el grafo es dirigido, en otro caso ((x,y)=(y,x)) diremos que el grafo es no dirigido.

96

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

VEAMOS ALGUNOS CONCEPTOS SOBRE GRAFOS:


Diremos que un grafo es completo si A=VxV, o sea, si para cualquier pareja de vrtices
existe una arista que los une(en ambos sentidos si el grafo es no dirigido).El nmero de
aristas ser:
Para grafos dirigidos:

Para grafos no dirigidos:

Donde n=|V|.

A tambin aparece la arista (y,


A implica que (y, x) A.

Un grafo dirigido es simtrico si para toda arista (x, y)


x)

A y es anti simtrico si dada una arista (x, y)

Tanto a las aristas como a los vrtices les puede ser asociada informacin, a esta
informacin se le llama etiqueta, si la etiqueta que se asocia es un nmero se le llama
peso, costo o longitud, un grafo cuyas aristas o vrtices tienen pesos asociados recibe el
nombre de grafo etiquetado o ponderado.
El nmero de elementos de V se denomina orden del grafo, un grafo nulo es un grafo de
orden cero.
Se dice que un vrtice x es incidente a un vrtice y si existe un arco que vaya de x a y ((x,
y) A), a x se le denomina origen del arco y a y extremo del mismo, de igual forma
se dir que y es adyacente a x, en el caso de que el grafo sea no dirigido si x es adyacente
(resp. incidente) a y entonces y tambin es adyacente (resp. incidente) a x.
Se dice que dos arcos son adyacentes cuando tienen un vrtice comn que es a la vez
origen de uno y extremo del otro.
Se denomina camino (algunos autores lo llaman cadena si se trata de un grafo no
dirigido) en un grafo dirigido a una sucesin de arcos adyacentes:

97

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

C= {(v1,v2),(v2,v3),...,(vn-1,vn), vi V}.
La longitud del camino es el nmero de arcos que comprende y en el caso en el que el
grafo sea ponderado se calcular como la suma de los pesos de las aristas que lo
constituyen.
Un camino se dice simple cuando todos sus arcos son distintos y se
dice elemental cuando no utiliza un mismo vrtice dos veces. Por tanto todo camino
elemental es simple y el recproco no es cierto.
Un camino se dice Euleriano si es simple y adems contiene a todos los arcos del grafo.
Un circuito (o ciclo para grafos no dirigidos) es un camino en el que coinciden los vrtices
inicial y final, un circuito se dice simple cuando todos los arcos que lo forman son
distintos y se dice elemental cuando todos los vrtices por los que pasa son distintos.
La longitud de un circuito es el nmero de arcos que lo componen. Un bucle es un
circuito de longitud 1 (estn permitidos los arcos de la forma (i, i) y notemos que un grafo
anti simtrico carecera de ellos).
Un circuito elemental que incluye a todos los vrtices de un grafo lo llamaremos
circuito Hamiltoniano.
Un grafo se denomina simple si no tiene bucles y no existe ms que un camino para unir
dos nodos.
Diremos que un grafo no dirigido es bipartido si el conjunto de sus vrtices puede ser
dividido en dos subconjuntos (disjuntos) de tal forma que cualquiera de las aristas que
componen el grafo tiene cada uno de sus extremos en un subconjunto distinto, un grafo
no dirigido ser bipartido si y slo si no contiene ciclos con un nmero de aristas par.
Dado un grafo G=(V,A),diremos que G'=(V,A' ) con A' A es un grafo parcial de G y
un subgrfo de G es todo grafo G'=(V',A') con V' V y A' A donde A' ser el conjunto
de todas aquellas aristas que unan en el grafo G dos vrtices que estn en V ', se podran
combinar ambas definiciones dando lugar a lo que llamaremos subgrfo parcial .

98

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Se denomina grado de entrada de un vrtice x al nmero de arcos incidentes en l, se


denota

e (x).

Se denomina grado de salida de un vrtice x al nmero de arcos adyacentes a l, se


denota s (x).
Para grafos no dirigidos tanto el grado de entrada como el de salida coinciden y hablamos
entonces de grado y lo notamos por (x).
A todo grafo no dirigido se puede asociar un grafo denominado dual construido de la
siguiente forma:
G (V, A) ------> G' (V', A' )
Donde A' est construido de la siguiente forma: si e1,e2 a A son adyacentes --> (e1,e2) a A' con
e1,e2 a V', en definitiva, para construir un grafo dual se cambian vrtices por aristas y viceversa.

99

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Dado un grafo G, diremos que dos vrtices estn conectados si entre ambos existe un
camino que los une.
Llamaremos componente conexa a un conjunto de vrtices de un grafo tal que entre
cada par de vrtices hay al menos un camino y si se aade algn otro vrtice esta
condicin deja de verificarse. Matemticamente se puede ver como que la conexin es
una relacin de equivalencia que descompone a V en clases de equivalencia, cada uno de
los subgrfos a los que da lugar cada una de esas clases de equivalencia constituira una
componente conexa. Un grafo diremos que es conexo si slo existe una componente
conexa que coincide con todo el grafo.

11.3. BSQUEDA DE CAMINOS MNIMOS EN GRAFOS


Supongamos que tenemos un grafo dirigido sencillo etiquetado G = {V, A} de grado n, V =
{1,..., n} y con etiquetas en los arcos no negativas.
11.3.1. ENTRE UN VRTICE Y TODOS LOS DEMS VRTICES DEL GRAFO
Nos planteamos el problema de dado un vrtice determinar el camino de costo mnimo de ese
vrtice a todos los dems vrtices de V.
Para resolver el problema aplicaremos un algoritmo debido a Dijkstra que esencialmente era a
partir de un conjunto S de vrtices (S V) cuya distancia ms corta desde el origen es conocida y
en cada paso se agrega un nuevo vrtice v a S cuya distancia a su vez desde el origen sea la ms
corta posible. Si la suposicin que hacamos de que las etiquetas son siempre no negativas se
cumple, puede comprobarse que siempre es posible encontrar un camino ms corto desde el
origen y un vrtice v que slo pase a travs de los vrtices de S (camino "inherente"). Si se utiliza
adems un vector D donde se almacena las longitudes de los caminos inherentes ms cortos a
cada vrtice, una vez que S incluya a todos los vrtices, todos los caminos son inherentes de
forma que D contendr la distancia ms corta del origen a cada vrtice.
Notacin:
Origen = vrtice 1 (obviamente esto no es una condicin)
Sea S un vector de n componentes representando el conjunto de vrtices cuya distancia
ms corta desde el origen ya es conocida.
D es un vector de n componentes donde D [i] indica en cada paso la distancia ms corta
entre el origen y el vrtice i:
a. bien mediante el camino directo si existe el arco (i,j).

100

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

b. bien a travs de los vrtices de S (de los que se conoce su distancia ms corta al
origen),
Al final D contendr el costo del camino mnimo entre el origen y cada vrtice.
C es la matriz de costos del grafo. C [1,i] representa el costo del arco (1,i). Si el arco no
existe, se le asigna un valor fuera de rango ()
P es un vector de dimensin n a travs del cual reconstruiremos el camino ms corto del
origen al resto de los vrtices. As P[i] contiene el vrtice inmediato anterior a i en el
camino ms corto.
Inicialmente es evidente que S = {1} y i D[i] = C[1 i] con P[i] = 1
Con estas premisas el algoritmo de Dijkstra se puede esquematizar as:
Algoritmo Dijkstra ()
1. S = {1}
2. for (i = 2; i<=n; i++ )
{
D[i] = C[I,i]
P[i] = 1
}
3. while ( S V )
{
elegir w V-S / D[w] sea mnimo
S= S U{w}
for (cada vrtice v V -S)
if (D[v] > D[w] + C[w, v])
{
D[v] = D[w] + C[w, v]
P[v] = w
}
}

Veamos un ejemplo del algoritmo, supongamos que queremos encontrar los caminos mnimos
del vrtice 1 al resto en el grafo siguiente:

101

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

En principio:

S= {1}

D [2] = 60; D [3] = 10; D [4] = 100; D [5] =

P[i] = 1 i

ITERACIN 1:
V -S = {2,3,4,5} w = 3 -> S = {1,3} -> V -S = {2,4,5}
D [2] = min(D [2] , D [3] + C [3,2]) = min(60, 50) = 50 -> P [2] = 3
D [4] = min(D [4] , D [3] + C [3,4]) = min(100, 40) = 40 -> P [4] = 3
D [5] = min(D [5] , D [3] + C [3,5]) = min (,) =
As D [2] = 50; D [4] = 40; D [5] = 00; P [2] = 3; P [4] = 3; P [5] = 1
ITERACIN 2:
V -S = {2,4,5} w = 4 -> S = {1,3,4} -> V- S = {2,5}
D [2] = min(D [2] , D [4] + C [4,2]) = min(50, 00) = 50 -> P [2] = 3
D [5] = min(D [5] , D [4] + C [4,5]) = min( 00,60) = 60 -> P [5] = 4
As D [2] = 50; D [5] = 60; p [2] = 3; P [5] = 4

102

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

ITERACIN 3:
V -S = {2,5} w = 2 -> S = {1,3,4,2} -> V- S = {5}
D [5] = min(D [5] , D[2] + C [2,5]) = min(60, 55) = 55 -> P [5] = 2
As D [5] = 55; P[5] = 2
Finalmente w = 5 -> S = {1,3,4,2,5} -> FIN DEL ALGORITMO
Para reconstruir el camino ms corto del origen a cada vrtice, se asignan los predecesores en
orden inverso. Por ejemplo, si se quiere conocer el camino desde el origen al vrtice S, se, tiene
que:
P [5] = 2-+ P [2] = 3-+ P [3] = 1 siendo por tanto el camino (1,3,2,5) con costo 55 .
Aunque la implementacin de este algoritmo es simple si la realizamos en base a una matriz de
adyacencia, en la prctica se utiliza normalmente una implementacin en base a listas de
adyacencia. La razn de esta eleccin es que en la primera la eficiencia es O(n2) para cualquier
grafo; sin embargo la mayora de los grafos que nos encontramos en la prctica tiene un nmero
de aristas bastante pequeo (grafos que podemos denominar dispersos o no densos ) y por tanto
el uso de listas de adyacencia se presenta como una solucin ms eficiente. Para conseguir una
mejor eficiencia en esta implementacin del algoritmo de Dijkstra se ha echado mano de una
estructura de datos formada por un APO que tiene como etiqueta los vrtices del grafo y como
clave el coste de ir desde el vrtice inicial en el problema a ese vrtice de tal forma que obtener el
vrtice con mnimo coste sera O(log n).
11.3.2. ENTRE CADA PAR DE VRTICES DEL GRAFO
En lugar de buscar los caminos mnimos de un vrtice a los dems nos podemos plantear buscar
el camino ms corto entre cualquier pareja de vrtices, es decir, dado un grafo dirigido
etiquetado G = {V, A} en el que las etiquetas son no negativas encontrar el camino de longitud "
ms corta entre dos vrtices cualesquiera de ese grafo.
Podra pensarse, para resolver el problema, en aplicar el algoritmo de Dijkstra n veces, una por
vrtice, pero en lugar de eso, aplicaremos un nuevo algoritmo creado por Floyd que va
encontrando los caminos de forma iterativa.
NOTACIN:

V = {1, ..., n} conjunto de vrtices.

103

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

A es una matriz de tamao n x n en la que se calcular en cada Aij la longitud ms corta del
camino que va de i a j.

P es una matriz de tamao n x n que utilizaremos para recuperar los caminos ms cortos.

C es una matriz de dimensin n x n conteniendo los costos de los arcos. Si no existe arco de
un vrtice i a otro j el correspondiente valor C [i,j] = .

Inicialmente A [i,j] = { C[i,j] si i j, 0 si i = j }.


A continuacin se itera sobre A n veces de forma que tras hacer la k iteracin A[i,j] tiene un valor
correspondiente a la longitud ms pequea de cualquier camino de i a j que no pase por un
vrtice de ndice mayor que k, es decir, cualquier vrtice intermedio entre i y j (extremos del
camino) ha de ser menor o igual que k. Por tanto en cada iteracin k se usar la siguiente
frmula:
Ak [i,j] = min(Ak-1 [i,j] ,Ak-1 [i,k] +Ak-1l [k,j])3
Es decir, cada Ak [i,j] se obtiene comparando Ak-1 [i,j], el coste de ir de i a j sin pasar por k o
cualquier vrtice de ndice mayor, con Ak-1 [i,k] +Ak-1 [k,j], el costo de ir primero de i a k y despus
de k a j sin pasar por un vrtice de ndice mayor que k de forma que si el paso por el vrtice k
produce un camino i ms corto que el indicado por Ak-1 [i,j], se elige ese coste para Ak [i,j] .As
mismo, cada iteracin P [i,j] contendr el vrtice k que permiti al algoritmo de Floyd encontrar el
valor ms pequeo de A[i, j] .Inicialmente P[i,j] = 0, puesto que inicialmente el camino ms corto
de i a j es el propio arco.
El algoritmo sera el siguiente:
Algoritmo Floyd ()
1. for (i = 1; i <= n; i++ )
for (j = 1; j <=n ; j++)
{
A[i, j]= C[i, j]
P[i, j]= 0
}
2. for (i = 1; i <= n; i++)
A[i, i]= 0
3. for (k = 1; k <= n; k++)
for (i = 1; i <= n; i++)

104

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

for (j = l; j <=n ; j++)


if ((i j) && (A[i,k]+A[k,j] < A[i, j]))
{
A[i, j]= A[i, k]+A[k, j]
P[i, j]= k
}
Algoritmo recuperar_camino (i, j de tipo vrtice)
1. k= P[i, j]
2. if (k 0)
{
recuperar_camino (i, k)
escribir (k)
recuperar_camino (k, j)
}
Por ejemplo, el camino ms corto entre los vrtices 2 y 4 se determinara llamando a:
recuperar-camino (2,4)
k = 3 -> recuperar-camino (2,3) -> 0
[3] recuperar-camino (3,4) -> k = 1 -> recuperar-camino (3,1) -> 0
[1] recuperar-camino (1,4) -> 0
con la que el camino es (2,3,1,4) con costo 12.
11.4. PRIMITIVAS DEL GRAFO
Dentro del TDA Grafo hemos propuesto las siguientes primitivas:

Grafo ( ) -> constructor del grafo, reserva los recursos e inicializa el grafo a vaco.

Nodo LocalizaLabel (const Tbase e) -> localiza la etiqueta, devuelve el nodo asociado a la
etiqueta e.
PARMETROS: e -> etiqueta asociada al nodo a encontrar.

Bool ExisteArco (nodo o, nodo d) -> nos dice si existe un arco, devuelve true si existe el arco
o false en otro caso.
PARMETROS: o -> nodo origen del arco.
d -> nodo destino del arco.

105

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Int GrafoVacio () -> devuelve 0 si el grafo esta vacio, si no devuelve 1 en otro caso.

Float EtiqArco (nodo o, nodo d) -> devuelve la etiqueta asociada a un arco, es decir el peso
del arco.
PARMETROS: o -> nodo origen del arco.
d -> nodo destino del arco.

Void InsertarNodo (const Tbase dato) -> inserta un nodo nuevo en el grafo.
PARMETROS: dato -> etiqueta del nuevo nodo.

Void InsertarArco (nodo o, nodo d, int valor) -> inserta un arco entre el nodo o y el d,
asociado al arco le podemos dar un valor o peso.
PARMETROS: o -> nodo origen del arco.
d -> nodo destino del arco.
valor -> peso del del arco.

Void BorrarArco (nodo o, nodo d) -> borra el arco existente entre los nodos o y d.
PARMETROS: o -> nodo origen del arco.
d -> nodo destino del arco.

Void DesconectarNodo (nodo a_eliminar) -> elimina un nodo del grafo receptor, todos los
arcos que entran o salen del nodo a eliminar tambien desaparecen.
PARMETROS: a_eliminar -> nodo a eliminar del grafo.
Void CopiarGrafo (Grafo gr) -> copia el grafo gr en el receptor.
PARMETROS: gr -> grafo a copiar.

~Grafo () -> destructor, destruye el grado liberando todos los recursos.

11.5. EJEMPLOS DE USO


IMPRIMIR UN GRAFO
Esta funcin nos imprime en pantalla el contenido de un grafo con etiquetas enteras.
Grafo<int> g;
Void Imprimir ()
{
nodo n1, n2;
arco a;
int cont = 1;
printf (Arcos : \n);
for (n1=g.inicio; n1 != 0; n = n->sig)
{
if (n1->etiqueta != 0)
{
for (a = n1->ady; a != 0; a = a->sig)

106

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

{
n2 = a->destino;
printf (%3d -> %3d (%d), n1->etiqueta, n2->etiqueta, a->valor);
}
if (cont % 4)
printf (,);
else printf ( \n );
cont++;
}
}
if ((cont % 4) != 0)
printf ( \n );
}

11.6. IMPLEMENTACIN DEL GRAFO


Existen diversas representaciones de naturaleza muy diferente que resultan adecuadas para
manejar un grafo,y en la mayora de los casos no se puede decir que una sea mejor que otra
siempre ya que cada una puede resultar ms adecuada dependiendo del problema concreto al
que se desea aplicar, as,si existe una representacin que es peor que otra para todas las
operaciones excepto una es posible que an as nos decantemos por la primera porque
precisamente esa operacin es la nica en la que tenemos especial inters en que se realice de
forma eficiente.
A continuacin veremos dos de las representaciones ms usuales:
11.6.1. MATRIZ DE ADYACENCIA
GRAFOS DIRIGIDOS
G=(V,A) un grafo dirigido con |V|=n .Se define la matriz de adyacencia o booleana asociada a G
como Bnxn con :
b i,j = { 1 si (i,j) A, 0 en otro caso }
Como se puede ver se asocia cada fila y cada columna a un vrtice y los elementos bi,j de la matriz
son 1 si existe el arco (i,j) y 0 en caso contrario.
GRAFOS NO DIRIGIDOS
G=(V,A) un grafo no dirigido con |V|=n .Se define la matriz de adyacencia o booleana asociada a
G como Bnxn con:
b i,i = { 1 si (i,j) A, 0 en otro caso }
La matriz B es simtrica con 1 en las posiciones ij y ji si existe la arista (i,j).

107

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Veamos ahora un ejemplo:

Si el grafo es etiquetado, entonces tanto bi,j como bi,j representan al coste o valor asociado al arco
(i,j) y se suelen denominar matrices de coste. Si el arco (i,j) no pertenece a A entonces se asigna
bi,j o bi,j un valor que no puede ser utilizado como una etiqueta valida.
La principal ventaja de la matriz de adyacencia es que el orden de eficiencia de las operaciones de
obtencin de etiqueta de un arco o ver si dos vrtices estn conectados son independientes del
nmero de vrtices y de arcos, por el contrario, existen dos grandes inconvenientes:

Es una representacin orientada hacia grafos que no modifica el nmero de sus vrtices ya
que una matriz no permite que se le o supriman filas o columnas.

Se puede producir un gran derroche de memoria en grafos poco densos (con gran nmero de
vrtices y escaso nmero de arcos).

Para evitar estos inconvenientes se introduce otra representacin: las listas de adyacencia.
11.6.2. LISTA DE ADYACENCIA
En esta estructura de datos la idea es asociar a cada vrtice i del grafo una lista que contenga
todos aquellos vrtices j que sean adyacentes a l. De esta forma slo reservar memoria para los
arcos adyacentes a i y no para todos los posibles arcos que pudieran tener como origen i, el grafo,
por tanto, se representa por medio de un vector de n componentes (si |V|=n) donde cada
componente va a ser una lista de adyacencia correspondiente a cada uno de los vrtices del
grafo. Cada elemento de la lista consta de un campo indicando el vrtice adyacente. En caso de
que el grafo sea etiquetado, habr que aadir un segundo campo para mostrar el valor de la
etiqueta.

108

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Veamos un ejemplo a continuacin:

Esta representacin requiere un espacio proporcional a la suma del nmero de vrtices, ms el


nmero de arcos, y se suele usar cuando el nmero de arcos es mucho menor que el nmero de
arcos de un grafo completo. Una desventaja es que puede llevar un tiempo O(n) determinar si
existe un arco del vrtice i al vrtice j, ya que puede haber n vrtices en la lista de adyacencia
asociada al vrtice i.
Mediante el uso del vector de listas de adyacencias slo se reserva memoria para los arcos
existentes en el grafo con el consiguiente ahorro de la misma, sin embargo, no permite que haya
vrtices que puedan ser aadidos o suprimidos del grafo, debido a que la dimensin del grafo
debe ser predeterminado y fija.
Para solucionar esto se puede usar una lista de listas de adyacencia, slo los vrtices del grafo
que sean origen de algn arco aparecern en la lista, de esta forma se pueden aadir y suprimir
arcos sin desperdicio de memoria ya que simplemente habr que modificar la lista de listas para
reflejar los cambios.

109

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Como puede verse en el ejemplo de las figuras anteriores tanto el vector de listas de adyacencias
como en la lista de listas se ha razonado en funcin de los vrtices que actan como orgenes de
los arcos. Anlogamente se poda haber hecho con los vrtices destino, y combinando ambas
representaciones podra pensarse en utilizar dos vectores de listas de adyacencia o dos listas de
listas de adyacencia.
Nuestra implementacin es con listas de adyacencia donde slo usamos los arcos adyacentes y no
los incidentes, es una simplificacin considerable ya que no tenemos mucho tiempo.
Usamos una estructura nodo que simula lo que sera un vrtice o nodo del grafo, contiene un
elemento de tipo Tbase que es la etiqueta, un entero nodo que identifica unvocamente al nodo,
un puntero sig al siguiente nodo de la lista y un puntero ady a la lista de adyacencia del nodo en
cuestin. Podra tener como hemos comentado antes un puntero a la lista de arcos incidentes
pero hemos simplificado el problema.
Tambin tenemos otra estructura para simular el comportamiento de un arco o arista del grafo,
esta estructura tiene un valor que es el peso que tiene el arco tratado, un puntero sig al siguiente
arco de la lista, un puntero al nodo origen del arco y otro al destino del mismo.
El grafo se compone de un nodo inicio que es el primer nodo del grafo, del cual cuelgan el resto
de los nodos y del nnodos que nos da el nmero de nodos del grafo.
Para el grafo de la siguiente figura:

La representacin segn nuestra implementacin sera:

110

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Vamos a ver la especificacin tanto de la funcin de abstraccin como del invariante de la


representacin del grafo:
FUNCIN DE ABSTRACCIN
Dado el objeto del tipo rep r, r = {inicio, nnodos}, el objeto abstracto al que representa es:
g = < r.inicio, r.inicio->sig, r.inicio->sig->sig ..., r.inicio->sig... nnodos...->sig >
INVARIANTE DE REPRESENTACIN
0 <= r.nnodos < 5
De manera que la clase Grafo en C++ tendra el siguiente aspecto:
Class Grafo
{
Public:
struct nodo
{
Tbase etiqueta;
int nodo;
struct nodo *sig;
struct arco *ady;

111

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

}
struct arco
{
int valor;
struct nodo *origen;
struct nodo *destino;
struct arco *sig;
}
struct nodo *inicio;
int nnodos;
Grafo ();
nodo LocalizaLabel (const Tbase e);
bool ExisteArco (nodo o, nodo d);
int GrafoVacio ();
float EtiqArco (nodo o, nodo d);
void InsertarNodo (const Tbase dato);
void InsertarArco (nodo o, nodo d, int valor);
void BorrarArco (nodo o, nodo d);
void DesconectarNodo (nodo a_eliminar);
void CopiarGrafo (Grafo gr);
~Grafo();
}

Debemos aclarar un par de cosas sobre la implementacin en C++; slo tenemos miembros
pblicos para facilitar el acceso a los mismos de forma rpido, aunque esta no sea la filosofa ms
apropiada tratndose de un lenguaje con orientacin a objetos, esto se ha hecho as para
simplificar en gran medida tanto las primitivas como el cdigo asociado a ellas ya que en la
confeccin de este tutorial no hemos tenido tiempo suficiente para hacer una clase Grafo como
dios manda.
Si se quiere hacer una clase grafo donde tengamos miembros privados como inicio y nnodos,
debemos elaborar primitivas que nos devuelvan cada elemento de una estructura nodo y arco en
este caso, seran muchas primitivas pequeas, luego el resto (las que hemos elegido aqu) habra
que modificarlas en base a las nuevas primitivas elaboradas.
Pasemos ahora a ver la implementacin de cada una de las primitivas enunciadas con
anterioridad en C++:
CODIGO EN C++
template <class Tbase>
Grafo<Tbase>::Grafo()
{
inicio = new nodo;

112

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

inicio->etiqueta = 0;
inicio->nodo = 1;
inicio->ady = 0;
inicio->sig = 0;
}
template <class Tbase>
nodo Grafo<Tbase>::LocalizaLabel(const Tbase e)
{
nodo n;
int enc=0;
for (n=this.inicio; n!=0 && !enc; )
{
if (n->etiqueta == e)
enc = 1;
else
n = n->sig;
}
return n;
}
template <class Tbase>
bool Grafo<Tbase>::ExisteArco(nodo o, nodo
{
arco a;

d)

a=o->ady;
while (a!=0)
{
if ((a->origen==o) && (a->destino==d))
return true;
else
a = a->sig;
}
return false;
}
template <class Tbase>
int Grafo<Tbase>::GrafoVacio()
{
return(this.inicio == 0);
}
template <class Tbase>
float Grafo<Tbase>::EtiqArco(nodo o, nodo d)
{
arco a;
a=o->ady;
while (a!=0)
{
if ((a->origen == o) && (a->destino == d))
return (a->valor);
else
a = a->sig;

113

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

}
return 0;
}
template <class Tbase>
void Grafo<Tbase>::InsertarNodo(const Tbase dato)
{
nodo aux,p;
aux = new nodo;
p=this.inicio;
while(p->sig != 0)
p = p->sig;
aux->etiqueta = dato;
aux->nodo = (p->nodo)+1;
aux->ady = 0;
aux->sig = 0;
p->sig = aux;
(this.nnodos)++;
}
template <class Tbase>
void Grafo<Tbase>::InsertarArco (nodo , nodo d, int valor)
{
arco aux;
aux = new arco;
aux->origen = o;
aux->destino = d;
aux->valor = valor;
aux->sig= o->ady;
o->ady = aux;
}
template <class Tbase>
void Grafo<Tbase>::BorrarArco(nodo o, nodo d)
{
arco a,ant;
int enc=0;
if (o->ady==0)
return;
else
if (o->ady->destino==d)
{
a = o->ady;
o->ady = a->sig;
delete a;
}
else {
ant = o->ady;
a = ant->sig;
while (!enc && (a!=0))
{
if (a->destino==d)

114

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

enc=1;
else {
a = a->sig;
ant = ant->sig;
}
}
if (a==0)
return;
else {
ant->sig = a->sig;
delete a;
}
}
}
template <class Tbase>
Void Grafo<Tbase>::DesconectarNodo(nodo a_eliminar)
{
Grafo g_nd;
nodo n,org,dst,o,d;
arco a;
g_nd = new Grafo;
for (n=this.inicio; n!=0; n=n->sig)
g_nd.InsertarNodo(n->etiqueta);
for (n=this.inicio; n!=0; n=n->sig)
for (a=n->ady; a!=0; a=a->sig)
{
org = a->origen;
dst = a->destino;
o = g_nd.LocalizaLabel(org->etiqueta);
d = g_nd.LocalizaLabel(dst->etiqueta);
if ((org!=a_eliminar) && dst!=a_eliminar))
g_nd.InsertarArco(o,d,a->valor);
}
this.CopiarGrafo(g_nd);
}
template <class Tbase>
Void Grafo<Tbase>::CopiarGrafo(Grafo gr)
{
nodo n,org,dest,o,d;
arco a;
this.Destruir();
this = new Grafo;
for (n=gr.inicio; n!=0; n=n->sig)
this.InsertarNodo(n->etiqueta);
for (n=gr.inicio; n!=0; n=n->sig)
for (a=n->ady; a!=0; a=a->sig)
{
org = a->origen;
dest = a->destino;
o = g_nd.LocalizaLabel(org->etiqueta);
d = g_nd.LocalizaLabel(dest->etiqueta);

115

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

this.InsertarArco(o,d,a->valor);
}
}
template <class Tbase>
Grafo<Tbase>::~Grafo()
{
nodo n;
arco aux;
while ((this.inicio)->sig != 0)
{
n = (this.inicio)->sig;
while (n->ady != 0)
{
aux = n->ady;
n->ady = aux->sig;
delete aux;
}
(this.inicio)->sig = n->sig;
delete n;
}
delete (this.inicio);
}

12. MANEJO DE ARCHIVOS


As como hemos revisado la salida y entrada por pantalla y teclado respectivamente, veremos
ahora la entrada y/o salida de datos utilizando ficheros, lo cual ser imprescindible para un gran
nmero de aplicaciones que deseemos desarrollar.
12.1. FICHEROS
El estndar de C++ contiene varias funciones para la edicin de ficheros, estas estn definidas en
la cabecera #include <cstdio> y por lo general empiezan con la letra f, haciendo referencia a file.
Adicionalmente se agrega un tipo FILE, el cual se usar como apuntador a la informacin del
fichero. La secuencia que usaremos para realizar operaciones ser la siguiente:
Crear un apuntador del tipo FILE *
Abrir el archivo utilizando la funcin fopen y asignndole el resultado de la llamada a nuestro
apuntador.
Hacer las diversas operaciones (lectura, escritura, etc).
Cerrar el archivo utilizando la funcin fclose.
12.1.1. FOPEN
Esta funcin sirve para abrir y crear ficheros en disco.
El prototipo correspondiente de fopen es:
FILE * fopen (const char *filename, const char *opentype);

Los parmetros de entrada de fopen son:

116

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

filename: una cadena que contiene un nombre de fichero vlido.


opentype: especifica el tipo de fichero que se abrir o se crear.
Una lista de parmetros opentype para la funcin fopen son:
"r: Abrir un archivo para lectura, el fichero debe existir.
"w: abrir un archivo para escritura, se crea si no existe o se sobre escribe si existe.
"a: abrir un archivo para escritura al final del contenido, si no existe se crea.
"r+: abrir un archivo para lectura y escritura, el fichero debe existir.
"w+: crear un archivo para lectura y escritura, se crea si no existe o se sobre escribe si existe.
"r+b rb+: Abre un archivo en modo binario para actualizacin (lectura y escritura).
"rb: Abre un archivo en modo binario para lectura.
Adicionalmente hay tipos utilizando "b" (binary) los cuales no sern mostrados por ahora y
que solo se usan en los sistemas operativos que no pertenecen a la familia de Unix.
12.1.2 FCLOSE
Esta funcin sirve para poder cerrar un fichero que se ha abierto.
El prototipo correspondiente de fclose es:
int fclose (FILE *stream);

Un valor de retorno cero indica que el fichero ha sido correctamente cerrado, si ha habido
algn error, el valor de retorno es la constante EOF.
Un ejemplo pequeo para abrir y cerrar el archivo llamado fichero.in en modo lectura:
#include <iostream>
#include <cstdio>
using namespace std;
int main(int argc, char** argv)
{
FILE *fp;
fp = fopen ( "fichero.in", "r" );
fclose ( fp );
return 0;
}

Como vemos, en el ejemplo se utiliz el opentype "r", que es para la lectura.


Otra cosa importante es que el lenguaje C++ no tiene dentro de s una estructura para el
manejo de excepciones o de errores, por eso es necesario comprobar que el archivo fue
abierto con xito "if (fp == NULL)". Si fopen pudo abrir el archivo con xito devuelve la
referencia al archivo (FILE *), de lo contrario devuelve NULL y en este caso se deber revisar
la direccin del archivo o los permisos del mismo. En estos ejemplos solo vamos a dar una
salida con un retorno de 1 que sirve para sealar que el programa termino por un error.

117

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

12.1.3 FEOF
Esta funcin sirve para determinar si el cursor dentro del archivo encontr el final (end of
file). Existe otra forma de verificar el final del archivo que es comparar el carcter que trae
fgetc del archivo con el macro EOF declarado dentro de <cstdio>, pero este mtodo no ofrece
la misma seguridad (en especial al tratar con los archivos "binarios"). La funcin feof siempre
devolver cero (Falso) si no es encontrado EOF en el archivo, de lo contrario regresar un
valor distinto de cero (Verdadero).
El prototipo correspondiente de feof es:
int feof(FILE *fichero);

12.1.4 REWIND
Literalmente significa "rebobinar", sita el cursor de lectura/escritura al principio del archivo.
El prototipo correspondiente de rewind es:
void rewind(FILE *fichero);

12.2 LECTURA
Un archivo generalmente debe verse como un string (una cadena de caracteres) que est
guardado en el disco duro. Para trabajar con los archivos existen diferentes formas y diferentes
funciones. Las funciones que podramos usar para leer un archivo son:
char fgetc(FILE *archivo)
char *fgets(char *buffer, int tamano, FILE *archivo)
size_t fread(void *puntero, size_t tamano, size_t cantidad, FILE *archivo);
int fscanf(FILE *fichero, const char *formato, argumento, ...);

Las primeras dos de estas funciones son muy parecidas entre s. Pero la tercera, por el nmero y
el tipo de parmetros, nos podemos dar cuenta de que es muy diferente, por eso la trataremos
aparte junto al fwrite que es su contraparte para escritura.
12.2.1 FGETC
Esta funcin lee un carcter a la vez del archivo que est siendo sealado con el puntero
*archivo. En caso de que la lectura sea exitosa devuelve el carcter ledo y en caso de que no
lo sea o de encontrar el final del archivo devuelve EOF.
El prototipo correspondiente de fgetc es:
char fgetc(FILE *archivo);

Esta funcin se usa generalmente para recorrer archivos de texto. A manera de ejemplo
vamos a suponer que tenemos un archivo de texto llamado "prueba.txt" en el mismo
directorio en que se encuentra la fuente de nuestro programa. Un pequeo programa que lea
ese archivo ser:

118

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
int main()
{
FILE *archivo;
char caracter;
archivo = fopen("prueba.txt","r");
if (archivo == NULL){
printf("\nError de apertura del archivo. \n\n");
}else
{

printf("\nEl contenido del archivo de prueba es \n\n");


while (feof(archivo) == 0)
{
caracter = fgetc(archivo);
printf("%c",caracter);
}
}
fclose(archivo);
return 0;
}

12.2.2 FGETS
Esta funcin est diseada para leer cadenas de caracteres. Leer hasta n-1 caracteres o
hasta que lea un cambio de lnea '\n' o un final de archivo EOF. En este ltimo caso, el
carcter de cambio de lnea '\n' tambin es ledo.
El prototipo correspondiente de fgets es:
char *fgets(char *buffer, int tamao, FILE *archivo);

El primer parmetro buffer lo hemos llamado as porque es un puntero a un espacio de


memoria del tipo char (podramos usar un arreglo de char). El segundo parmetro es tamao
que es el lmite en cantidad de caracteres a leer para la funcin fgets. Y por ltimo el puntero
del archivo por supuesto que es la forma en que fgets sabr a que archivo debe leer.
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;

119

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

int main()
{
FILE *archivo;
char caracteres[100];
archivo = fopen("prueba.txt","r");
if (archivo == NULL)
exit(1);
printf("\nEl contenido del archivo de prueba es \n\n");
while (feof(archivo) == 0)
{
fgets(caracteres,100,archivo);
printf("%s",caracteres);
}
system("PAUSE");
fclose(archivo);
return 0;
}

Este es el mismo ejemplo de antes con la diferencia de que este hace uso de fgets en lugar de
fgetc. La funcin fgets se comporta de la siguiente manera, leer del archivo apuntado por
archivo los caracteres que encuentre y a ponerlos en buffer hasta que lea un carcter menos
que la cantidad de caracteres especificada en tamao o hasta que encuentre el final de una
lnea (\n) o hasta que encuentre el final del archivo (EOF). En este ejemplo no vamos a
profundizar ms que para decir que caracteres es un buffer, los por menores sern explicados
en la seccin de manejo dinmico de memoria.
El beneficio de esta funcin es que se puede obtener una lnea completa a la vez.
12.2.3 FREAD
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

Esta funcin lee un bloque de una "stream" de datos. Efecta la lectura de un arreglo de
elementos "count", cada uno de los cuales tiene un tamao definido por "size". Luego los
guarda en el bloque de memoria especificado por "ptr". El indicador de posicin de la cadena
de caracteres avanza hasta leer la totalidad de bytes. Si esto es exitoso la cantidad de bytes
ledos es (size*count).
PARAMETROS:
ptr : Puntero a un bloque de memoria con un tamao mnimo de (size*count) bytes.
size : Tamao en bytes de cada elemento (de los que voy a leer).
count : Nmero de elementos, los cuales tienen un tamao "size".
stream: Puntero a objetos FILE, que especifica la cadena de entrada.

120

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

12.2.4 FSCANF
La funcin fscanf funciona igual que scanf en cuanto a parmetros, pero la entrada se toma
de un fichero en lugar del teclado.
El prototipo correspondiente de fscanf es:
int fscanf(FILE *fichero, const char *formato, argumento, ...);

Podemos ver un ejemplo de su uso, abrimos el documento "fichero.txt" en modo lectura y


leyendo dentro de l.
#include <iostream>
#include <cstdio>
using namespace std;
int main ( int argc, char **argv )
{
FILE *fp;
char buffer[100];
fp = fopen ( "fichero.txt", "r" );
fscanf(fp, "%s" ,&buffer);
printf("%s",buffer);
fclose ( fp );
return 0;
}

12.3 ESCRITURA
As como podemos leer datos desde un fichero, tambin se pueden crear y escribir ficheros con la
informacin que deseamos almacenar, Para trabajar con los archivos existen diferentes formas y
diferentes funciones. Las funciones que podramos usar para escribir dentro de un archivo son:
int fputc(int caracter, FILE *archivo)
int fputs(const char *buffer, FILE *archivo)
size_t fwrite(void *puntero, size_t tamano, size_t cantidad, FILE *archivo);
int fprintf(FILE *archivo, const char *formato, argumento, ...);

12.3.1 FPUTC
Esta funcin escribe un carcter a la vez del archivo que est siendo sealado con el puntero
*archivo. El valor de retorno es el carcter escrito, si la operacin fue completada con xito,
en caso contrario ser EOF.
El prototipo correspondiente de fputc es:

121

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

int fputc(int carcter, FILE *archivo);

Mostramos un ejemplo del uso de fputc en un "fichero.txt", se escribir dentro del fichero
hasta que presionemos la Tecla Enter.
#include <iostream>
#include <cstdio>
using namespace std;
int main ( int argc, char **argv )
{
FILE *fp;
char caracter;
fp = fopen ( "fichero.txt", "r+" );
printf("\nIntrouce un texto al fichero: ");
while((caracter = getchar()) != '\n')
{
printf("%c", fputc(caracter, fp));
}
fclose ( fp );
return 0;
}

12.3.2 FPUTS
La funcin fputs escribe una cadena en un fichero. No se aade el carcter de retorno de lnea
ni el carcter nulo final. El valor de retorno es un nmero no negativo o EOF en caso de error.
Los parmetros de entrada son la cadena a escribir y un puntero a la estructura FILE del
fichero donde se realizar la escritura.
El prototipo correspondiente de fputs es:
int fputs(const char *buffer, FILE *archivo)

Para ver su funcionamiento mostramos el siguiente ejemplo:


#include <iostream>
#include <cstdio>
using namespace std;
int main ( int argc, char **argv )
{
FILE *fp;
char cadena[] = "Mostrando el uso de fputs en un fichero.\n";

122

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

fp = fopen ( "fichero.txt", "r+" );


fputs( cadena, fp );
fclose ( fp );
return 0;
}

12.3.3 FWRITE
Esta funcin est pensada para trabajar con registros de longitud constante y forma pareja
con fread. Es capaz de escribir hacia un fichero uno o varios registros de la misma longitud
almacenados a partir de una direccin de memoria determinada. El valor de retorno es el
nmero de registros escritos, no el nmero de bytes. Los parmetros son: un puntero a la
zona de memoria de donde se obtendrn los datos a escribir, el tamao de cada registro, el
nmero de registros a escribir y un puntero a la estructura FILE del fichero al que se har la
escritura.
El prototipo correspondiente de fwrite es:
size_t fwrite(void *puntero, size_t tamano, size_t cantidad, FILE *archivo);

Un ejemplo concreto del uso de fwrite con su contraparte fread y usando funciones es:
/*
*
*
*
*
*
*
*/

FicheroCompleto.cpp
Copyright 2012 Alain Wilfredo Fuentes Garcia
Cel: 60413636
E-mail: lamente.maestra2014@hotmail.es>

#include <iostream>
#include <cstdio>
using namespace std;
void
void
void
void

menu();
CrearFichero(FILE *Fichero);
InsertarDatos(FILE *Fichero);
VerDatos(FILE *Fichero);

struct sRegistro {
char Nombre[25];
int Edad;
float Sueldo;
} registro;
int main()
{
int opcion;
int exit = 0;
FILE *fichero;
while (!exit)
{

123

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

menu();
printf("\nOpcion: ");
scanf("%d", &opcion);
switch(opcion)
{
case 1:
CrearFichero(fichero);
break;
case 2:
InsertarDatos(fichero);
break;
case 3:
VerDatos(fichero);
break;
case 4:
exit = 1;
break;
default:
printf("\n opcion no valida");
}
}
return 0;
}
void menu()
{
printf("\nMenu:");
printf("\n\t1. Crear fichero");
printf("\n\t2. Insertar datos");
printf("\n\t3. Ver datos");
printf("\n\t4. Salir");
}
void CrearFichero(FILE *Fichero)
{
Fichero = fopen("fichero", "r");
if(!Fichero)
{
Fichero = fopen("fichero", "w");
printf("\nArchivo creado!");
}
else
{
printf("\nEl fichero ya existe!");
}
fclose (Fichero);
return;
}
void InsertarDatos(FILE *Fichero)
{
Fichero = fopen("fichero", "a+");
if(Fichero == NULL)
{
printf("\nFichero no existe! \nPor favor creelo");
return;

124

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

}
printf("\nDigita el nombre: ");
scanf("%s", &registro.Nombre);
printf("\nDigita la edad: ");
scanf("%d", &registro.Edad);
printf("\nDigita el sueldo: ");
scanf("%f", &registro.Sueldo);
fwrite(&registro, sizeof(struct sRegistro), 1, Fichero);
fclose(Fichero);
return;
}
void VerDatos(FILE *Fichero)
{
int numero = 1;
Fichero = fopen("fichero", "r");
if(Fichero == NULL)
{
printf("\nFichero no existe! \nPor favor creelo");
return;
}
fread(&registro, sizeof(struct sRegistro), 1, Fichero);
printf("\nNumero \tNombre \tEdad \tSueldo");
while(!feof(Fichero))
{
printf("\n%d \t%s \t%d \t%.2f", numero, registro.Nombre,
registro.Edad, registro.Sueldo);
fread(&registro, sizeof(struct sRegistro), 1, Fichero);
numero++;
}
fclose(Fichero);
return;
}

12.3.4 FPRINTF
La funcin fprintf funciona igual que printf en cuanto a parmetros, pero la salida se dirige a
un archivo en lugar de a la pantalla.
El prototipo correspondiente de fprintf es:
int fprintf(FILE *archivo, const char *formato, argumento, ...);
Podemos ver un ejemplo de su uso, abrimos el documento "fichero.txt" en modo
lectura/escritura y escribimos dentro de l.
#include <iostream>
#include <cstdio>
using namespace std;

125

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

int main ( int argc, char **argv )


{
FILE *fp;
char buffer[100] = "Esto es un texto dentro del fichero.";
fp = fopen ( "fichero.txt", "r+" );
fprintf(fp, buffer);
fprintf(fp, "%s", "\nEsto es otro texto dentro del fichero.");
fclose ( fp );
return 0;
}

126

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

SOLUCIONARIO PROBLEMAS PROPUESTOS


1. Disear un programa para calcular la suma de dos nmeros A y B
#include <iostream>
using namespace std;
int main()
{
int a,b;
cout<<"Inserte primer valor: ";
cin>>a;
cout<<"Inserte segundo valor: ";
cin>>b;
cout<<endl<<"La Suma es: "<<a+b;
return 0 ;
}

2. Calcular el rea de un tringulo de base B y altura H


#include <iostream>
using namespace std;
int main()
{
int b,h;
cout<<"Inserte Base: ";
cin>>b;
cout<<"Inserte Altura: ";
cin>>h;
cout<<"El area del triangulo es: "<<(b*h)/2<<endl;
return 0;
}

127

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

3. Calcular el rea de un crculo de radio R


#include <iostream>
using namespace std;
int main()
{
int r;
cout<<"Inserte Radio: ";
cin>>r;
cout<<"El
area
de
"<<3.1416*(r*r)<<endl;
return 0;
}

la

circunferencia

4. Ingresar una nota por teclado y determinar si es de aprobacin o reprobacin

#include <iostream>
using namespace std;
int main()
{
int nota;
cout<<"LA NOTA MINIMA DE APROBACION ES DE 51"<<endl<<endl;
cout<<"Introduzca Nota: ";
cin>>nota;
cout<<endl;
if (nota>=51)
cout<<"Es una nota de aprobacion";
else
cout<<"Es una nota de reprobacion";
return 0;
}

5. Ingresar un nmero por teclado y determinar si es PAR o IMPAR

#include <iostream>
using namespace std;
int main()
{
int num;
cout<<"Itroduzca un numero: ";

128

es:

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

cin>>num;
cout<<endl;
if (num % 2==0)
cout<<"El numero introducido es par";
else
cout<<"El numero introducido es impar";
return 0;
}

6. Determinar si una persona es "Nio 1 a 10 aos", "Adolescente 11 a 17 aos",


"Joven 18 a 29 aos", "Adulto 30 a 60 aos", "Tercera Edad 60 a 100 aos", de
acuerdo a su edad que es introducida por teclado.

#include <iostream>
using namespace std;
int main()
{
int edad;
cout<<"Introduzca su edad para realizar el analisis: ";
cin>>edad;
cout<<endl;
if (edad <= 10)
cout<<"Es un Nio";
else if (edad <= 17)
cout<<"Es un Adolescente";
else if (edad <= 29)
cout<<"Es un joven";
else if (edad <= 60)
cout<<"Es una persona Adulta";
else if (edad <= 100)
cout<<"Es una persona de la Tercera Edad";
else
cout<<"MUCHAS FELICIDADES!!!";
return 0;
}

129

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

7. Generar Aleatoriamente dos nmeros enteros entre 0 y 100. Determinar cul es el


mayor de ellos.

#include <iostream>
#include <cstdlib>
#include <time.h>

using namespace std;


int main()
{
int a,b;
srand(time(NULL));
a=rand()%101;
b=rand()%101;
cout<<a<<" "<<b<<" "<<endl;
if (a<b)
cout<<a<<" Es menor";
else if (a>b)
cout<<a<<" Es mayor";
else if (b<a)
cout<<b<<" Es menor";
else
cout<<b<<" Es mayor";
return 0;
}
8. Introducir tres nmeros por teclado. Determinar cul es el mayor de los tres

#include <iostream>
using namespace std;
int main()
{
int a,b,c;
cout<<"Primer valor: ";
cin>>a;
cout<<"Segundo valor: ";
cin>>b;
cout<<"Tercer valor: ";
cin>>c;
cout<<endl;
if (a>b)

130

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

{
if (a>c)
cout<<"El mayor es: "<<a;
else
cout<<"El mayor es: "<<c;
}
else
{
if (b>c)
cout<<"El mayor es: "<<b;
else
cout<<"El mayor es: "<<c;
}
return 0;
}
9. Visualizar cuatro operaciones aritmticas de dos nmeros cualesquiera introducidos
por teclado.

#include <iostream>
using namespace std;
int main()
{
int a,b;
cout<<"Inserte primer valor: ";
cin>>a;
cout<<"Inserte segundo valor: ";
cin>>b;
cout<<endl<<endl;
cout<<"La Suma es: "<<a+b<<endl;
cout<<"La Resta es: "<<a-b<<endl;
cout<<"El producto es: "<<a*b<<endl;
cout<<"La division es: "<<a/b<<endl;
return 0;
}

10. Ingresar un nmero cualquiera, determina si es POSITIVO, NEGATIVO CERO

#include <iostream>
using namespace std;
int main()
{
int num;

131

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

cout<<"Introduzca numero: ";


cin>>num;
if (num==0)
cout<<"Es cero";
else if (num<0)
cout<<"Es un numero negativo";
else
cout<<"Es positivo";
return 0;
}

11. Generar un numero aleatoriamente entre 1 a 1000 y determinar si es PAR o IMPAR

#include <iostream>
#include <cstdlib>
#include <time.h>

using namespace std;


int main()
{
int a;
srand(time(NULL));
a=1+rand()%(1001-1);
cout<<a<<endl<<endl;
if (a%2==0)
cout<<"Es par";
else
cout<<"Es impar";
return 0;
}
12. Introducir un nmero positivo por teclado. Si es negativo o cero rechazarlo, caso
contrario, determinar si el nmero positivo es par o impar

#include <iostream>
using namespace std;
int main()
{
int n;
cout<<"Inserte numero: ";
while (cin>>n && n!=0 && n>0)
{

132

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

if (n%2==0)
cout<<"Es par"<<endl;
else
cout<<"Es impar"<<endl;
}
return 0;
}
13. Ingresar un nmero por teclado y determinar si es mltiplo de 10

#include <iostream>
using namespace std;
int main()
{
int n;
cout<<"Inserte numero: ";
cin>>n;
cout<<endl;
if (n%10==0)
cout<<"Es multiplo de 10"<<endl;
else
cout<<"No es multiplo de 10"<<endl;
return 0;
}
14. Ingresar una nota por teclado y determinar su grado de aprovechamiento (0-10)
Psimo, (11-20) Muy Malo, (21-30) Malo, (31-40) regular, (41-50) Bueno, (51-60) Muy
Bueno, (61-70) Excelente

#include <iostream>
using namespace std;
int main()
{
int nota;
cout<<"Introduzca su nota para realizar el analisis: ";
cin>>nota;
cout<<endl;
if (nota <= 10)
cout<<"Es una nota Pesima";
else if (nota <= 20)
cout<<"Es una nota Muy mala";
else if (nota <= 30)
cout<<"Es una nota Mala";
else if (nota <= 40)

133

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

cout<<"Es una nota Regular";


else if (nota <= 50)
cout<<"Es una nota Buena";
else if (nota <= 60)
cout<<"Es una nota Muy buena";
else if (nota <= 70)
cout<<"Es una nota Excelente";
else
cout<<"No me mientas!!!";
return 0;
}
15. Simular un juego con un dado. Si se saca un 1 o un 6 e gana, caso contrario se pierde.

#include <iostream>
#include <cstdlib>
#include <time.h>
using namespace std;
int main()
{
int d;
srand(time(NULL));
d=1+rand()%(7-1);
cout<<d<<endl;
if(d==1 || d==6)
cout<<"Usted Gano!!!";
else
cout<<"Usted Perdio!!!!";
return 0;
}
16. Simular un juego con dos dados. Si se saca un siete o un once se gana, caso contrario se
pierde.

#include <iostream>
#include <cstdlib>
#include <time.h>
using namespace std;
int main()
{
int d1,d2;
srand(time(NULL));
d1=1+rand()%(7-1);
d2=1+rand()%(7-1);

134

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

cout<<"Dado 1: "<<d1<<endl<<"Dado 2: "<<d2<<endl;


if((d1+d2==7)||(d1+d2==11))
cout<<"Usted Gano!!!";
else
cout<<"Usted Perdio!!!!";
return 0;
}
17. Visualizar la serie 1,3,5,7,.n

#include <iostream>
using namespace std;
int main()
{
int r;
cout<<"Inserte el tamao de la Serie: ";
cin>>r;
for (int i=1;i<=r;i++)
{
cout<<(i*2)-1<<" ";
}
return 0;
}
18. Visualizar la serie 1,4,7,10,13,16..n

#include <iostream>
using namespace std;
int main()
{
int r;
cout<<"Inserte el tamao de la Serie: ";
cin>>r;
for (int i=1;i<=r;i++)
{
cout<<(i*3)-2<<" ";
}
return 0;
}

135

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

19. Ingresar un nmero y visualizar su tabla de multiplicar

#include <iostream>
using namespace std;
int main()
{
int num;
cout<<"Inserte el numero que desa generar la
tabla"<<endl;
cin>>num;
for (int i=1;i<=10;i++)
{
cout<<num<<" * "<<i<<" = "<<num*i<<endl;
}
return 0;
}

136

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

13. INSTALACION DEL EDITOR CODE::BLOCKS 10.05


A continuacin mostraremos la correcta forma de instalar el Editor de Comandos Code::Blocks
10.05, y el inicio de dicho editor.
PASOS PARA INSTALAR EL EDITOR DE COMANDOS CODE::BLOCKS 10.05
Necesitas el instalador de Code::Blocks 10.05, que esta en el CD.

Dar Doble Clic en el Programa, aparecer la siguiente ventana, que es el asistente de instalacin
de Code::Blocks 10.05.

Damos Click en Next > nos aparecer una nueva ventana.

137

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Nos aparece una ventana con el contrato de uso del software, preguntndonos si deseamos
aceptar. Le damos Click en I Agree, que significa Acepto.

Damos click en Next > para continuar.

Luego nos pide la ruta donde se instalar Code::Blocks 10.05, le damos Install dejando por
defecto la direccin de instalacin.

138

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Nos saldr un mensaje que nos indica que el directorio de instalacin no existe, y si deseamos
crearlo. Le damos Click y le decimos que Si.

Y empezar a instalar el editor de comando Code::Blocks 10.05. Esto tardar aproximadamente


de 2 a 3 minutos.

139

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Nos aparecer la siguiente ventana preguntndonos si deseamos ejecutar el Programa. Le


decimos que Si.

Dos ventanas ms le damos en Next > luego en Finish. Y listo!!! Tenemos instalado Code::Blocks
10.05 en nuestro sistema.

140

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

INICIAR EL CODE::BLOCKS 10.05 PARA EMPEZAR A TRABAJAR


En nuestro escritorio nos saldr un icono, un acceso directo, le damos doble click.

Nos aparecer el entorno de trabajo de Code::Blocks 10.05

Le damos Click en Create a new Project nos saldr un asistente de configuracin.

141

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Seleccionamos el que dice Console Application y le damos click en Go.

En el siguiente cuadro que nos aparezca le damos clic en Next >, nos enviar a un men donde
debemos seleccin que lenguaje deseamos programar. En nuestro caso seleccionamos el que dice
C++ y le damos click en Next >.

En la siguiente ventana debemos darle el nombre del proyecto, y seleccionar en que directorio
deseamos guardar nuestro proyecto.

142

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

Y en la ventana Final no tocamos nada, y le damos en Finish. De seguro les saldr una venta en
blanco. No hay problema. En la parte Izquierda tenemos un panel de seleccin.
Le damos doble click en el que dice: Sources nos aparecer un archivo que dice main.cpp, pues es
ah donde debemos entrar con un doble click. Y ya estomos listos para empezar!!.

143

Tec. Sup. Alain Wilfredo Fuentes Garcia


ESTRUCTURA DE DATOS

HARDWARE - SOFTWARE

BIBLIOGRAFIA

Luis Joyanes Aguilar

Fundamentos de Programacin 3ra Edicin

Freddy Zambrana Rodriguez

Problemas Codificados en Pascal y C++

Rufino Goi Lasheras

Aprenda Lenguaje ANCI C

Deitel & Deitel

Como Programas en C++

Jorge Humberto Tern

Fundamentos de la Programacin

Schaums Outline

Programming with C++

Addison Wesley

Accelerated C++

Sitio Web en Internet

http://c.conclase.net

144

Você também pode gostar