Está en la página 1de 85

MANUAL ESTRUCTURA DE DATOS

1. Representacin de datos e introduccin a el lenguaje C


Tipos de datos
Estructura de un programa
Operadores aritmticos
Operadores relacionales y lgicos
Estructuras de control
2. Ordenamientos y bsquedas
Arreglos
Ordenamiento
Burbuja y Burbuja Mejorado (Bubble Sort)
Ordenamiento por Insercin Directa (InsertSort)
Ordenamiento por seleccin (SelectSort)
Ordenamiento Shell (ShellSort)
Ordenamiento Mezcla (MergeSort)
Bsquedas
Bsqueda Secuencial
Bsqueda Binaria
3. Estructuras de datos lineales, representaciones secuenciales.
Conceptos fundamentales: Tipo de Dato, Tipo de Dato Abstracto, Estructura de datos,
Registros.
T.D.A. Lista
Modelo Matemtico
Operaciones
Implementacin con Arreglos
T.D.A Pila
Modelo Matemtico
Operaciones
Implementacin con arreglos
Notacin Polaca
Recursividad
Ordenamiento Rpido (Quick Sort)
Torres de Hanoi
T.D.A Cola
Modelo Matemtico
Operaciones
Implementacin con arreglos
Concepto de Apuntador
Listas implementadas con cursores

4. Estructuras de Datos lineales, representaciones ligadas.


Teora de lista ligada
Listas con encabezado
Lista simplemente ligada
Lista simplemente ligada circular
Lista doblemente ligada
Lista doblemente ligada circular
Listas sin encabezado
Lista simplemente ligada

Pag 1

Pilas
Colas
5. Estructuras de datos no lineales, representaciones secuencial y ligada.
Teora general de rboles
rboles binarios
T.D.A. rbol Binario
Representaciones secuenciales
Representacin ligada
Recorridos En-Orden, Pre-Orden y Post-Orden
6. Grafos.

Representacin de datos e Introduccin a lenguaje C


Tipos de datos.
Los diferentes objetos de informacin con los que un programa C trabaja se conocen
colectivamente como datos. Todos los datos tienen un tipo asociado con ellos
La asignacin de tipos a los datos tiene dos objetivos principales:
1. Detectar errores de operaciones en programas.
2. Determinar como ejecutar las operaciones.
El tipo de un dato determina la naturaleza del conjunto de valores que puede tomar una variable.
Tipos predefinidos
Tipo
unsigned char
Char
enum
unsigned int
short int
int
unsigned long
long
float
double
long double

Largo
8 bits
8 bits
16 bits
16 bits
16 bits
16 bits
32 bits
32 bits
32 bits
64 bits
80 bits

Rango
0 to 255
-128 to 127
-32,768 to 32,767
0 to 65,535
-32,768 to 32,767
-32,768 to 32,767
0 to 4,294,967,295
-2,147,483,648 to 2,147,483,647
3.4 * (10**-38) to 3.4 * (10**+38)
1.7 * (10**-308) to 1.7 * (10**+308)
3.4 * (10**-4932) to 1.1 * (10**+4932)

Tipos de datos definidos por el usuario


Constantes
Las constantes se presentan en expresiones como
c= Y
2* (x + 7) 33
kilmetros = 1.609344 * millas
Adems de tener un valor, una constante tambin tiene un tipo de dato inherente. Los tipos de
datos posibles en las constantes dependen de la mquina. Lo normal es que no existan constantes
de los tipos short, unsigned y float. Aunque esto puede ser distinto en mquinas pequeas, se
supondr que la situacin normal prevalece.

Pag 2

El tipo de dato asociado a una constante depende de la forma en que sta se escribe. La siguiente
lista contiene todos los tipos de datos que admiten constantes, asi como algunos ejemplos:
int
long
double
char
cadena

0
0L

77
5013
77L
5013L
0.003 1.0|| 0.5013e-2
a
b
c
est es una constante de cadena

Una expresin constante slo contiene constantes, y el compilador C las evaluar en el momento
de la compilacin, en lugar de hacerlo en la ejecucin. Por ejemplo, en la proposicin:
Segundos = 60 * 60 * 24 * das;
Segundos = 86400 * das;
Uso de #define y de #include
El compilador C tiene un preprocesador incorporado. Si las lineas
#define
#define

LIMITE
PI

100
3.14159

se encuentran en un archivo que se est compilando el preprocesador cambia primero todos los
identificadores LIMITE por 100 y todos los PI por 3.14159, excepto los que estn en cadenas entre
comillas. Una lnea #define puede estar en cualquier lugar del programa, pero debe empezar en la
columna 1 y solo tendr efecto en las lneas de archivo que le sigue. El preprocesador solo
cambiar los identificadores que se escriben con maysculas.
Si en un programa hay una lnea como:
#include mi_archivo
Se trata tambin de una orden al procesador. Una linea #include puede presentarse en cualquier
parte de un archivo, pero debe empezar en la columna uno. Las comillas que encierran el nombre
de archivo son necesarias. El efecto de esta lnea es incluir en ese punto de la codificacin una
copia del contenido del archivo mi_archivo
Usos de printf() Y scanf()
La funcin printf() se usa para la salida; en forma similar; la funcin scanf() se usa para la
entrada. Estas funciones no son parte del lenguaje C, sino del sistema C; residen en una
biblioteca estndar y estn disponibles para usarlas donde quiera que haya un sistema C. Las f de
printf() y de scanf() significan con formato. Ambas funciones tienen una lista de parmetros con
dos partes:
Cadena_de_control

lista_de_argumentos

La primera es una cadena y puede contener especificaciones de conversin de formatos. Una


especificacin de conversin se inicia con un carcter % y termina con un carcter de conversin;
por ejemplo, en el formato %d la letra de es el carcter de conversin. Este formato se emplea
para imprimir el valor de una expresin como un entero decimal. Para imprimir las letras ABC en
la pantalla, podra usarse la proposicin:
printf(ABC);
otra manera de hacer esto es mediante la proposicin:
printf(%s,ABC);

Pag 3

El formato %s hace que el argumento ABC se imprima en el formato de una cadena de


caracteres. Esto mismo puede realizarse tambin con la proposicin:
printf(%c%c%c,A,B,C);
Los apstrofos que encierran cada letra se emplean para designar constantes de caracteres de
acuerdo con esto, A es la constante de carcter que corresponde a la letra A mayscula. El
formato %c imprime el valor de una expresin como un carcter.
printf()
Carcter
de
conversi
n
C
D
E
F
G
S

Cmo se describe el argumento correspondiente


Como carcter
Como un entero decimal
Como nmero de punto flotante en notacin
cientfica
Como un nmero de punto flotante
En el formato-e o el formato-f el que sea ms corto
Como una cadena de caracteres

La funcin scanf() es anloga a la funcin printf(), pero se usa para la entrada. Su primer
argumento es una cadena de control con formatos que corresponden a las diferentes formas en
que pueden interpretarse los caracteres de la entrada como valores para los diferentes tipos de
variables. La lista de argumentos est formada por direcciones de variables. El smbolo &
representa el operador de direccin; por ejemplo, la proposicin
scanf(%d,&x);
Contiene el formato %d, el cual provoca que scanf() interprete los caracteres de entrada como
un entero decimal y que coloque el valor en la direccin x.
Carcter
de
conversi
n
c
d
f
lf
s

Los caracteres de la entrada se convierten en


Un carcter
Un entero decimal
Un nmero de punto flotante (float)
Un nmero de punto flotante (double)
Una cadena

Funciones
La definicin de una funcin consiste en un encabezamiento y un cuerpo. De manera explicita,
podramos decir que es un bloque o una proposicin compuesta. Si hay declaraciones deben
aparecer al inicio del bloque antes de cualquier proposicin ejecutable. El encabezamiento puede
ser tan slo un identificador y unos parntesis. Un ejemplo sencillo es :
/****Una funcin con un encabezamiento y un cuerpo sencillos
escr_direcc()

***/

/* encabezamiento*/
/* el cuerpo es cuanto est entre llaves */

Pag 4

printf(\n\n%s\n%s\n%s\n%s\n%s\n\n,

********************,

** SAN NICOLAS *,

** El POLO NORTE *,

** LA TIERRA
*,

*******************);
}
Donde quiera que un programa identifique a esta funcin, la expresin har que se invoque la
funcin.
Una definicin de funcin tiene un nombre y unos parntesis que contienen cero o ms
parmetros y un cuerpo. Para cada parmetro debe de haber una declaracin correspondiente
antes del cuerpo, cualquier parmetro que no se declar se considera un int por omisin, a estos
parmetros se les llama parmetros formales de funcin. El cuerpo de la funcin es un bloque o
una proposicin compuesta, y tambin puede contener declaraciones, todas las variables
declaradas en el cuerpo de una funcin se dice que son variables locales. Otras variables no
declaradas ni como argumentos ni en el cuerpo de la funcin se consideran como globales a la
funcin y deben definirse en forma externa.
La proposicin return
La proposicin return puede incluir u omitir una expresin.
Proposicin _return ::= return; \ return expresin;
Algunos ejemplos son:
return;
return (377);
return (a * b);
return (++x);
return ++x;

Invocacin y llamada por valor


La funciones se declaran como objetos individuales que no pueden anidarse. Por tanto un
programa consiste en una serie de una o ms definiciones de funciones. Estas funciones estn
disponibles para usarse en el cuerpo de las dems. Pueden emplearse donde quiera que sea
apropiado la expresin del tipo dado para el especificador de tipo de la funcin ( Recurdese que
si un especificador de tipo de una funcin est ausente, entonces por omisin es int.)
Las funciones se invocan al escribir su nombre y una lista adecuada de argumentos entre
parntesis. Todos los argumentos pasan con una llamada por valor. Se evala cada argumento y
su valor se utiliza de forma local en lugar del parmetro formal.
Invocacin y llamada por referencia
En la practica moderna de la programacin, el empleo de una variable externa global como va de
comunicacin entre una funcin y el medio que la llama se considera indeseable. El proceso de
declarar un parmetro de funcin como apuntador y utilizar en forma consistente el parmetro
desreferenciado en el cuerpo de la funcin se le denomina llamada por referencia. Cuando se
pasa una direccin como argumento, puede hacerse que la funcin cambie el valor de la variable
direccionada en el medio que la llama.
Para indicar que un parmetro de funcin es pasado por referencia, slo coloque ampersand (&)
despus del tipo del parmetro en el prototipo de funcin.

Pag 5

int ordena(int &lista)


La invocacin de una funcin significa
1. Se evala cada expresin de la lista de argumentos.
2. Al principio del cuerpo de la funcin se asigna el valor de la expresin a su parmetro
formal correspondiente.
3. Se ejecuta el cuerpo de la funcin.
4. Si se ejecuta una proposicin return, el control regresa al medio que hizo la llamada.
5. Si la proposicin return incluye una expresin, el valor de la expresin se convierte (si es
necesario) al tipo dado por el especificador de tipo de la funcin y ese valor tambin
regresa al medio que hizo la llamada.
6. Si no hay una proposicin return el control regresa al medio que hizo la llamada cuando
se llega al final del cuerpo de la funcin.
7. Si se ejecuta una proposicin return que no tiene una expresin o si no hay una
proposicin return, entonces no regresa ningn valor til al medio que hizo la llamada
Especificador de tipo void
El especificador de tipo void se usa para declarar funciones que no se pretende que devuelvan
valores. Emplear una funcin void en una expresin que requiere un valor hace que el compilador
produzca un mensaje de error.
Estructura de un programa
La base de la programacin en C es la funcin, pues constituye una parte fundamental de la
codificacin en el proceso de solucin de problemas. Todas las funciones estn en el mismo nivel
externo; no se pueden anidar unas en otras. Un programa contiene una o ms funciones en uno o
ms archivos. Una de las funciones es main() donde se inicia la ejecucin del programa. El resto
de las funciones se llaman desde main() y desde el interior de otras
main()
Todo programa tiene una funcin main donde inicia la ejecucin; los parntesis que van
despus de main indican al compilador que se trata de una funcin
{
Las llaves encierran al cuerpo de la funcin; tambin se usan para agrupar varias
proposiciones.
printf()
El sistema contiene una biblioteca estndar con funciones que pueden usarse en
programas; est es una funcin de la biblioteca estndar que imprime en pantalla.
de mar en mar C\n
En C una constante de cadena es una serie de caracteres entre comillas. Esta cadena es un
argumento de la funcin printf() y controla lo que se escribir los dos caracteres \n al final
de esta cadena representan un carcter sencillo llamado nuevalnea; ste es un carcter
que no se imprime, su efecto es hacer que el cursor avance hacia una lnea nueva.
}
La llave derecha hace pareja con la llave de una funcin y da por terminada la funcin main

Pag 6

Identificadores.
Los identificadores representan objetos de un programa ( constantes, variables, tipos de datos
procedimientos, funciones, unidades, programas y campos de registros). Un identificador es una
secuencia de caracteres que pueden ser de cualquier longitud, pero slo los primeros 63
caracteres son significativos.
Un identificador se caracteriza por estas reglas:
1. Debe comenzar con una letra (A a Z maysculas o minsculas) y no puede contener
blancos.
2. Letras dgitos y caracteres subrayados estn permitidos despus del primer carcter.
3. No se puede utilizar una palabra reservada como identificador, sin embargo, los
identificadores estndar se pueden redefinir
Palabras reservadas.
Las palabras reservadas en C tienen un significado especial y no se pueden utilizar para otros
propositos

auto
const
double
float
int
short
struct
unsigned

break
continue
else
for
long
signed
switch
void

case
default
enum
goto
register
sizeof
typedef
volatile

char
do
extern
if
return
static
union
while

Operadores aritmticos
Los operadores aritmticos (+,-,*) pueden ser utilizados con tipos enteros o reales, si ambos son
enteros el resultado es entero si uno es real el resultado es real.
2+3
2 +3.0
2.0 + 3
2.0 + 3.0

=5
= 5.0
= 5.0
= 5.0

Operador
+
*
/
%

Significado
Suma
Resta
Multiplicacin
Divisin
Mdulo

Ejemplo
a+b
ab
a*b
a/b
a%b

Resultado
Suma de a y b
Diferencia de a y b
Producto de a por b
Cociente de a por b
Resto de a por b

Operadores Incrementales y decrementales


++
++a
Se incrementa a en 1 y a continuacin se utiliza el
nuevo valor de a en la expresin en la cual resida
a.
++
a++
Utiliza el valor actual de a en la expresin en la
cual reside a, y despus se incrementa a en 1
---b
Se decrementa b en 1 y a continuacin se utiliza el
nuevo valor de b en la expresin en la cual reside

Pag 7

--

b.
Se utiliza el valor actual de b en la expresin en la
cual reside b, y despus se decrementa a b en 1

b--

Operadores de asignacin
+=
C += 7
-=
D -= 4
*=
e*=5
/=
F /= 3
%=
g %= 9

c = c +7
d=d-4
e = e* 5
f=f/3
g=g%9

Prioridad de operadores
Cuando una expresin aritmtica se evala, el resultado es siempre un nmero. Cuando en una
expresin aparecen dos o ms operadores, qu operacin se realiza primero?.
Reglas de evaluacin de expresiones.

1. Todas las subexpresiones entre parntesis se evalan primero. Las subexpresiones con
parntesis anidados se evalan de dentro a afuera; el parntesis ms interno se evala
primero.
2. Prioridad de operaciones. Dentro de una misma expresin o subexpresin, los
operadores se evalan en el siguiente orden:
*,/,% primero
+,ltimo
3. Regla asociativa izquierda. Los operadores en una misma expresin o subexpresin con
igual nivel de prioridad (tal como * y /) se evalan de izquierda a derecha.

El orden de las operaciones es:


x
-(A +

2)

+
Pag 8

Escritura de formulas matemticas en C.


En C las formulas matemticas se deben escribir en formato lineal. Esto obliga al uso frecuente de
parntesis que indiquen el orden de evaluacin correcto de los operadores.
M = y2 y1
x2 x1

m = (y2 - y1) / (x2 x1)

Operadores relacionales y lgicos.


Operadores de relacin
Se utilizan para expresar condiciones y describen una relacin entre dos valores.
Operador

Significado
Mayor que
Menor que
Igual que
Mayor o igual que
Menor o igual que
Distinto a

<
>
==
>=
<=
!=

Equivalente matemtico
>
<
=

Los operadores de relacin se utilizan en condiciones cuyo formato tiene una de las siguientes
formas:
1. variable
operador relacional
2. constante operador relacional

variable
constante

El resultado de la expresin lgica es un valor tipo lgico: verdadero o falso.


Expresin
6.7315 < 6.7342
-124.2 < 0.003
8 == 8.0
A < B
Z < H

valor
0
1
1
1
1

Operadores lgicos
Las expresiones lgicas pueden combinarse para formar expresiones ms complejas utilizando los
operadores lgicos: &&, || y !. Estos operadores se utilizan con constantes lgicas de forma
similar al modo en que los operadores aritmticos se utilizan con las constantes numricas, estos
operadores trabajan con operandos que son expresiones lgicas.
[operando1]

operador

operando2

Segn el tipo de operador puede no existir

Orden
1.
2.
3.

de evaluacin de operadores lgicos.


!
&&
||

Pag 9

Operador
!
*,/,%,&&
+,-,||
< , <= , == , <> , >= , >
Si existen parntesis las expresiones de
su

Prioridad
Mas alta (se evala primero)
Mas baja se evala al ultimo
Interior se evalan primero

((x *

>

2 >

3)

||

(x

1))

&&

(y <

5)

>

>

<

||

&&

Pag 10

Operador &&
Operando1
1
1
0
0
Operador ||
Operando1
1
1
0
0

Operando2

Operando1 && Operando2

1
0
1
0

Operando2
1
0
1
0

1
0
0
0

Operando1 || Operando2
1
1
1
0

Operador !
Operando1

! Operando1

Pag 11

Estructuras de control
Selectivas.
La sentencia if.
Sentencia de control que dirige a la computadora para ejecutar una sentencia si la expresin es
verdadera, y otra en caso de ser falsa.
Formato

if (expresin lgica)
proposicion1
else
proposicin2
proposicin siguiente
En muchos casos se desea que una determinada accin slo ejecute si una cierta condicin es
verdadera y no realizar ninguna accin si la condicin es falsa.
if (condicin)
sentencia
Sentencia compuesta.
{
sentencia
sentencia
sentencia
sentencia

1;
2;
3;

n;

}
Ejemplo:
#include <stdio.h>
main()
{
if (grado >=90)
Printf(A\n);
else if (grado >=80)
Printf(B\n);
else if (grado >=70)
Printf(C\n);
else if (grado >=60)
Printf(D\n);
else if (grado >=50)
Printf(F\n);
}
La sentencia switch
La sentencia switch se utiliza para elegir entre diferentes alternativas.

Pag 12

switch (expresion_entera){
case 1 : sentencia1;break;
case 2 : sentencia2;break;
case 3 : sentencia3;break;
case n : sentencian;break;
[default :sentencia x]
} {case}
El siguiente ejemplo utiliza switch para contar el nmero de cada distinta letra de calificacin
que los estudiantes alcanzarn en un examen.
/*Contando calificaciones*/
#include <stdio.h>
main()
{
int Letra;
int acontador = 0, bcontador =0, contador = 0,
dcontador =0, fcontador = 0;
printf(Mete la Letra de su calificacin.\n);
printf(Mete el carcer EOF para finalizar las entradas.\n);
while ((Letra = getchar() ) != EOF) {
switch (Letra) {
case A: case a:
acontador;
break;
case B: case b:
bcontador;
break;
case C: case c:
ccontador;
break;
case D: case d:
dcontador;
break;
case F: case f:
fcontador;
break;
default
{printf(
Letra de entrada incorrecta);
printf( Meta una nueva calificacin.\n);}
break;
}
}
printf(\nTotales de cada calificacion\n);
printf(A: %d\n, acontador);
printf(B: %d\n, bcontador);
printf(C: %d\n, ccontador);

Pag 13

printf(D: %d\n, dcontador);


printf(F: %d\n, fcontador);
return 0;
}
EOF es una constante simblica entera, definida en el archivo de cabecera <stdio.h>
Mete la letra de su c
Mete el carcer EOF para finalizar las entradas
A
B
C
C
A
D
F
C
E
Letra de entrada incorrecta meta una nueva calificacin
D
A
B
Totales de cada calificacin
A: 3
B: 2
C: 3
D: 2
F: 1
La sentencia while.
La estructura repetitiva while (mientras) es aquella en la que el nmero de iteraciones no se
conoce por anticipado y el cuerpo del bucle se repite mientras se cumple una determinada
condicin.

while (expresin lgica)


{
Sentencia 1
Sentencia n
}

1. La condicin (expresin lgica) se evala antes y despus de cada ejecucin del bucle. Si
la condicin es verdadera se ejecuta el bucle y si es falsa el control pasa a la sentencia
siguiente al bucle.
2. Si la condicin se evala falso cuando se ejecuta el bucle por primera vez el cuerpo del
bucle no se ejecutar nunca.
3. Mientras la condicin sea verdadera el bucle se ejecutar, esto significa que el bucle se
ejecutar indefinidamente a menos que algo en el interior del bucle modifique la condicin
haciendo que su valor pase a falso.

Pag 14

Ejemplo: El promedio de la clase es igual a la suma de calificaciones dividida por el nmero de


alumnos. El algoritmo para resolver este problema en una computadora, debe introducir cada una
de las calificaciones, ejecutar el clculo de promedio e imprimir el resultado.
#include <stdio.h>
main()
{
int, contador, grado, total, promedio;
total = 0;
/*inicializacion*/
counter = 1;
/*procesamiento*/
while (counter <=10) {
printf (Mete grado:);
scanf(%d,&grado);
total = total +grado;
counter++;
}
promedio = total / 10;
printf(El promedio de la clase es %d\n, promdio);
return 0;
}
La sentencia do while.
Una variante de la sentencia while es la sentencia do while, esta sentencia especifica un bucle
condicional que se repite hasta que la condicin se hace falsa.

do
Sentencia 1
sentencia n
while (expresin lgica);
1. La condicin se evala al final del bucle, despus de ejecutarse todas las sentencias
2. Si la expresin lgica es verdadera, se vuelve a repetir el bucle y se ejecutan todas las
sentencias.
3. Si la expresin lgica es verdadera, se sale del bucle y se ejecuta la siguiente sentencia a
while.
4. La sintaxis no requiere {}.
El siguiente ejemplo utiliza una estructura do while para imprimir los nmeros del 1 al 10.
#include <stdio.h>
main()
{
int contador = 1;
do {
printf (%d , contador);
}
while (++contador <= 10);
return 0;
}

Pag 15

La sentencia for.
Esta sentencia requiere que sepamos por anticipado el nmero de veces que se ejecutan las
sentencias del interior del bucle.

for ( expresion1; expresion2; expresion3 )


{
Sentencia 1;
Sentencia 2;
Sentencia n
}
#include <stdio.h>
main()
{
int contador;
/*inicializacin, condicin de repeticin, e incremento*/
for (contador=1; contador <=10; contador++)
printf(%d\n,contador);
return 0;
}
ejemplo utillizando la estructura for
a) Vare la variable de control de 1 a 100 en incrementos de 1.
for (i=1;i<=100; i++)
b) Vare la varible de control de 100 a 1 en incrementos de 1 (decrementos de 1).
for ( i = 7; i <=77;i+=7)
c) Variar la variable de control a lo largo de la siguiente secuencia de valore: 2, 5, 8, 11, 14,
17, 20.
for (j= 2; j <=20; j+=3)
d) Variar la variable de control de acuerdo a la siguiente secuencia de valores: 99, 88, 77, 66,
55, 44, 33, 22, 11, 0.
for (j=99;j>=0;j-=11)
Los siguientes ejemplos proporcionan aplicaciones simples de la estructura for. El programa
siguiente utiliza la estructura for para sumar todos los enteros pares desde 2 hasta 100
/*Sumacin con for*/
#include <stdio.h>
main()
{
int sum = 0, number;
for (number = 2; number <=100; number +=2)
sum += number;
printf(Sum es %d\n,sum);
return 0;
}

Sum es 2550

Pag 16

Ordenamientos y bsquedas
Arreglos
Un arreglo es una estructura de datos en la que se almacena una coleccin de datos del mismo
tipo, es una lista de un nmero finito n de elementos del mismo tipo que se caracteriza por:
1. Almacenar los elementos del arreglo en memoria continua.
2. Tener un nico nombre de variable que representa todos los elementos y estos a sus vez
se diferencian por un ndice o subndice.
3. Acceso directo o aleatorio a los elementos individuales del arreglo.

Para referirse a una posicin en particular o elemento dentro del arreglo, especificamos el nombre
del arreglo y el nmero de posicin del elemento particular dentro del mismo.
Los arreglos se clasifican en:
Unidimensionales
Multidimensionales

(vectores o listas)
(tablas o matrices)

En la figura se muestra un arreglo de nmeros reales llamado x . Este arreglo contiene 8


elementos. Cualquiera de estos elementos puede ser referenciado dndole el nombre del arreglo
seguido del nmero de posicin de dicho elementos en particular en parntesis cuadrados o
corchetes ([]). El primer elemento de cualquier arreglo es el elemento cero. Entonces el primer
elemento de un arreglo x se conoce como x[0], el segundo como x[1], el sptimo como x[6] y en
general, el elemento de orden i del arreglo x se conoce como x[i-1]. Los nombres de los arreglos
siguen las mismas reglas convencionales que los dems nombres de la variables.
Ejemplo:
float x[8];
x[0]
x[1] x[2]
x[3]
x[4] x[5]
x[6]
45.2 12.0 3.45 4.32 0.31 513. 2.65 13.0
1
4
6
4

x[7]

El nmero de posicin que aparece dentro de los corchetes se conoce ms formalmente como
subndice. Un subndice debe de ser un entero o una expresin entera. Si un programa utiliza una
expresin como subndice, entonces la expresin se evala para determinar el subndice. Por
ejemplo, si a = 3 y b = 4, entonces el enunciado
C[a + b] +=2;
Aade 2 al elemento del arreglo c[11]. Note que un nombre de arreglo con subndice es un Ivalue
que puede ser utilizado al lado izquierdo de una asignacin.
Examinaremos el arreglo x. Sus 8 elementos se conocen como x[0], x[1], x[2],....,x[7]. El valor
de x[0] es 45.21, el valor de c[1] es 12.0, el valor de c[2] es 3.45, el valor de x[6] es de 2.65 y el
valor de x[7] es 13.04.
Para imprimir la suma de los valores contenidos en los primeros tres elementos del arreglo x,
escribiramos
Printf (%f,x[0] +x[1] + x[2]);
Para dividir el valor del sptimo elemento del arreglo x entre 2 y asignar el resultado a la variable
c escribiramos
C= x[6] / 2;

Pag 17

Como declarar arreglos


Los arreglos ocupan espacio en memora. El programador especifca el tipo de cada elemento y el
nmero de elementos requerido por cada arreglo, de tal forma que la computadora pueda
reservar la cantidad apropiada de memora. Para indicarle a la computadora que reserve 12
elementos para el arreglo entero c, la declaracin
int c[12];
es utilizada. La memoria puede ser reservada para varios arreglos dentro de una sola declaracin,
Para reservar 100 elementos para el arreglo entero b y 27 elementos para el arreglo entero x, se
puede utilizar la siguiente declaracin
int b[100], x[27];
Los arreglos pueden ser declarados para que contengan otro tipo de datos. Por ejemplo un arreglo
de tipo char puede ser utilizado para almacenar una cadena de caracteres.
Ejemplos utilizando arreglos
El programa siguiente utiliza la estructura de repeticin for para inicializar los elementos de un
arreglo entero de diez elementos n a ceros, e imprime el arreglo en formato tabular.
El enunciado printf muestra los encabezados de columnas de las dos columnas impresas en la
estructura for.
/* inicializa el arreglo*/
#include <stdio.h>
main()
{
int n[10], i;
for (i = 0; i <= 9; i++)
/*inicializa el arreglo*/
n[i] = 0;
printf(%s%13s\n, Elemento, Value);
for(i= 0; i <= 9; i++)
/*imprime arreglo*/
printf(%7d%13d\n,i, n[i]);
return 0;
}

Elemento
0
1
2
3
4
5
6
7
8
9

Value
0
0
0
0
0
0
0
0
0
0

Pag 18

El programa siguiente suma los valores contenidos en un arreglo entero a de doce elementos. El
enunciado en el cuerpo del ciclo for se ocupa de la totalizacin.
/* Calcula la suma de los elementos del arreglo*/
#include <stdio.h>
#define SIZE 12
main()
{
int a [SIZE] = {1, 3, 5, 4, 7, 2, 99, 16, 45, 67, 89, 45}
i, total =0;
for (i=0; i <=SIZE 1;i++)
total += a[i]
printf(El total del valor de los elementos del arreglo es %d\n,total);
return 0;
}

El total del valor de los elementos del arreglo es 383


El siguiente ejemplo utiliza arreglos para resumir los resultados de datos recopilados en una
investigacin. Deseamos resumir el nmero de respuestas de cada tipo (es decir del 1 hasta el
10). El arreglo respuestas es un arreglo de 40 elementos correspondiente a las respuestas de los
alumnos. Utilizamos un arreglo de 11 elementos, frecuencia para contar el nmero de ocurrencias
de cada respuesta. Ignoramos el primer elemento frecuencia[0], por que es ms lgico tener un
incremento de respuesta 1 frecuencia[1] que frecuencia[0]. Esto nos permite utilizar cada
respuesta directa como subndice en el arreglo frecuencia.
El primer ciclo for toma las respuestas del arreglo respuestas una por una e incrementa uno de
los diez contadores (frecuencia[1] hasta frecuencia [10] ) en el arreglo frecuencia. El enunciado
clave es
++frecuencia[respuestas[pregunta]
Este enunciado incrementa
el contador frecuencia apropiado, dependiendo del valor de
respuestas[pregunta]. Por ejemplo cuando la variable del contador pregunta es 0,
respuestas[pregunta] es 1 y por lo tanto, ++frecuencia [respuesta[pregunta]]; se interpreta en
realidad como
++frecuencia[1];
#include <stdio.h>
#define RESPUESTAS_SIZE 40
#define FRECUENCIA_SIZE 11
main()
{
int answer, rating;
int respuestas[RESPUESTAS_SIZE] = {1, 2, 6, 4, 8, 5, 9, 7, 8, 10, 1, 6, 3, 8, 6, 10, 3, 8,
2, 7, 6, 5, 7, 6, 8, 6, 7, 5, 6, 6, 5, 6, 7, 5, 6, 4, 8, 6, 8, 10);
int frecuencia[FRECUENCIA_SIZE] = {0};
for (pregunta = 0; pregunta <= RESPUESTA_SIZE 1; answer++)
++frecuencia[respuestas[pregunta]];
printf (%s%17s\n,Rating, Frecuencia);
for (rating = 1; rating <= FRECUENCIA_SIZE 1; rating++)
printf(%6d%17d\n, rating, frecuencia[rating]);
return 0;
}

Pag 19

Rating
1
2
3
4
5
6
7
8
9
10

Frecuencia
2
2
2
2
5
11
5
7
1
3

Cmo pasar arreglos a funciones


Para pasar cualquier argumento de arreglo a una funcin, especifique el nombre del arreglo, sin
corchete alguno. Por ejemplo, si el arreglo Temperaturas ha sido declarado como
int Temperaturas[24];
El enunciado de llamada a la funcin
ModificaArreglo(Temperaturas, 24);
Pasa el arreglo Temperaturas y su tamao, a la funcin ModificaArreglo, al pasar un arreglo esl
tamao del arreglo se pasa a una funcion, de tal forma que pueda procesar el nmero especifico
de elementos incluidos en dicho arreglo.
C pasa de forma automtica los arreglos a las funciones utilizando simulacin de llamadas por
referencia las funciones llamadas pueden modificar los valores de los elementos en los arreglos
originales de los llamadores. El nombre del arreglo de hecho es la direccin del primer elemento
de dicho arreglo. Dado que ha sido pasada la direccin inicial del arreglo, la funcin llamada sabe
precisamente dnde est el arreglo almacenado. Por lo tanto, cuando en su cuerpo de funcin, la
funcin llamada modifica los elementos del arreglo, est modificando los elementos reales del
arreglo, en sus localizaciones de memoria originales.
#include <stdio.h>
main()
{
char array[5];
printf (
array = %p\n&array[0] = %p\n, array, &array[0]);
return 0;
}

array = FFF0
&array = FFF0
Arreglos multidimensionales
Aunque los elementos de los arreglos se almacenan en forma contigua, con frecuencia resulta til
imaginar que un arreglo bidimensional es un conjunto rectangular de elementos con filas y
columnas. Por ejemplo si se declara:
int b[3] [5];

Pag 20

Puede imaginarse que los elementos del arreglo estn ordenados de la manera siguiente:
Col 1
Col 2
Col 3
Col 4
Col 5
Fila 1
Fila 2
Fila 3

B[0] [0]
B[1] [0]
B[2] [0]

B[0] [1]
B[1] [1]
B[2] [1]

B[0] [2]
B[1] [2]
B[2} [2]

B[0] [3]
B[1] [3]
B[2] [3]

B[0] [4]
B[1] [4]
B[2] [4]

Los arreglos de doble subndice se referencian con los subndice dentro de un mismo par de
corchetes separando por comas los subndices.
t[x,y];
y no
t[x] [y];
Los arreglos de doble subndice pueden ser declarados e inicializados de la siguiente manera
int b[2][2] = {{1,2},{3,4}};
Muchas manipulaciones comunes con arreglos utilizan estructuras de repeticin for. Por ejemplo,
la siguiente estructura define todos los elementos en el tercer rengln del arreglo a
int a[4][4];
for (column = 0;column 3; column++)
A[2] [column] =0
Especificamos el tercer rengln, por lo tanto, sabemos que el primer subndice ser siempre 2 (o
es el primer rengln y 1 el segndo). El ciclo for vara slo en el segundo subndice (es decir, el
subndice de columnas). La estructura for anterior es equivalente a los enunciados de asignacin
siguientes:
a[2][0]
a[2][1]
a[2][2]
a[2][3]

=
=
=
=

0;
0;
0;
0;

En el arreglo a, la siguiente estructura for anidada determina el total de todos los elementos.
Total = 0;
for (renglon =0; renglon <=3; renglon++)
for (column = 0;column <=3; column++)
total +=[renglon] [column];
Cadenas
Una cadena es una secuencia de caracteres encerrada entre comillas . Obsrvese que el smbolo
es un solo carcter, no dos. Si el carcter ha de aparecer en una cadena, debe ir precedido del
carcter \. A continuacin se presentan varios ejemplos de cadenas.
una cadena de texto

/*una cadena de caracteres blancos */


z
,.1kM87tt - basura
una cadena con \ comillas incorporadas
a = b + c;
x =sin(y);
nada se ejecuta

/* la cadena nula */

Pag 21

Las cadenas son arreglos unidimensionales de tipo char que tinen varas caractersticas nicas.
Un arreglo de caracteres puede ser inicializado utilizando una literal de cadena. Por ejemplo, la
declaracin
char string1[] = first;
Inicializa los elementos de la cadena string1 a los carcteres individuales de la literal de cadena
first. El tamao del arreglo string1 en la declaracin anterior queda determinada por el
compilador, basado en la longitud de la cadena. Es importante hacer notar que first contiene 5
caracteres, ms un carcter especial de terminacin de cadena, conocido como carcter nulo.
Entonces el arreglo string1 de hecho contiene 6 elementos, la representacin de la constante de
caracteres del carcter nulo es \0. En C todas las cadenas terminan con este carcter. Un arreglo
de caracteres representando una cadena debera declararse siempre lo suficientemente grande,
para contener el nmero de caracteres de la caden incluyendo el carcter nulo de terminacin..
Los arreglos de caracteres tambin pueden ser inicializados con constantes individuales de
caracteres en una lista de inicializacin. La declaracin anterior es equivalente a
char string1[] = {f,i,r,s,t,\0};
Dado que la cadena es un arreglo de caracteres podemos tener acceso directo a los caracteres
individuales de una cadena, utilizando la notacin de subndices de arreglos. Por ejemplo,
string1[0], es el carcter f y string[3] es el carcter s.
Tambin podemos introducir desde el teclado directamente una cadena en un arreglo de
caracteres, utilizando scanf y la especificacin de conversin %s. Por ejemplo, la declaracin .
char string2[20];
Crea un arreglo de caracteres capaz de almacenar una cadena de 19 caracteres y un carcter nulo
de terminacin. El enunciado
scanf (%s, string2);
Lee una cadena del teclado y la coloca en string2. Note que el nombre del arreglo se pasa a scanf
sin colocar el & precedente, que en otras variables se utiliza. El & es utilizado por lo regular para
darle a scanf una localizacin de variable en memoria, a fin de que se pueda almacenar un valor
ah.
El nombre de un arreglo es la direccin del inicio del arreglo y, por tanto, & no es necesario.
La funcin scanf lee caracteres del teclado hasta que se encuentra con el primer carcter de
espacio en blanco sin impotarle que tan grande es el arreglo. Por lo tanto, scanf podra escribir
ms all del final del arreglo.
Un arreglo de caracteres que represente una cadena puede ser sacado utilizando printf y el
especificador de convesin %s. El arreglo string2 se imprime utilizando el enunciado
printf (%s\n, string2);
#include <stdio.h>
main()
{
char string1[20], string2[] = string literal;
int i;
printf(Mete un string: );
scanf(%s,string1);
printf(string1 es: %s\nstring2 es %s\n
string1 con espacios entre caracteres es: \n,
string1, string2);

Pag 22

for (i = 0; string1[i] != \0; I++)


printf(%c , string1[i]);
printf(\n);
return 0;
}

Mete un string: Hello there


string1 es: Hello
string2 es : string literal
string con espacios entre caracteres es :
He l l o
Uniones
Una union es un tipo de datos derivado como lo es una estructura- cuyos miembros comparten
el mismo espacio de almacenamiento. Para distintas situaciones en un programa, algunas
variables pudieran no ser de importancia, pero otras variables lo son por lo que una union
comparte el espcacio, en vez de desperdiciar almacenamiento en variables que no esten siendo
utilizadas. Los miembros de la union pueden ser de cualquier tipo el nmero de bytes utilizados
para almacenar una unin, deben ser por lo menos suficientes para contener al miembro mas
grande. En la mayor parte de casos las uniones contienen dos o ms tipos de datos. Unicamente
un miembro y, por lo tanto, nicamente un tipo de datos, puede ser referenciado en un momento
dado
union number{
int x;
float y;
}
indica que number es un tipo union con miembros int x y float. En un programa normalmente la
definicin de unin antecede a main, por lo que esta puede ser utilizada para declarar variables en
todo el programa.
Las operaciones que pueden ser ejecutadas en una unin son: asignar una unin a otra unin del
mismo tipo, tomar la direccin (&) de una unin, y tener acceso a los miembros de una union
utilizando el operador de miembro de estructura y el operador de apuntador de estructura.
En una declaracin, una union puede ser inicializada nicamente con un valor del mismo tipo que
el primer miembro de la union. Por ejemplo, en la union anterior, la declaracin
union number value ={10};
Es una inicializacin valida de la variable de union value, porque la union esta inicializada con un
int, pero la siguiente declaracin no sera valida:
union number value = [1.43]
Constantes de enumeracin
C proporciona un tipo final, definido por el usuario, conocido como una enumeracin. Una
enumeracin, introducida por la palabra reservada enum, es un conjunto de constantes enteras
representadas por identificadores. Estas constantes de enumeracin son, en efecto, constantes
simblicas, cuyos valores pueden ser definidos automticamente. Los valores de un enum se
inician con 0, a menos de que se defina de otra manera, y se incrementan en 1. Por ejemplo
enum months {JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC};

Pag 23

Crea un nuevo tipo en enum months, en el cual los identificadores son definidos automticamente
a los enteros 0 a 11. Para numerar los meses 1 a 12, utilice la enumeracin siguiente
enum monts {JAN =1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV,
DEC};
Dado que el primer valor de la enumeracin se define explcitamente en 1, los valores
subsiguientes se incrementan en 1dando como resultado los valores 1hasta 12
Los identificadores en una enumeracin deben de ser unicos. En una enumeracin el valor de cada
constante en la enumeracin puede ser establecido explcitamente en la definicin, mediante la
asignacin de un valor al identificador. Varios miembros pueden tener el mismo valor entero.
#include <stdio.h>
enum months {JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC};
main ()
{
enum months month;
char *monthName[] = {, January,February,March,April,May,
June,July,August, September, October,November, December};
for (month = JAN; month <=DEC; month++)
printf(%2d%11s\n,month, monthName[month]);
return 0
}
1
2
3
4
5
6
7
8
9
10
11
12

January
February
March
Apr
May
June
July
Aug
Sep
Oct
Nov
Dec

Apuntadores
Los apuntadores le permiten a los programas simular llamadas por referencia, crear y manipular
estructuras de datos es decir, estructuras de datos que pueden crecer o encongerse como son
listas enlazadas, colas de espera, pilas y rboles.
Los apuntadores son variables que contienen direcciones de memoria como sus valores. Por lo
regular una variable contiene directamente un valor especifico, un apuntador por otra parte,
contiene la direccin de una variable que contiene un valor especifico. En este sentido un nombre
de variable se refiere directamente a un valor y un apuntador se refiere indirectamente a un valor,
el referirse a un valor a travs de un apuntador se conoce como indireccin.
Los apuntadores como cualquier otra variable deben ser declarados antes de que puedan ser
utilizados.

Pag 24

int *contadorAptr, contador;

contador

Contador se refiere
directamente a la
variable cuyo valor es
7.

contadorAptr

contador
ContadorAptr se
refiere en forma
indirecta a la
variable cuyo
valor es 7

La declaracin declar la variable contadorAptr siendo del tipo int*, se lee, contadorAptr es un
apuntador a int, o bien contadorAptr apunta a un objeto de tipo entero. Tambin, la variable
contador se declara como un entero, no un apuntador a un entero. El *solo se aplica a
contadorAptr en la declaracin.
Los apuntadores deben ser inicializados cuando son declarados o en un enunciado de asignacin.
Un apuntador puede ser inicializado a 0, NULL, o una direccin. Un apuntador con el valor NULL
apunta a nada. NULL es una constante simblica, definida en el archivo de cabecera<stdio.h>.
Cuando se inicializa 0 es equivalente a inicializar un apuntador a NULL. El valor 0 es el nico valor
entero que puede ser directamente asignado a una variable de apuntador
Operadores de apuntador
El &, u operador de direccin, es un operador unario que regresa la direccin de su operando. Por
ejemplo, suponiendo las declaraciones
int y= 5;
int *yPtr;
el enunciado
yPtr = &y;
asigna la direccin de la variable y a la variable de apuntador yPtr. La variable yPtr se dice que
apunta a

yPtr
Representacin grfica de un apuntador apuntando a una variable entera en memoria.

Pag 25

500000

yPtr
600000

y
600000

Representacin en memoria de y y yPtr.


La direccin de a y el valor de aPtr son idnticos en la salida, confirmando asi que de hecho la
direccin de a ha sido asignada a la variable de apuntador aPtr. Los operadores & * son
complementos el uno del otro.
En C se utilizan los apuntadores y el operador de indireccin para simular llamadas por referencia.
Cuando se pasan direcciones de los argumentos que deban ser modificados, se pasan las
direcciones de los argumentos. Esto se lleva a cabo aplicando el operador de direccin (&), a la
variable cuyo valor deber ser modificado. Cuando se pasa a una funcin la direccin de una
variable, el operador de indireccin (*), puede ser utilizado en la funcin para modificar el valor
de esa posicin en la memoria de ese llamador
#include <stdio.h>
CuboPorReferencia(int *);
main()
{
int numero = 5;
printf(El valor original del nmero es %d\n,number)
cuboPorReferencia(&number);
printf(El nuevo valor de el nmero es %d\n,number);
return 0;
}
void cuboPorReferencia(int *nPtr)
{
*nPtr = *nPtr * *nPtr* *nPtr;
}
Relacin entre apuntadores y arreglos
Los arreglos y los apuntadores en C estn relacionados en forma intima y pueden ser utilizados
casi en forma indistinta . Un nombre de arreglo puede ser considerado como un apuntador
constante. Los apuntadores pueden ser utilizados para hacer cualquier operacin que involucre
subndices de arreglos.
Suponga que han sido declarados el arreglo entero b[5] y la variable de apuntador entera bPtr.
Dado que el nombre del arreglo (sin subndice) es un apuntador al primer elemento del arreglo,
podemos definir bPtr igual a la direccin del primer elemento en el arreglo b mediante el
enunciado.
bPtr = b;
Este enunciado es equivalente a tomar la direccin del primer elemento del arreglo, como sigue
bPtr = &b[0]
Alternativamente el elemento del arreglo b[3] puede ser referenciado con la expresin de
apuntador

Pag 26

*(bPtr + 3)
El 3 en la expresin arriba citada es el desplazamiento del apuntador. Cuando el apuntador
apunta al principio del arreglo, el desplazamiento indica que el elemento del arreglo debe ser
referenciado, y el valor del desplazamiento es idntico al subndice del arreglo, la notacin
anterior se conoce como notacin apuntador/desplazamiento.Al igual que el elemento del arreglo
puede ser referenciado con una expresin de apuntador, la direccin
&[3]
puede ser escrita con la expresin de apuntador
bPtr + 3
El arreglo mismo puede ser tratado como un apuntador, y utilizado en aritmtica de un
apuntador.
Por ejemplo la expresin
*(b + 3)
tambin se refiere al elemento del arreglo b[3]. En general, todas las expresiones de arreglos son
subndice pueden ser escritas mediante un apuntador y un desplazamiento.
Arreglos de apuntadores
Los arreglos pueden contener apuntadores. Un uso comn para una estructura de datos como
sta, es formar un arreglo de cadenas. Cada entrada del arreglo es una cadena pero en C una
cadena es esencial un apuntador a su primer carcter. Por lo que en un arreglo de cadenas cada
entrada es de hecho un apuntador al primer carcter.
char *suit[4] = {Corazones,Diamantes, Espadas, Treboles);
La porcin suit[4] indica un arreglo de 4 elementos. La porcin char * de la declaracin ndica
que cada elemento del arreglo suit es del tipo apuntador a char. Los cuatro valores a colocarse en
el arreglo son: Corazones, Diamantes, Treboles y Espadas. Cada una de estas est almacenada en
memoria como una cadena de caracteres terminada por NULL, de una longitud de un carcter ms
largo que el nmero de caracteres entre las comillas. En el arreglo suit parece que estan
colocadas estas cadenas pero en el arreglo solo estn almacenados los apuntadores.
Cada apuntador seala al primer carcter de su cadena correspondiente. Por lo tanto, aunque el
arreglo suit es de tamao fijo, permite el acceso a cadenas de caarcter de cualquier longitud.

Suit[0]

\0

\0

\0

\0

Suit[1]
Suit[2]
Suit[3]
Un ejemplo grfico de un arreglo suit
Asignacin dinmica de memoria mediante new y delete
Los operadores new y delete de C++ le permiten a los programas llevar a cabo la asignacin
dinmica de memoria. En ANSI C, la asignacin dinmica de memoria por lo general se lleva a
cabo con las funciones estandar de biblioteca malloc y free. Considere la declaracin
TypeName *ptr;

Pag 27

Donde typeName es cualquier tipo (como int, float, char, etctera). En ANSI C, el enunciado
siguiente asigna en forma dinmica un objeto typeName, regresa un apuntador void al objeto, y
asigna dicho apuntador a ptr
Ptr = malloc (sizeof(typeName))
En C la asignacin dinmica de memoria requiere una llamada de funcin a malloc y una
referencia explicita al operador sizeof (o una mensin explicita al nmero necesario de bytes). La
memoria se asigna sobre el montn (memoria adicional disponible para el programa en tiempo de
ejecucin). Tambin, en puestas en prctica anteriores a ANSI C, el apuntador regresado por
malloc debe ser explcitamente convertido (cast) al tipo apropiado de apuntador con el convertidor
explicito (cast) (typeName*).
En C++, el enunciado
Ptr = new typeName
Asigna memoria para un objeto del tipo typeName partiendo de la tienda libre del programa. El
operador new crea automticamente un objeto del tamao apropiado y regresa un apuntador del
tipo apropiado. Si mediante new no se puede asignar memoria, se regresa un apuntador nulo.
Para liberar en C++ el espacio para este objeto se utiliza el siguiente enunciado:
delete ptr
En C, se invoca la funcin free con el argumento ptr, a fin de desasignar memoria. El operador
delete slo puede ser utilizado para desasignar memoria ya asignada por new. Aplicar delete a
un apuntador previamente desasignado puede llevar a errores, inesperados durante la ejecucin
del programa. Aplicar delete a un apuntador nulo no tiene efecto en la ejecucin del programa.
C++ permite un inicializador para un objeto recin asignado. Por ejemplo,
float* cosaPtr = new float ( 3.14159);
Tambin mediante new los arreglos pueden ser creados dinmicamente. El siguiente enunciado
asigna dinmicamente un arreglo de un subndice de 100 enteros y asigna el apuntador regresado
por new al apuntador entero arrayPtr
int *arrayPtr;
ArrayPtr = new int[100]; //creando arreglo dinmico
Para desasignar la memoria asignada dinmicamente para arrayPtr por new, utilice el enunciado
delete [] arrayPtr;

Ordenamiento
La ordenacin o clasificacin de datos (sort) es una operacin consistente en disponer un conjunto
estructura- de datos, en algn determinado orden con respecto a uno de los campos elementos
del conjunto. Los elementos numricos se pueden ordenar en orden creciente o decreciente de
acuerdo al valor numrico del elemento. En terminologa de ordenacin, el elemento por el cual
esta ordenado un conjunto de datos se denomina clave.
Una coleccin de datos puede ser almacenada en un archivo, un arreglo (vector o tabla), un
arreglo de registros, una lista enlazada o un rbol. Cuando los datos estn almacenados en un
arreglo, una lista enlazada o un rbol, se denomina ordenacin interna. Si los datos estn
almacenados en un archivo el proceso de ordenacin se llama ordenacin externa.

Pag 28

Los mtodos (algoritmos) de ordenacin son numerosos, por ello se debe prestar especial
atencin en su eleccin Cmo se sabe cual es el mejor algoritmo? La eficiencia es el factor que
mide la calidad y rendimiento de un algoritmo.
1. tiempo menor de ejecucin en computadora
2. menor nmero de instrucciones
Los mtodos de ordenacin se suelen dividir en dos grandes grupos:

directos
indirectos(avanzados)

burbuja, seleccin, insercin


Shell, ordenacin rpida, ordenacin por mezcla

Ordenacin por burbuja


Este mtodo es clsico y muy sencillo, aunque por desgracia poco eficiente. La ordenacin por
burbuja se basa en la comparacin de elementos adyacentes de la lista (vector) e intercambiar
sus valores si estn desordenados. De este modo se dice que los valores ms pequeos burbujean
hacia la parte superior de la lista, mientras que los valores ms grandes se hunden haca el fondo
de la lista.

Supongamos un vector A[1], A[2],...,A[n]. Se comienza el seguimiento del vector de izquierda a


derecha, comparando A[1] con A[2]; si estn desordenados se intercambian entre s. A
continuacin se compara A[2] con A[3], intercambindolos si estn desordenados, este proceso
de comparaciones e intercambios continua a lo largo de toda la lista. Estas operaciones
constituyen una pasada a travs de la lista. Al terminar esta pasada el elemento mayor est en la
parte inferior y algunos de los elementos han burbujeado hacia arriba de la lista. Se vuelve a
explorar de nuevo la lista comparando elementos consecutivos e intercambindolos cuando estn
desordenados, pero esta vez el elemento mayor no se compara, ya que se encuentra en su
posicin correcta, al terminar esta pasada se habr situado en su sitio el segundo elemento ms
grande se siguen las comparaciones hasta que toda la lista este ordenada cosa que suceder
cuando se hayan realizado (n-1) pasadas. Para su mejor comprensin, veamos grficamente el
proceso anterior con un vector (lista) con cinco elementos; A[1], A[2], A[3], A[4], A[5].

A[1]

23

15

A[2]

19

19

A[3]

45

23

A[4]

31

31

A[5]

15

44

Lista sin ordenar

Lista ordenada

En la lista A, i ser el nmero de la pasada y j indica el orden del elemento de la lista.


Se compara el elemento j-esimo y el (j+1)-simo.

Pag 29

Pasada 1: i=1

A[1]

23

19

19

19

19

A[2]

19

23

23

23

23

A[3]

45

45

45

31

31

A[4]

31

31

31

45

15

A[5]

15

15

15

15

45

j=3

j=4

j=1

j=2

elemento
ordenado

Se han realizado cuatro comparaciones (5-1 o bien n-1 en el caso de n elementos) y tres
intercambios.

Pasada 2: i = 2

A[1]

19

19

19

19

19

A[2]

23

23

23

23

23

A[3]

31

31

31

15

15

A[4]

15

15

15

31

31

A[5]

45

45

45

45

45

J=1

j=2

j=3

j=4

A[1]

19

19

19

19

19

A[2]

23

23

15

15

15

A[3]

15

15

23

23

23

A[4]

31

31

31

31

31

A[5]

45

45

45

45

45

j=1

j=2

j=3

j=4

elemento
ordenado

Pasada 3: i = 3

elemento
ordenado

Pag 30

Pasada 4: i =4

A[1]

19

15

15

15

15

A[2]

15

19

19

19

19

A[3]

23

23

23

23

23

A[4]

31

31

31

31

31

A[5]

45

45

45

45

45

j=1

j=2

j=3

j=4

j=5

elemento
ordenado

Se observa que se necesitan cuatro pasadas para ordenar una lista de nmeros de cinco
elementos, por lo que una lista de n elementos necesitar n-1 pasadas.
El nmero de pasadas se puede controlar con un bucle for y cada secuencia de comparaciones se
puede controlar con un bucle for anidado al bucle de pasadas, en el que j vara desde 1 hasta 5
menos el valor especifico de i.

Algoritmo (Pseudocdigo)
Desde i = 1hasta n-1 hacer
Desde j= 1 hasta n-i hacer
Si A[j] > A[j+1]
Entonces Intercambio (A[j],A[j+1])
Fin_si
Fin _desde {bucle j}
Fin_desde
{bucle i}

void burbuja(int Lista[],int N){


int i, j,aux;
for (j=1; j<N; j++)
for (i=0; i < N-j;i++)
if (Lista[i]> Lista[I+1]){
aux = Lista[I];
Lista[i] =Lista[i+1];
Lista[i+1]= aux;
}
}
Burbuja mejorado
El algoritmo burbuja se puede mejorar si disponemos de algn tipo de indicador que registre si se
han producido intercambios en la pasada. Cuando se explor la lista y el indicador no refleje
intercambios, la lista estar ya ocupada y se terminarn las comparaciones.
El intercambio ser una variable lgica NoIntercambio (o bien ordenado) que se inicializa a 1
(significa que la lista a priori est desordenada). Si dos elementos se intercambian en una pasada.
No Intercambio se pone en 0. Al principio de cada pasada NoIntercambio se fija a 1 y a 0 si se
produce a intercambios. El bucle externo for se sustituye por un bucle do while o bien while y
un contenido i se necesitara para contar el nmero de pasadas.

Pag 31

i =1
Repetir
NoIntercambio = true
Desde j = i hasta n i hacer
Si A[j] > A[J+1]
Entonces Intercambio (A[j], A[j+1])
NoIntercambio = false
Fin si
Fin_desde
i = i+1
Hasta que NoIntercambio = true
void burbuja_mejorada(int Lista[],int N){
int i,j=1,aux,bandera=1;
while (j<N && bandera==1){
Bandera=0;
for(I=0;I<N-j;I++)
if (Lista[I]>Lista[I+1]){
Bandera=1;
Aux=Lista[I];
Lista[i]=Lista[i];
Lista[i+1]=aux;
}
j++;
}
Ordenacin por insercin
Este mtodo est basado en la tcnica utilizada por los jugadores de cartas para clasificar sus
cartas. El jugador va colocando (insertando) cada carta en su posicin correcta.
Tres cartas

10

Cuatro
cartas

//////// 9
////////

10

Cinco cartas

//////// 7
////////

10

El mtodo se basa en considerar una parte de la lista ya ordenada y situar cada uno de los
elementos restantes insertndolo en el lugar que le corresponde por su valor.

A[1]

A[2]

A[3]

10

A[4]

A[5]

15

A[N]

Pag 32

10

15

Algoritmo
{para cada elemento de la lista despus del primero}
desde k = 2 hasta n hacer
Guardar el valor de este elemento A[k] en una variable Aux.
Hacer espacio para Aux desplazando todos los valores mayores que dicho valor
A[k] una posicin.
Insertar el valor de Aux en el lugar del ultimo valor desplazado.
Fin_desde
La operacin de desplazamiento se realiza con un procedimiento Desplazar, que mueve todos los
elementos de la lista mayores que Aux, comenzando con el elemento de la lista de posicin Aux-1.
Si Aux es el valor ms pequeo hasta aqu, la operacin de desplazamiento termina despus que
todos los elementos de la lista se han desplazado. Si Aux no es el valor ms pequeo, la
operacin de desplazamiento termina cuando un valor menor o igual a Aux se alcanza. Aux se
inserta en la posicin que ocupaba el ltimo valor que se desplaz.
Algoritmo de desplazamiento
Mientras el primer elemento no se desplaza y el valor del elemento > Aux hacer
o Desplazar elemento una posicin.
o Comprobar valor del siguiente elemento.
o Definir NuevaPos como posicin original del ltimo elemento desplazado.
Fin_mientras
Codificacin del procedimiento OrdenarInsercin

void OrdenacionInsercion(int Lista[];int n){


/*Lista (entrada/salida) , n (entrada) */
/*Lista = array de N elementos enteros */
int k,
/*subindice del siguiente elemento al que se inserta*/
nueva_pos,
/*subindice de este elemento despus de la insercin*/
aux;
for(k=2;k<=n;k++){
aux = lista[k];
/*obtener siguiente elemento a insertar*/
Lista[nueva_pos(Lista,k,aux)]=aux;
/*insertar aux en posicin nueva*/
}
return 0;
}
La funcin de nueva posicin que desplaza todos los elementos de la lista
int nueva_pos (int Lista[],int k,int aux ){
int encontrado ;
{indicador}
/*desplazar valores > Aux . Comenzar con el elemento K 1
*/
encontrado= 0;
while (k > 1 && !encontrado)
if (Lista [k 1] > aux) {
Lista[k] = Lista[k 1];

Pag 33

k--;
}
else
encontrado = 1;
return k;
} {Desplazar}

Ordenacin por seleccin


El algoritmo de ordenacin por seleccin de una lista (vector) de n elementos tiene los siguientes
pasos:
1. Encontrar el elemento mayor de la lista.
2. Intercambiar el elemento mayor con el elemento de subndice n (o bien el elemento menor
en el subndice 1).
3. A continuacin se busca el elemento mayor en la sublista de subndices 1...n 1, y se
intercambiaba con el elemento de subndice n 1: por consiguiente, se sita el segundo
elemento mayor en la posicin n-1.
4. A continuacin se busca el elemento mayor en la sublista 1...n 2 y as sucesivamente.

Lista
desordenada

A[1]

-2

A[2]

14

A[3]

-2

-2

-2

A[4]

10

10

10

10

A[5]

14

14

14

El algoritmo de PosMayor debe guardar j como la posicin del elemento mayor y luego poder
intercambiar.

int PosMayor (int Ultimo,int Lista[] ){


/*encuentra el indice del elemento mayor en la tabla [1..
Ultimo]*/
int Indice_Max, Indice;
Indice_Max = 1;
for(Indice= 2; Indice<=Ultimo;Indice++)
if (Lista [Indice] > Lista [Indice_Max] )
indice_Max = Indice;
return Indice_Max;
}
void Seleccion (int Limi,int Lista[]){
int Aux, J, Mayor;
for(J=Limi; >=2 ;J++)
{

Pag 34

/*encontrar el elemento mayor de 1..J*/


Mayor = PosMayor (J, Lista);
/*Intercambio con el elemento Tabla [J]*/
Aux
= Lista[Mayor];
Lista[Mayor] = Lista[J];
Lista [J] = Aux;
}
}

Ordenamiento Shell
La ordenacin Shell debe el nombre a su inventor, D. L. Shell. Se suele denominar tambin
ordenacin por disminucin de incremento (gap). La idea general del mtodo (algoritmo) es la
siguiente:
Lista original
504

88

513

62

908

171

898

277

654

427

150

510

612

675

750

704

1. Se divide la lista original (16 elementos, en este ejemplo) en ocho grupos de dos
(consideramos un incremento o intervalo de 16/2 = 8).
2. Se clasifica cada grupo por separado (se comparan las parejas de elementos y si no estan
ordenados se intercambian entre si de posiciones).
3. Se divide ahora la lista en cuatro grupos de cuatro (intervalo o salto de 8/2 = 4) y
nuevamente se clasifica cada grupo por separado.
4. Un tercer paso clasifica dos grupos de ocho registros y luego un cuarto paso completa el
trabajo clasificando todos los 16 registros.

Primer paso (divisin/ordenacin por 8)


504

88

513

62

908

171

898

277

654

427

150

510

612

Pag 35

675

750

704

Segundo paso (divisin/ordenacin por 4)


504

88

150

62

612

171

760

277

654

427

513

510

908

675

898

704

277

654

427

760

510

908

675

898

704

Tercer paso (divisin/ordenacin por 2)


504

88

150

62

612

171

513

Cuarto paso (divisin/ordenacin por 1)


154

62

62

88

504

154

88

513

171

612

277

654

427 760

510

898

675

908

704

171

277

427

504

510

513

612 654

675

704

760

898

908

El algoritmo de Shell tiene diferentes modelos ms populares y citados en numerosas obras de


programacin
Algoritmo
Intervalo = n div 2
Mientras (intervalo > 0 ) hacer
Desde i = (intervalo + 1) hasta n hacer

Pag 36

J = i intervalo
Mientras (j >0 ) hacer
K = j + intervalo
Si ( a [j] <= a[k])
Entonces
J=0
Si no
Intercambio (a[j], a[k]
Fin si
j = j intervalo
Fin mientras
Fin desde
Intervalo = intervalo div 2
Fin mientras

Cdigo
void Intercambio (int X,int Y){
int Aux ;
Aux = X;
X = Y;
Y =Aux;
}
void Shell (int Lista[],int N){
int Intervalo =N/2, I, J, K ;
while (Intervalo > 0){
for( I = Intervalo + 1; I <=N;I++) {
J = I Intervalo;
while (J > 0) {
K = J + Intervalo;
if (Lista[J] <= Lista[K])
J = 0;
else
Intercambio (*(Lista +J),*(Lista +K));
J = J Intervalo;
} {while}
}
Intervalo /= 2;
}
return 0;
}

Pag 37

Ordenamiento Mezcla (MergeSort)


El proceso de mezcla, fusin o intercalacin (merge) consiste en tomar dos vectores ordenados
(a, b) y obtener un nuevo vector tambin ordenado.
El algoritmo ms sencillo para resolver el problema es:
1. Situar todos los elementos del vector a en el nuevo vector c.
2. Situar todos los elementos del vector b en el nuevo vector c.
3. Ordenar todo el vector c.
Esta solucin no tiene en cuenta que los valores de de a y b ya estn ordenados.
El algoritmo que tiene en cuenta la ordenacin es el siguiente:
1. Seleccionar el elemento de valor o clave mas pequeo con cualquiera de dos vectores y
situarlo en el nuevo vector c.
2. Comparar a(i) y b(i) y poner el elemento de vector ms pequeo en c(k).
3. Seguir esta secuencia de comparaciones hasta que los elementos de un vector se hayan
agotado en cuyo momento se copia el resto del otro vector en c.

Ejemplo:
Mezclar las dos listas de nmeros a y b.
2
-15

4
0

78
13

97
15

78

-15 0

13

78

97

90

lista A
lista B

96

Lista A

j se ha incrementado
junto con k

i
<
j

-15 0

15

78

90

94

96

Lista B

Lista C

Lista C

Pag 38

78

-15 0

13

97

Lista A

i
<
j

-15

15

78

90

94

96

Lista B

Comparar A[i]
Y B[j]. Poner el
Ms pequeo en
C[k]. Incrementar
Los indices apropiados

B < A[j], de modo que C[k] se obtiene de B[j]


Procedimiento mezcla de los vectores A y B
void Mezcla (int A[],int B[],int C[],int M,int N ){
int I, J, K ; /*A Y B : entrada. Vectores ya ordenados*/
I=J=K=1;
/*M Y N: nmero de elementos de A y B respectivamente*/
while ((I <= M) &&(J <= N)) { /*C : salida. Vector mezcla ordenado*/
if (A[I] <= B[J]){
/*El tipo Lista, tendr una longitud minima de M + N
elementos*/
C [K] = A[I];
I++;
}
else
{
C [K] = B[J];
J ++;
}
K++;
}
{copiar el resto del vector no agotado}
if (I > M)
for( P=J;P<=N;P++){
C [K] = B [P];
K++;
}
else
for( P=I;P< M;P++){
C [K] = A [P];
K++;
}
return 0;
}

Pag 39

Bsquedas
Bsqueda secuencial
Un problema importante en el proceso de datos, como ya se ha comentado, es la bsqueda en un
conjunto de datos de un elemento especifico y la recuperacin de alguna informacin asociada al
mismo.
La bsqueda lineal o secuencial es la tcnica ms simple para buscar un elemento en un arreglo
(vector). Consiste el mtodo en el recorrido de todo el vector, desde el primer elemento hasta el
ltimo, y de uno en uno. Si el vector contiene el elemento, el proceso devolver la posicin del
elemento buscado y en caso contrario un mensaje que indique la falta de xito en la bsqueda.
Supongamos una lista de nmeros de la seguridad Social incluidos en un arreglo a y se desea
buscar a ver si existe el nmero 453714.
Nmeros Seguridad Social

A[1}
A [2]
A [3]
A[4]
A[98]
A[99]
A[100]

451871
120467
401321
25761
-

Elemento a buscar: t
453714

339412
81467
924116

Mediante un bucle desde ir comparando el elemento t buscando con a[i], donde i vara, en el
ejemplo anterior, de 1 a 100. En caso de encontrarlo, almacenar la posicin (el indice arreglo) del
mismo dentro de la lista y finalmente se devolver al programa principal.
Pseudocdigo 1
Posicin = 0
{lista = vector a[i] de n elementos}
desde i = 1 hasta n hacer
si a[i] = t
entonces Posicin = i
fin si
fin desde
Este algoritmo tiene un inconveniente, sea cual sea el resultado se recorre el vector completo. El
algoritmo se puede mejorar con un bucle while o do_while, y utilizando unas banderas que
detecten cuando se encuentre el elemento. El bucle se terminar por dos causas:

La bandera o indicador toma el valor esperado y la bsqueda ha tenido xito.


El valor del ndice i es mayor que el nmero de trminos de la lista, lo que significa que se
ha terminado de recorrer la misma y el elemento buscado no ha aparecido.

Pseudocdigo 2

Pag 40

Encontrado = falso
Posicin = 0
i=1
mientras (i <= n) y (No Encontrado=verdadero) hacer
si a[i] = t
entonces Posicin = i
Encontrado = verdadero
Fin si
i=i+1
fin_mientras
Funcin bsqueda lineal
int BusquedaLineal (int A[]; /*entrada, vector bsqueda*/
int N ; /* entrada, nmero de elementos */
int T /*elemento a buscar*/){
int Encontrado=0,I=1,Posicion;
Posicion= 0;
/*posicin del elemento caso de no xitir*/
while (I <= N) && ! Encontrado){
if (A[I] == T ){
Posicion= I;
Encontrado = 1;
}
{fin del if y del while}
I ++;
return 0;
} {posicin del elemento en la lista
Bsqueda Binaria
La bsqueda lineal, por sus simplicidad es buena para listas de datos pequeas para listas
grandes es ineficiente, la bsqueda binaria es el mtodo idneo. Se basa en el conocido mtodo
divide y vencers.
Este mtodo tiene una clara expresin en la bsqueda de una palabra en un diccionario. Cuando
se busca una palabra no se comienza la bsqueda por la pgina 1 y se sigue secuencialmente sino
que se abre el diccionario por una pagina donde aproximadamente se piensa puede estar la
palabra, es decir se divide el diccionario en dos partes, al abrir la pgina se ve si se ha acertado o
en que parte se encuentra la palabra buscada. Se repite este proceso hasta que por divisiones o
aproximaciones sucesivas se encuentra la palabra.
Supongamos que la lista donde se busca es

Elemento buscado

1331
1373
1555
1850
1892
1898
1989
2002
2400
2670
3200

Elemento central

Pag 41

Y que se busca el nmero 1989


Se examina en primer lugar el elemento central de la lista (las divisiones se toman iguales) 1898.
Dado que 1989 es mayor que 1898, el elemento a buscar estar en la segunda mitad. Por
consiguiente, se sigue la bsqueda en esta mitad:

Elemento a buscar

1989
2002
2400
2670
3200

Elemento central

El elemento central en esta sublista es 2400, y como1989 es menor, la nueva sublista donde
buscar es

1989
2002

Elemento considerado central

como ya no hay elemento central se toma el nmero inmediatamente anterior de la posicin


central, que en este caso es 1989. En este caso se ha encontrado el elemento deseado en tres
comparaciones, mientras que en la bsqueda lineal hubiese necesitado al menos seis
comparaciones. Este mtodo es muy eficiente con el nico inconveniente, que requiere la lista
ordenada.
Algoritmo
1. Establecer Primero = 1 y Ultimo = n (n, nmero de elementos). Estas variables
representan la primera y ltima posicin de la lista o sublista donde se est buscando y
permite el calculo de la posicin del elemento central.
2. Encontrado = falso .
3. mientras Primero <= Ultimo y Encontrado = falso hacer
{Encontrar posicin central}
Central = (Primero + Ultimo) div 2
{Comparar elemento buscado t con A[Central]}
si t = a [Central]
entonces Encontrado = verdadero
sino si t > A [Central]
entonces Primero = Central + 1
sino Ultimo = Central 1
fin mientras
4. si Encontrado = verdadero
entonces Posicin = Central
{existe elemento}
si no
Posicin = 0
{no se ha encontrado}
fin_si

Pag 42

La bsqueda binaria requiere una ordenacin previa del vector o lista en el que se va ha efectuar
la bsqueda. Por consiguiente, las acciones tpicas (mdulos) en un algoritmo de bsqueda binaria
son:
1.
2.
3.
4.

Lectura del vector


Ordenacin del vector
Bsqueda binaria
Visualizar resultado

int Binaria (int T, int L[] ,int N ){


int Primero, Ultimo, Central,
Encontrado;
Primero = 1;
Ultimo = N;
Encontrado = 0 ;
while ((Primero <= Ultimo) && !Encontrado){
Central = ( Primero + Ultimo) / 2;
if (T == L [Central])
Encontrado = 1;
else
if ( T > L [Central])
Primero = Central + 1;
else
Ultimo = Central 1;
}
if (!Encontrado)
return 0;
else
return Central;
}

Estructuras de datos lineales, representaciones secuenciales.


Conceptos fundamentales: Tipo de Dato, Tipo de Dato Abstracto, Estructura de Datos,
Registros.
Concepto de estructuras de datos
Aunque los terminos tipo de datos (o simplemente <<tipo>>), <<estructura de datos>> y
<<tipo de dato abstracto>> parecen semejantes, su significado es diferente.
Una estructura de datos es una coleccin de datos organizados de un modo particular, las
estructuras de datos pueden ser de dos tipos: estructuras de datos estticas y estructuras de
datos dinmicas.
Las estructuras de datos estticas son aquellas en las que se asigna una cantidad fija de memoria
cuando se declara la variable, en numerosas ocasiones se necesitan, colecciones de datos que
crezcan y reduzcan su tamao en memoria a medida que el programa progresa, a estas
estructuras de datos cuya ocupacin en memoria puede aumentar o disminuir en tiempo de
ejecucin se denominan estructuras dinmicas de datos.
En un lenguaje de programacin, el tipo de datos de una variable es el conjunto de valores que
este puede tomar. Por ejemplo una variable de tipo booleano puede tomar los valores verdadero o
falso, pero ningn otro, los tipos de datos bsicos varian de un lenguaje a otro; en C son enteros

Pag 43

(int), real (float), y carcter (char). Las reglas para construir tipos de datos compuestos a partir
de los bsicos tambin varan de un lenguaje a otro
Un tipo de datos abstracto (TDA) es un modelo matemtico, junto con varias operaciones
definidas sobre ese modelo. Para representar el modelo matemtico bsico de un TDA se emplean
estructuras de datos, que son conjuntos de variables quiza de tipos distintos, conectadas entre si
de diversas formas.
El componente bsico de una estructura de datos es la celda. Se puede representar una celda
como una caja capaz de almacenar un valor tomado de algn tipo de datos bsico o compuesto,
las estructuras de datos se crean dando nombres a agregados de celdas
El mecanismo de agregacin ms sencillo en C y en la mayor parte de los lenguajes de
programacin es el arreglo (unidimensional), que es una sucesin de celdas de un tipo dado al
cual se llamar casi siempre <<tipo_celda>> .
Estructuras
Las estructuras son colecciones de variables relacionadas a veces denominados agregados bajo
un nombre. Las estructuras pueden contener variables de muchos tipos diferentes de datos a
diferencia de los arreglos, que contienen unicamente elemento de un mismo tipo de datos.
Generalmente las estructuras se utilizan para definir registros a almacenar en archivos.
Creacin de estructuras
Crear una estructura es definir un nuevo tipo de datos, denominado tipo estructura y declarar una
variable de este tipo. En la definicin del tipo estructura, y declarar una variable de este tipo. En
la definicin del tipo estructura, se especifican los elementos que la componen as como sus tipos.
Cada elemento de la estructura recibe el nombre de miembro (campo del registro). La sntaxis es
la siguiente:
struct tipo_estructura
{
declaraciones de los miembros
};
tipo_estructura

es un identificador que nombra el nuevo tipo definido.

Despus de definir un tipo estructura, podemos declarar una variable de ese tipo, de la forma:
struct tipo_estructura [variable[, variable]];
Para referirse a un determinado miembro de la estructura, se utiliza la notacin:
variable.miembro
Ejemplo:
struct ficha /* definicin del tipo estructura ficha */
{
char nombre[40];
char direccin[40];
long telefono;
};
La anterior definicin no reserva ningn espacio en memoria, ms bien genera un nuevo tipo de
datos, que se utiliza para declarar variables.

Pag 44

struct ficha var1, var2;


Este ejemplo define las variables var1 y var2, de tipo ficha, por lo que cada una de las variables
consta de los miembros: nombre, direccin y telfono.
Una variable que es un miembro de una estructura, puede utilizarse exactamente igual que
cualquier otra variable.
Ejemplo:
var1. Telefono = 232323;
gets(var2.nombre);
La declaracin de las variables var1 y var2, puede realizarse tambin directamente de la siguiente
forma:
struct ficha
{
char nombre[40];
char direccion[40];
long telefono;
} var1, var2;
La declaracin de un miembro de una estructura no puede contener calificadores de clase de
almacenamiento extern, static, auto o register y no puede ser inicializado. Su tipo puede ser:
fundamental, array, puntero, unin, estructura o funcin.
Los miembros de la estructura pueden ser variables de los tipos de datos bsicos, o agregados,
como son los arreglos y otras estructuras. Una estructura no puede tener una instancia de si
misma, sin embargo pudiera ser incluido un apuntador a
la estructura ( estructura
autoreferenciada).

struct card {
char false[10];
char suit[10];
}a, deck[52];
El nombre del rtulo es opcional. Si la definicin de una estructura no contiene un nombre de
rtulo e estructura, las variables de ese tipo de estructura pueden nicamente ser declaradas
dentro de la definicin de la estructura.
La nicas operaciones vlidas que pueden ejecutarse sobre estructuras son : asignar variables de
estructura a variables de estructura del mismo tipo, tomando la direccin (&) de una variable de
estructura obteniendo acceso a los miembros de una varible de estructura, y utilizando el
operador sizeof, a fin de determinar el tamao de la variable de estructura.

Como inicializar estructuras


Las estructuras pueden ser inicializadas mediante listas de inicializacin como los arreglos.
struct card a = (Three, Hearts);

Pag 45

Como tener acceso a los miembros de estructuras


Para tener acceso a miembros de estructuras se utilia el operador de miembro de estructura (.).
printf (%s, a.suit);
Cmo utilizar estructuras con funciones
Las estructuras pueden ser pasadas a funciones pasando miembros de estructuras individuales,
pasando toda la estructura o pasando un apuntador a una estructura. Cuando se pasan
estructuras o miembros individuales de estructura a una funcin se pasan en llamada por valor.
Para pasar una estructura en llamada por referencia, pase la direccin de la variable de
estructura. Los arreglos de estructura como todos los dems arreglos son automticamente
pasados en llamada por referencia.
typedef
La palabra reservada typedef proporciona un mecanismo para la creacin de sinnimos (o
alias)para tipos de datos anteriormente definidos
typedef struct card Card;
define el nuevo nombre de tipo Card como un sinnimo para el tipo struct card. Lo anterior se
puede expresar de la siguiente forma
typedef struct{
char false[10];
char suit[10];
}Card;
Card puede ser utilizado para declarar variables de tipo struct card. La declaracin
Card deck[52];
Al crear un nuevo nombre utilizando typedef no se crea un nuevo tipo; typedef simplemente crea
un nuevo nombre de tipo que puede ser utilizado como un seudnimo para un nombre de tipo
existente.

Ejemplo:
El siguiente programa lee una lista de alumnos y sus correspondientes notas de final de curso,
dando como resultado el tanto porciento de alumnos aprobados y suspendidos

#include <stdio.h>
#include <stdlib.h>
#define NA 10
main()
{
struct ficha
{
char nombre[60];
float nota;
};
struct ficha alumnos[NA]; /*arreglo de estructuras o registros */
int n =0,i;
char *fin;
/* Puntero al nombre leido*/

Pag 46

float aprobados = 0, suspensos = 0;


/*Entrada de datos*/
printf(Finalizar la entrada con cont/Z\n\n);
printf(Nombre);
fin = gets(alumnos[n].nombre);

while (n <NA && fin =NULL)


{
printf(Nota
);
scanf(%f,&alumnos[n++].nota);
printf(Nombre );
fin =gets(alumnos[n].nombre);
}
for (i =0;i<n>i++)
if (alumnos[i].nota >=5)
aprobados ++;
else
suspensos ++;
printf(Aprobados %.2g %%\n,aprobados /n*100);
printf(Suspensos %.2g %% \n,suspensos/n*100);
}

T.D.A. Lista
Modelo Matemtico
Las listas constituyen una estructura flexible en particular, por que pueden crecer y acortarse
segn se requiera, los elementos son accesibles y se pueden insertar y suprimir en cualquier
posicin de la lista, las listas tambin pueden concatenarse entre si o dividirse en sublistas; se
representan de manera rutinara en aplicaciones como manera de aplicacin.
Matemticamente, una lista es una secuencia de cero o ms elementos de un tipo determinado. A
menudo se representa una lista como una sucesin de elementos separados por comas
A1, a2, a3,.....an
Donde n 0 y cada a1 es de tipo tipo_elemento. Al nmero n de elementos se le llama longitud
de la lista. Al suponer que n 1, se dice que a1 es el primer elemento y an el ltimo elemento. Si
n = 0, se tiene una lista vaca, es decir, que no tiene elementos.
Una propiedad importante de una lista es que sus elementos pueden estar ordenados en forma
lineal de acuerdo con sus posiciones en la misma. Se dice que ai precede a ai+1 para i = 1, 2,...n1 y que ai sucede a ai-1 para i = 2, 3,...n. Se dice que el elemento ai est en la posicin i. Es
conveniente postular tambin la existencia de una posicin que sucede al ltimo elemento de la
lista. La funcin FIN(L) devolver la posicin que sigue a la posicin que sigue a la posicin n en
una lista L de n elementos. Observese que la posicin FIN(L), con respecto al principio de la lista,
est en una distancia que vara conforme la lista crece o se reduce, mientras que las demas
posiciones guardan una distancia fija con respecto al principio de la lista.
Para formar un tipo de dato abstracto a partir de la nocin matemtica de la lista, se debe de
definir un conjunto de operaciones con objetos de tipo lista.

Pag 47

Operaciones
Se representar ahora un conjunto representativo de operaciones con listas. Ah, L es una lista de
objetos de tipo tipo_elemento, x es un objeto de ese tipo y p es de tipo posicin. Observese que
<<posicin>> es otro tipo de datos cuya implantacin cambiar con aquella que se haya elegido
para las listas. Aunque de manera informal se piensa en las posiciones como enteros, en la
practica pueden tener otra representacin.

1. INSERTA(x, p, L). Esta funcin inserta x en la posicin p de la lista L, pasando los


elementos de la posicin p y siguientes a la posicin inmediata posterior. Esto quiere decir
que si L es a1,a2,...,an, se convierte en a1, a2,..., ap-1, x, ap,..., an. Si p es FIN(L)
entonces L se convierte en a1, a2,...., an, x. Si la lista L no tiene posicin p, el resultado es
indefinido.
2. LOCALIZA(x, L). Esta funcin devuelve la posicin de x en la lista L. Si x figura ms de una
vez en L, la posicin de la primera aparicin de x es la que se devuelve. Si x no figura en la
lista entonces se devuelve FIN(L).
3. RECUPERA(p, L). Esta funcin devuelve el elemento que esta en la posicin p de la lista L.
El resultado no est definido si p = FIN(L) o si L no tiene la posicin p. Obsrvese que si se
utiliza RECUPERA, los elementos deben ser de un tipo que pueda ser devuelto por una
funcin. No obstante en la practica siempre es posible modificar RECUPERA para devolver
un apuntador a un objeto de tipo elemento.
4. SUPRIME(p, L). Esta funcin elimina el elemento en la posicin p de la lista L. Si L es a1,
a2,...,an, L se convierte en a1, a2,...ap-1, ap+1,..., an. El resultado no est definido si L
no tiene posicin p o si p = FIN(L).
5. SIGUIENTE(p, L) y ANTERIOR (p,L) devuelven las posiciones siguiente y anterior,
respectivamente, a p en la lista L. Si p es la ltima posicin de L, SIGUIENTE(p, L)
=FIN(L). SIGUIENTE no esta definida si p es FIN(L). ANTERIOR no esta definida si p es 1,
ambas funciones no estan definidas cuando L no tiene posicin P.
6. ANULA(L). Esta funcin ocasiona que L se convierta en la lista vaca y devuelve la posicin
FIN(L).
7. PRIMERO(L). Esta funcin devuelve la primera posicin de la lista L. Si L est vaca, la
posicin que se devuelve es FIN(L).
8. IMPRIME_LISTA(L). Imprime los elementos de L en su orden de aparicin en la lista.

Implementacin de listas con arreglos


En la realizacin de una lista mediante arreglos, los elementos de esta se almacenan en celdas
contiguas de un arreglo. Esta representacin permite recorrer con facilidad una lista y agregarle
elementos nuevos al final, pero insertar un elemento en la mitad de la lista obliga a desplazarse
una posicin dentro del arreglo a todos los elementos que siguen al nuevo elemento para
concederle espacio. De la misma forma la eliminacin de un elemento, excepto el ltimo, requiere
desplazamientos de elementos para llenar de nuevo el vacio formado.

Pag 48

1
2

primer elemento
segundo elemento
lista

lt

ltimo elemento

vaco
Long_mx
En la realizacin con arreglos se define el tipo LISTA como un registro con dos campos, el primero
es un arreglo de elementos que tiene la longitud adecuada para contener la lista de mayor
tamao que se puede representar. El segundo campo es un entero lt que indica la posicin del
ltimo elemento de la lista en el arreglo. El i-simo elemento de la lista est en la i-sima
posicin, mediante el entero i. La funcin FIN(L) slo tiene que devolver lt +1. Las declaraciones
importantes son:
#include <stdio.h>
#include <conio.h>
# define TAM 10
# define TRUE 1
# define FALSE 0
typedef int dato;
typedef int posicion;
typedef char logico;
struct LISTA
{
dato
elem[TAM];
posicion ult;
};
typedef struct LISTA Lista;
posicion Fin(Lista &L);
void Anula(Lista &L);
void Imprime(Lista L);
posicion Ultimo(Lista &L);
logico Vacia(Lista &L);
logico Llena(Lista &L);
posicion Primero(Lista &L);
posicion Siguiente(posicion p, Lista &L);
posicion Anterior(posicion p, Lista &L);

Pag 49

void Insertar(dato x, posicion p, Lista &L);


void Suprimir(posicion p, Lista &L);
posicion Localiza(dato x, Lista &L);
dato Recupera(posicion p, Lista &L);
posicion Fin(Lista &L)
{
return (L.ult+1);
}
void Anula(Lista &L)
{
L.ult=-1;
}
posicion Ultimo(Lista &L)
{
if (L.ult >=0)
return L.ult;
else
return -1;
}
posicion Primero(Lista &L)
{
if (L.ult >=0)
return (0);
else
return -1;
}
posicion Siguiente(posicion p, Lista &L)
{
if (p>=L.ult || p< 0 )
return(-1);
else
return (++p);
}
posicion Anterior(posicion p, Lista &L)
{
if (p>L.ult || p== 0 )
return(-1);
else
return (--p);
}
logico Vacia(Lista &L)
{
if (L.ult==-1)
return 1;
else
return 0;
}
logico Llena(Lista &L)
{
if (L.ult==TAM-1)
return 1 ;

Pag 50

else
return 0;
}
void Insertar(dato x, posicion p, Lista &L)
{
posicion q;
if ( Llena(L) )
printf("Lista Llena");
else
{
if (p>Fin(L) || p< 0)
printf( "Posicion invalida");
else
{
for ( q= L.ult; q>=p; q--)
L.elem[q+1]=L.elem[q];
L.elem[p]=x;
L.ult++;
}
}
}

void Suprimir(posicion p, Lista &L)


{
posicion q;
if (Vacia(L))
printf("Lista Vacia");
else
if (p>L.ult || p< 0)
printf( "Posicion invalida");
else
{
for ( q= p; q<L.ult; q++)
L.elem[q]=L.elem[q+1];
L.ult--;
}
}
posicion Localiza(dato x, Lista &L)
{
posicion q=0;
while (q<Fin(L) && L.elem[q]!=x)
q++;
if (q==Fin(L))
return (-1);
else
return(q);
}
dato Recupera(posicion p, Lista &L)
{
if (p>L.ult || p< 0)
{
printf( "Posicion invalida");
return -1;
}

Pag 51

else
return(L.elem[p]);
}
void Imprime(Lista L)
{
posicion q;
for ( q=0; q<Fin(L); q++)
printf("%d\n",L.elem[q]);
}
void main( void )
{
Lista L;
dato x;
posicion p;
int i;
clrscr();
Anula(L);
Insertar(1,0,L);
for(i=0;i<9;i++)
{
printf("Dame el numero");
scanf("%d",&x);
Insertar(x,Primero(L),L);
}
Imprime(L);
printf("La posicion el numero");
scanf("%d",&p);
Suprimir(p,L);
clrscr();
Imprime(L);
x=Recupera(1,L);
printf("%d",x);
x=Anterior(3,L);
printf("%d",x);
x=Siguiente(5,L);
printf("%d",x);
getch();
}
Ventajas y Desventajas de la implementacin de Listas con arreglos.
La implementacin con arreglos requiere especificar el tamao mximo de una lista en tiempo de
compilacin, esto quiere decir que el tamao es fijo y no puede establecerse mientras se est
ejecutando el programa, lo cual implica conocer con exactitud la longitud de la Lista para evitar
desperdicio de memoria o bien si se estableci de un tamao mximo y al utilizarla se rebasa,
esto implicara falla del programa, en otras palabras, un arreglo es una variable esttica.
Las operaciones como INSERTA y SUPRIME requieren un tiempo proporcional al nmero de
elementos que haya que desplazar, y por lo general ests son las operaciones ms importantes.
Una ventaja es que como es bien sabido, los arreglos son estructuras de acceso directo, por lo
que las dems operaciones son triviales, as que una representacin con arreglos en un momento
dado pudiera ser de utilidad.

Pag 52

El tipo de Dato Abstracto PILA


Una pila es un tipo especial de Lista en la que todas las inserciones y supresiones tienen lugar en
un extremo denominado tope. Son estructuras LIFO (Last In First Out) o ltimo en entrar, primero
en salir en las que solo es posible quitar el elemento que se encuentra en la parte superior de la
pila (tope), son muy tiles en muchos aspectos de la programacin, tales como evaluacin de
expresiones, anidacin de parentisis, asi como en la implementacin de rutinas recursivas, entre
muchas otras aplicaciones. Una estructura de este tipo generalmente incluye las Operaciones
siguientes:
1.
2.
3.
4.
5.
6.

ANULA(P). Que convierte la pila en una Pila Vaca.


TOPE(P). Devuelve el elemento que est en el tope de la Pila.
POP(P). Suprime el elemento que est en el tope de la pila P.
PUSH(x, P). Inserta el elemento x en la parte superior de la Pila.
VACIA(P). Devuelve verdadero si la Pila est vaca y falso en caso contrario.
LLENA(P). Regresa verdadero si la Pila est llena y falso si no lo est.

Implementacin de Pilas basadas en Arreglos


Para representar una Pila con arreglos es posible hacerlo de manera similar como se hizo con las
Listas con arreglos, establecemos la Pila como un registro don dos campos, el primero un arreglo
para contener los datos de la Pila y un campo para almacenar la posicin del elemento superior de
la pila (que en lo sucesivo llamaremos tope).
#define TAM 38
typedef char tipo_elem;
typedef int logico;

struct Pila{
Tipo_elem elemento[TAM];
Int tope;
};

1
2
3
4

tope

.
.
.

TAM
Pag 53

void ANULA(Pila &P){


P.tope =TAM +1; {Creamos una Pila Vaca}
}
tipo_elem TOPE(Pila &P){
if (VACIA(P))
return TAM +1;
else
return L.elemento[P.tope];
}
void POP(Pila &P){
if (VACIA(P))
printf (Error, Pila Vaca\n);
else
P.tope++;
/*Eliminamos el elemento del tope*/
}

void PUSH(tipo_elemento x,Pila &P){


if (LLENA(P))
printf(Error, Pila Llena\n)
else {
P.tope--;
P.elemento[P.tope]=x;
}
}
int VACIA(Pila &P){
return P.tope==TAM+1;
}
int LLENA(Pila &P){
return P.tope==1;
}

Notacin Polaca
Las expresiones se componen de operandos, operadores y delimitadores. Los operandos son
valores numricos que se utilizan para calcular la expresin. Los operadores indican las
operaciones matemticas que van hacerse sobre los operandos respectivos. Tambin determinan
la cantidad de operandos necesarios para cada tipo de operacin (binarios y unarios).
Es evidente que el orden en que se calculan las operaciones puede ser muy importante, como en
la expresin 6 + 4/2. Si la resolvemos como (6+4)/2, la respuesta es 5, si lo hacemos como 6 +
(4/2), el resultado es 8.
Los operadores tienen su precedencia

Pag 54

Operador
x,/
+,-

Valor
3
2
1

Para cambiar el orden de clculo de una expresin, pueden utilizarse parntisis pero en su
ausencia las operaciones de mayor precedencia se resuelven primero. Cuando una expresin
incluye operaciones de igual precedencia, se calculan de izquierda a derecha.
La forma ms usual de representar una expresin es la forma infija, es decir, colocamos los
operadores entre sus operandos.
A + B (infija)
A B + (posfija o polaca)
La segunda forma con el operador despus del operando se conoce como notacin posfija
(polaca).
Al utilizar las reglas de precedencia de operadores, podemos convertir expresiones infijas a la
notacin polaca correspondiente, los pasos que debemos seguir son:
1. Encerrar entre parentisis toda la expresin infija.
2. Volver a colocar (mover) los operadores, uno por uno y en orden de precedencia, a su
posicin final en notacin postfija (a la derecha de sus operandos).
3. Quitar los parentisis.
Por ejemplo, vamos a convertir la expresin a + b X c a notacin polaca. El primer paso es
agregar los parntesis:
a + (bXc)
Despus se colocan los operadores en orden de precedencia, as el primero que debemos mover
es el signo de multiplicacin, X, para que la expresin resultante sea de este modo:
a + (bcX)
Los dos operandos del operador X son b y c, por lo que es fcil determinar la posicin posfija de
ese signo, pero cuales son los dos operandos del operador +?, la respuesta es a y el resultado de
la subexpresin (bXc). Y ponemos el operador + despus del parentisis de cierre:
a(bcX)+
El paso final es quitar el parntesis
abcX+
Ahora, usando parntesis, vamos a cambiar el orden del clculo de los operandos y a convertir la
expresin (a + b) X c en notacin polaca:

(a + b) X c
(a + b) X c
(ab +)X c
(ab +) c X
ab + c X

expresin infija
se aaden parntesis sin cambio
se convirti el +
se convirti el X
se elimin el parntesis

Pag 55

Recursividad
Un subprograma (procedimiento o funcin) recursivo es aquel que se llama as mismo. La
recursividad es una alternativa a la iteracin o repeticin, y aunque en tiempo de computadora y
en ocupacin de memoria es la solucin recursiva menos eficiente que la solucin iterativa,
existen numerosas situaciones en las que la recursividad es una solucin simple y natural a un
problema que en caso contrario sera difcil de resolver.
Una aplicacin importante de las pilas se da en la aplicacin de procedimientos recursivos, en los
lenguajes de programacin. La organizacin a tiempo de ejecucin de uno de tales lenguajes es el
conjunto de estructuras de datos usadas para representar los valores de las variables de un
programa durante su ejecucin. Todo lenguaje que como Pascal, permita procedimientos
recursivos, utiliza una pila de registros de activacin, para representar los valores de todas las
variables que pertenecen a cada procedimiento activo de un programa. Cuando se llama a un
procedimiento P, se coloca en la pila un nuevo registro de activacin para P, con independencia de
si ya existe en ella otro registro de activacin para ese mismo procedimiento. Cuando P vuelve, su
registro de activacin debe estar en el tope de la pila, pueso que P no puede volver si no lo han
hecho todos los procedimientos a los que P ha llamado. As, se puede sacar de la pila el registro
de activacin correspondiente a la llamada actual de P y hacer que el control regrese al punto en
el que P fue llamado (este punto, conocido como direccin de retorno, se coloc en el registro de
activacin de P al llamar a este procedimiento).
Ordenamiento Rpido (Quick Sort)
Es uno de los mtodos ms rpidos y frecuentemente utilizados en ordenacin (Quick Sort) Fue
inventado por C.H. Hoare, y la cantidad de cdigo necesario es sorprendentemente pequeo
comparando con la excelente velocidad que proporciona.
La idea bsica de la ordenacin rpida es:
Elegir un elemento de la lista denominado pivote.
Dividir o partir la lista original en dos sublistas o mitades, de modo que en una de ellas
estn todos los elementos menores que el pivote;
Las sublistas deben ser ordenadas, independientemente, del mismo modo, lo que conduce
a un algoritmo recursivo.
La eleccin del pivote es arbitraria aunque por comodidad es usual utilizar el termino central de la
lista original, o bien el primero o el ltimo elemento de la misma.
9

23

31

17

21

19

13

15

26

1. Elijamos el elemento pivote; supongamos el trmino central, 21.


9

23

31

17

//
21//

19

13

15

26

pivote
2. A continuacin se establecen dos punteros en la lista I o J. El primer puntero apunta al
primer elemento. Por consiguiente, I =1. El segundo puntero apunta al ltimo elemento y,
por lo tanto, J=9 (noveno elemento).
9

I= 1

23

31

17

//
21//

19

13

15

26

J=9

Pag 56

3. Mientras I apunte a un elemento que sea menor que 20, se incrementa el valor de I en 1,
hasta que se encuentre un elemento mayor que el pivote. A continuacin se realiza la
misma tarea con el puntero J, buscando un elemento menor que 21, y mientras no lo
encuentra se decrementa J en 1.

23

31

17

//
21//

19

13

15

26

I
J
4. Se intercambian los elementos apuntados por I y J y a continucacin se incrementan en
uno los contadores I, J.

15

31

17

//
21//

19

I
5. El proceso se repite

15

13

15

15

13

13

23

26

31

23

26

31

23

26

31

23

26

17

//
21//

I
9

13

17

17

19

J
//
21//

19

//
19//

21

6. En el momento en que J < I, se ha terminado la particin. Se han generado dos sublistas


que tienen las propiedades citadas: la primera sublista, todos los elementos menores o
iguales a 20, y en segunda todos los elementos mayores que 20.

Pag 57

Sublista Izquierda

Sublista Derecha

9
I

15

13

17

19
J

21
I

31

23

26
J

15

13

17

19

21

31

23

26

23

31

31

26

31

26

I
9

15

13

I
9

19

21

13

15

J
9

17

17

19

13

15

17

19

Sublista Izquierda II

Sublista izquierda 12

15

13

17

26

19

Sublista izquierda 1 ordenada


9

13

15

17

19

Lista Ordenada
9

13

15

17

//
19//

21

23

26

31

Pag 58

Algoritmo de Ordenacin Rpida:


1. Inicializar I a Primero (primer indice de la lista)
2. Inicializar J a Ultimo (ltimo indice en la lista)
3. Seleccionar el elemento pivote (termino Central)
Central = [(Primero + Ultimo) div 2]
4. Repetir
Mientras A[I] < Central hacer
I=I + 1
Mientras A[J] > Central hacer
J=J+1
Si I <= J entonces Intercambiar A[I],A[J] hasta que
J<I
Hasta _que I>J
5. Si J > Primero, llamar al procedimiento Partir, para dividir la sublista izquierda [Primero..J]
6. Si I < Ultimo, llamar al procedimiento Partir, para dividir la sublista derecha [J..Ultimo]
Cdigo para Quick Sort
typedef
int enteros;
enteros Lista[]
void Intercambiar(int &m,int &n ){
int Aux ;
aux =m; /*intercambiar*/
m = n;
n = aux;
}
void Partir(int primero,int ultimo,enteros Lista[] ){
int I,J, Central;
{partir}
I =primero;
J =ultimo;
//encontrar elemento pivote central
Central = lista [(primero + ultimo)div 2];
do{
while (lista[I]< central)
I++;
while (lista[J]> central)
J--;
if (I <= J){
Intercambiar(lista[I], lista[J]);
I++;
J--;
} // if
}
while (I<=J);
if (primero < J)
Partir (primero, J,Lista);
if (I<ultimo)
Partir(I, ultimo,Lista)
} { partir }
void rapido(enteros a[],int N){
Partir (l, n,a)
}

Pag 59

Torres de Hanoi
Un caso tpico de resolucin de un problema con un mtodo recursivo es el juego de nios
conocidos como torres de hanoi.

Se dispone de tres postes (1,2,3) con soportes de madera (varillas de alambre o similar) y un
juego de discos de diferentes tamaos (el nmero de ellos se leer en el programa principal) que
se situan en el primer poste, el disco de mayor tamao (dimetro) se sita en el fondo y el ms
pequeo en la parte superior. El juego consiste en mover los discos del poste 1 al poste 3 de
acuerdo a las siguientes reglas:
1. Slo un disco se puede mover a la vez.
2. Un disco nunca puede estar encima de otro disco con un dimetro ms pequeo.
3. Un disco siempre debe estar en uno de los postes (Excepto cuando se este moviendo.

Anlisis
El problema a primera vista parece sencillo, pero su solucin es francamente difcil y slo la
solucin recursiva facilita la resolucin. Tres, cuatro discos son imaginables, 64 (las leyendas citan
esta cifra como la propuesta de un rey tibetano a sus subditos, al estilo del tambin famoso
problema del tiempo necesario para llenar un tablero de ajedrez en progresin geomtrica) es
prcticamente inimaginable y casi imposible, sin solucin recursiva.

Algoritmo (3 discos)

Mover dos (3-1) discos desde el poste 1 hasta el poste 2.


Mover el disco ms grande desde el poste 1 hasta el poste 3.
Mover los dos discos desde el poste 2 hasta el poste 3 utilizando el poste 1.

Algoritmo (n discos)
Mover n-1 discos desde 1 hasta el 2 utilizando el poste 3.
Mover el disco restante desde 1 hasta el 3.
Mover la torre de n-1 discos desde el poste 3 utilizando el poste 1.

Situacin
inicial

Pag 60

Poste 1

Poste 2

Poste 3

Poste 1

Poste 2

Poste 3

Este modelo de solucin es recursivo.


#include
typedef int Poste;
typedef int Pos ;
Pos NumDiscos;

void Mover Disco (Poste Desde,Poste Hasta ){


printf (mover un disco desde el poste %d, desde);
printf(hasta el poste %d\n, hasta);
}

void MoverTorre(Pos N,Poste Uno,Poste Dos,Poste Tres){


if (N==1)
MoverDisco (Uno, Tres);
else{
MoverTorre (N 1, Uno, Tres, Dos);
MoverDisco (Uno, Tres);
Mover Torre ( N 1, Dos, Uno, Tres);
}
}
main(){
printf (Introduzca nmero de discos en juego\n);
scanf(%d,&NumDiscos);
printf(Para %d discos, NumDiscos);
printf (Los movimientos sucesivos son :\n);
MoverTorre(NumDiscos, 1, 2, 3);
}
El nmero de movimientos H(n) para una torre de n discos se calcula as:

Pag 61

H(1) =1
H(n) = 1 + 2 H(n-1)

(n>1)

Con lo que se puede deducir


H(n) = 2 E(n) 1 para n > = 1
Para una torre de 4 discos los movimientos son 15 y para una torre de 64 discos los movimientos
son inimaginables 2 E(64) 1.
Colas
Una cola es otro tipo especial de lista en el cual los elementos se insertan en un extremo (el
posterior ) y se suprimen en el otro (el anterior o frente). Las colas se conocen tambin como
listas <<FIFO>> (first-in, first out) o listas <<primero en entrar, primero en salir>>. Las
operaciones para una cola son anlogas a las de las pilas, las diferencias sustanciales consisten en
que las inserciones se hacen al final de la lista, y no al principio, y en que la terminologa
tradicional para colas y listas no es la misma. Se usarn las siguientes operaciones con colas.
Operaciones
1. ANULA( C) convierte la cola C en una lista vaca.
2. FRENTE( C) es una funcin que devuelve el valor del primer elemento de la cola C.
FRENTE( C) se puede escribir en funcin de operaciones con listas, como RECUPERA
(PRIMERO( C), C).
3. PONE_EN_COLA(x, C) inserta el elemento x al final de la cola C. En funcin de operaciones
con listas, PONE_EN_COLA(x, C) es INSERTA(x, FIN( C), C).
4. QUITA_DE_COLA( C) suprime el primer elemento de C; es decir, QUITA_DE_COLA( C) es
SUPRIME(PRIMERO( C), C).
5. VACIA( C) devuelve verdadero si, y slo si, C es una cola vaca.
Implementacin de Colas basadas en Arreglos
La representacin de colas por medio de arreglos, se le conoce como Colas Circulares. La
estructura de datos para representarlas se muestra a continuacin:
#define TAM 20
#define TRUE 1
#define FALSO 0
typedef int tipo_elem,logico;
typedef struct{
Tipo_elem elemento [TAM];
Int final, frente;
}Cola;

Pag 62

Final

Frente

En la figura se representa una cola vaca, esto sucede si anterior est en la posicin que sigue a la
posicin del posterior.
void ANULA(COLA &C){
C.Final =TAM-1;
C.Frente =1;
}
logico VACIA(COLA &C){
if ((C.final+1==C.frente) || (C.final ==TAM-1 && C.frente==0))
return (TRUE);
else
return (FALSE);
}
tipo_elemento FRENTE (COLA &C){
if (VACIA ( C))
return -1;
else
return (C.elementos[C.Frente]);
}
void PONE_EN_COLA(tipo_elem x;COLA &C){
if (LLENA( C)))
printf(la cola est llena)
else{
if (C.final==TAM-1)
C.final =0;
else
C.final++;
c.elem[C.final]=x;
}
}

Pag 63

void QUITA_DE_COLA(COLA &C){


if (VACIA ( C))
printf(la cola est vaca)
else{
if(C.frente==TAM-1)
C.frente =0;
else
C-frente++;
}
}
Concepto de apuntador
En una computadora cada posicin de memora tiene una direccin y un valor especifico
almacenado en esa posicin. Se han utilizado nombres de variables en lugar de direcciones. Para
almacenar un nuevo valor a la memoria se asigna a una variable, y la computadora enva una
direccin a la memoria seguida por el valor a almacenar en esa posicin. Con los apuntadores se
puede hacer referencia a variables por sus direcciones.
Considerese un programa que procese registros de empleados [es comn que los registros de
empleados sean muy largos; para nuestro ejemplo, supondremos que su tamao es de 2048
bytes. Supongamos que ya hemos escrito una funcin para la nmina que procesa estos registros
e imprime recibos. Una forma de suministrarle datos a nuestra funcin es pasarle cada uno de los
registros de empleados como argumento.

Estructuras autoreferenciadas
Una estructura autoreferenciada contiene un miembro de apuntador que apunta a una estructura
del mismo tipo de estructura. Por ejemplo, la definicin
struct nodo {
int dato;
struct nodo *proxPtr;
};
Define un tipo struct nodo. Una estructura del tipo struct nodo tiene dos miembros el miembro
entero dato y el miembro de apuntador proxPtr. El miembro nextPtr apunga a una estructura de
tipo struct nodo Una estructura del mismo tipo que la que se est declarando aqu, de ah el
termino estructura autorreferenciada. El miembro proxPtr se conoce como un enlace o vnculo
es decir proxPtr puede ser utilizada para vincular una estructura del tipo struct nodo con otra
estructura del mismo tipo. Las estructuras autorreferenciadas pueden ser enlazadas juntas para
formar tiles estructuras de datos como son las listas, las colas de esperas, las pilas y los rboles.

15

10

Dos estructuras autoreferenciadas enlazadas juntas


Listas implementadas con cursores
Algunos lenguajes, como FORTRAN y ALGOL, no tienen apuntadores. Si se trabaja con un
lenguaje tal, se pueden simular los apuntadores mediante cursores; esto es, con enteros que
indican posiciones en arreglos. Se crea un arreglo de registros para almacenar todas las listas de

Pag 64

elementos cuyo tipo es tipo_elemento; cada registro contiene un elemento y un entero que se usa
como curso Es decir, se define
#define TAM 10
typedef int Tipo_elem;
struct ESPACIO{
Tipo_elem Elemento;
int sig;
}Lista[TAM];
int dis,Prim;
Para la realizacin de este tipo de listas nos podemos auxiliar de una variable llamada Disponible,
que nos da la posicin del arreglo del primer disponible o vaca y en el caso de saber donde inicia
la lista hacemos uso de una variable entera que llamaremos Primero.

ESPACIO

Prim

1
2
3
4
5
6
7

Disponible

8
9

4
1
6

9
7
0
5

0
10
2

Elemento

sig

10
11

Estructuras de Datos lineales, representaciones ligadas


Teora de lista ligadas
La segunda forma de realizacin de listas, celdas enlazadas sencillas, utiliza apuntadores para
enlazar elementos consecutivos. Esta implantacin permite eludir el empleo de memoria contigua
para almacenar una lista y, por tanto, tambin elude los desplazamientos de elementos para
hacer inserciones o rellenar vacos creados por la eliminacin de elementos. No obstante, por esto
hay que pagar el precio de un espacio adicional para los apuntadores.

Pag 65

Listas con encabezado


Lista simplemente ligada
En esta representacin, una lista est formada por celdas; cada celda contiene un elemento de la
lista y un apuntador a la siguiente celda. Si la lista a1, a2, a3,...,an, la celda que contiene ai tiene
un apuntador a la celda que contiene a ai+1, para i=1,2,...,n 1. La celda que contiene an posee
un apuntador a NULL. Existe tambin una celda de encabezamiento que apunta a la celda que
contiene a1; esta celda de encabezamiento no tiene ningn elemento. En este caso hablamos de
una lista simplemente ligada con nodo de encabezamiento vaco, en la que el empleo de una celda
completa para el encabezado simplifica la implementacin de las operaciones para manipular la
lista, aunque tambin se puede utilizar el encabezado para almacenar el primer elemento y a este
tipo de representacin se le conoce como lista simplemente ligada con nodo de encabezamiento
no vaco, en la que las inserciones y supresiones al principio de la lista se manejan de manera
especial.
En el caso de una lista con encabezado vacio, el apuntador al siguiente nodo es NULL ya que no
se tienen ms celdas. La estructura de datos que emplearemos para representar una lista con
apuntadores ser un registro con dos campos, uno para guardar el elemento de la lista y otro
para mantener la direccin del siguiente nodo.
A continuacin se muestra la figura de una lista simplemente ligada lineal con nodo de
encabezamiento vaco y longitud n.

A1
encabezado

A2

An

Lista

Las operaciones ms comunes a las listas se muestran a continuacin:


typedef tipo_elemento:
struct nodo{
tipo_elemento elemento;
nodo *sig;
}
typedef nodo *Nodo;
void INICIALIZA ( Nodo Encabezado){
Encabezado =new(nodo); //Se crea el nodo de encabezado
Encabezado->sig =NULL; //Se le pone nil al campo siguiente, ya que la lista est vaca
}
{La siguiente figura muestra una lista vaca}

encabezado
Pag 66

void INSERTA (tipo_elemento x, Nodo p ){


//Coloca el elemento x delante de la celda que apuntada por p
Nodo aux;
aux= new(nodo); //Se reserva memoria para el nuevo nodo
aux-> elemento=x;
//Se almacena el elemento
aux->sig =p->sig; //Se enlaza con el siguiente nodo de p
p->sig=aux;
//p se enlaza con el nuevo nodo
}

A1

encabezado

A2

An

aux
void SUPRIME(Nodo p){ //Suprime el nodo siguiente al apuntado por p
Nodo aux;
Aux=p->sig;
//Se almacena la direccin del nodo que se desea eliminar
p->sig=aux->sig
//Se enlaza con el nodo siguiente al que se quiere suprimir
delete(aux);
//Se libera el espacio de memoria ocupada por el nodo
}

A1

encabezado

A2

An

aux

Nodo LOCALIZA(tipo_elemento x,Nodo p){


//Si encuentra el dato en la lista devuelve el apuntador al nodo anterior a donde lo encontr, //en
caso contrario regresa nil
while ((p->sig!=NULL)&&(p->sig->elemento!=x){
p=p->sig;
if (p->sig=NULL)
return NULL;
else
return p;
}
tipo_elemento RECUPERA (Nodo p){
//regresa el elemento del nodo siguiente al apuntado por p
if (!VACIA(p))
return p->sig->elemento;
else

Pag 67

printf(Error, no hay elemento);


}

int VACIA (Nodo p){


VACIA=p->sig==NULL;
}
void IMPRIME (Nodo p){
if (VACIA(p))
printf(Error, Lista Vaca);
else
while (!VACIA(p)) {
printf(%d,RECUPERA(p));
p=p->sig;
}
}
Lista simplemente ligada circular
La implementacin de una lista tambin puede hacerse mediante una lista simplemente ligada
circular, que es muy similar a la anterior, con la diferencia de que el ltimo nodo contiene en su
campo siguiente un apuntador al encabezado en lugar de NULL.
La estructura de datos que se emplea para representar este tipo de lista es la misma que para
una lista ligada lineal, y al igual que estas tambin el nodo de encabezado puede contener
informacin.

A1

encabezado

A2

An

Lista

Una desventaja de las listas lineales es que dado un apuntador p a un nodo de la lista, no se
puede tener acceso a cualquier otro nodo anterior a p. Si se recorre una lista, el apuntador al
encabezado no debe ser modificado a fin de poder hacer referencia a esta lista. Si hacemos un
pequeo cambio en la estructura de tal manera que el ltimo nodo en lugar de tener en el campo
siguiente un apuntador nulo (nil) tenga la direccin al inicio de la lista, entonces desde cualquier
otro punto de la lista es posible llegar a cualquier otro punto. En este caso la lista se llama lista
circular.
typedef int tipo_elemento
struct nodo{
Tipo_elemento Elemento;
nodo *sig;
}
typedef nodo *Nodo;
void INICIALIZA(Nodo Encabezado){
encabezado = new(nodo);

//Se crea el nodo de encabezado


//Se hace que el campo siguiente del

Pag 68

encabezado->sig = encabezado;
}

{encabezado se apunte asi mismo}

encabezado
void INSERTA (tipo_elemento x, Nodo p){
/*Coloca el elemento x delante de la celda apuntada por p es exactamente igual que una
lista lineal */
Nodo aux;
aux =new(nodo);
/*Se reserva memoria para el nuevo nodo*/
aux->elemento =x;
/*Se almacena el elemento*/
aux->sig =p^->sig;
/*Se enlaza con el siguiente nodo de p*/
p->sig = aux;
/*p se enlaza con el nuevo nodo*/
}
void SUPRIME(Nodo p){
//Suprime el nodo siguiente al apuntado por p
Nodo aux;
Aux =p->sig;
//Se almacena la direccin del nodo que se desea eliminar
p->sig =aux->sig; //Se enlaza con el nodo siguiente al que se quiere suprimir
delete(aux);
//Se libera el espacio de memoria ocupado por el nod
}

Nodo LOCALIZA(tipo_elemento x,Nodo p)


/*Si se encuentra el dato en la lista devuelve el apuntador al nodo anterior a donde lo
encontr, en caso contrario regresa nil, en este caso hay que almacenar la direccin del nodo de
encabezado para saber cuando recorrimos toda la lista*/
Nodo q;
q=p;
while (p->sig!=q) &&(p->sig->elemento!=x)
p =p->.sig;
if (p->sig==q)
return NULL;
else
return p;
}
tipo_elem RECUPERA(Nodo p){
//Regresa el elemento del nodo siguiente al apuntado por p
if (p->sig!=p)
return p->sig->elemento;
else
return -1;
}

Pag 69

int VACIA(Nodo p){


VACIA=p->sig==p
}

//Si el que sigue del nodo de encabezado, es l mismo


entonces no hay datos

void IMPRIME(Nodo p){


Nodo q;
if (VACIA(p ))
printf(Error, Lista Vaca\n);
else{
q = p;
while (p!=q->sig){
printf(%d,RECUPERA(p));
p = p->sig;
}
}
}
Ventajas de la representacin con apuntadores
Operaciones como INSERTAR Y SUPRIMIR tienen un nmero constante de pasos para este tipo de
listas, sin importar cuntos elementos contenga, a diferencia de la representacin con arreglos
que requiere un tiempo proporcional al nmero de elementos que siguen.
En la implementacin con arreglos se desperdicia espacio, independientemente de el nmero de
elementos que en realidad tiene la lista en un momento dado, mientras que la representacin con
apuntadores utiliza slo el espacio necesario para los elementos que contenga la lista en cada
momento, pero requiere espacio para almacenar el apuntador a la siguiente celda. Asi que
cualquiera de los dos mtodos podra usar ms espacio que el otro dependiendo de las
circunstancias.

Lista doblemente ligada lineal


En algunas aplicaciones puede ser deseable poder recorrer eficientemente una lista, tanto haca
adelante como hacia atrs, o dado un elemento podra determinarse con rapidez el siguiente y el
anterior. Para representar estas situaciones se emplean las listas Doblemente ligadas, en las que
cada nodo o celda de la lista adems de contener el elemento, contiene dos apuntadores, uno a la
celda siguiente y otro a la celda anterior. De la misma manera que las listas simplemente ligadas,
ests cuentan con un nodo de encabezamiento, que contiene la direccin del nodo que contiene al
primer elemento de la lista o bien este nodo de encabezamiento puede contener al primer dato.

Aun cuando una Lista Circular tiene ventajas sobre una Lista Lineal, sta todava tiene algunas
deficiencias, uno no puede recorrer esta lista en direccin contraria, ni tampoco se puede eliminar
un nodo de una lista simplemente ligada circular simplemente un apuntador a ese nodo. En el
caso de que se requieran tener estas flexibilidades la estructura de datos para representar una
lista con apuntadores es la lista doblemente ligada.
Como se mencion anteriormente, cada nodo en esta lista contiene dos apuntadores, uno es
predecesor y el otro a su sucesor. Este tipo de lista puede ser tanto lineal como circular y puede
contener o no un nodo de encabezado.

Pag 70

La estructura de datos para representar este tipo de Lista sera un nodo com un registro con tres
campos, uno para almacenar al elemento de la lista, y dos para almacenar las direcciones de los
nodos siguiente y anterior a uno dado.
Para insertar un dato hay que saber si se quiere insertar a la derecha o a la izquierda, adems de
que la insercin al principio y al final son diferentes, y sucede lo mismo para suprimir.

typedef int tipo_elem


struct nodo{
Tipo_elem elemento;
nodo *sig, *ant ;
};
typedef nodo *Nodo;
Una lista Vaca se representara de la siguiente manera:

Encabezado

nil
void INICIALIZA (Nodo Encabezado){
Encabezado =new(nodo); //Se crea el nodo de encabezado
Encabezado->sig =NULL;
Encabezado->ant =NULL;
}
{La siguiente figura muestra una lista vaca}

void INSERTA (tipo_elemento x, Nodo p ){


//Coloca el elemento x delante de la celda que apuntada por p
Nodo aux;
aux = new(nodo); //Se reserva memoria para el nuevo nodo
aux-> elemento =x; //Se almacena el elemento
aux->sig =p->sig; //Se enlaza con el siguiente nodo de p
aux->ant=p;
if (p-<sig!=NULL)
p->sig->ant =aux;
{REVISARp se enlaza con el nuevo nodo}
p->sig =aux;
}

void SUPRIME(Nodo p){


Nodo aux;
aux =p->sig->sig;

//Suprime el nodo siguiente al apuntado por p

Pag 71

delete(p->sig);
p->sig=aux;
if (p->sig!=NULL)
aux->ant=p;
}

Nodo LOCALIZA(tipo_elemento x,Nodo p){


/*Si encuentra el dato en la lista devuelve el apuntador al nodo anterior a donde lo encontr, en
caso contrario regresa nil*/
Nodo aux;
aux=p;
while (aux->sig!=NULL)&& (aux->sig->elemento!=x) {
aux =aux->sig;
if (aux->sig==NULL)
return NULL;
else
return aux;
}

tipo_elemento RECUPERA(Nodo p){


//regresa el elemento del nodo siguiente al apuntado por p
if (! VACIA(p))
return p->sig->elemento;
else
return -1;
}
int VACIA (Nodo p){
VACIA=p->sig==NULL;
}
Nodo ANTERIOR(Nodo p){
if (p->ant->ant!=NULL)
return p->ant;
else
return NULL;
}
void IMPRIME (Nodo p){
Nodo Aux;
Aux =p;
if (VACIA(p))
printf (Error, Lista Vaca\n);
else
while (!VACIA(p)) {
printf(%d,RECUPERA(p));
p=p->sig;
}
}

Pag 72

Lista doblemente ligada circular


Como se puede apreciar, este tipo de lista es similar a una lista Doblemente Ligada Lineal, pero
en esta, el primer nodo (el encabezado) en su campo anterior contiene un apuntador al ltimo
nodo de la lista, mientras que el ltimo nodo en su campo siguiente contiene la direccin del
primer nodo es decir del encabezado.

typedef int tipo_elem


struct nodo{
Tipo_elem elemento;
Nodo *sig, *ant;
}

typedef nodo *Nodo;

Encabezado

void INICIALIZA(Nodo Encabezado){


Encabezado = new(nodo);
Encabezado->ant =Encabezado;
Encabezado->sig =Encabezado;
}

//Se crea el nodo de encabezado


//Se hace que el campo siguiente del
//encabezado se apunte asi mismo

void INSERTA (tipo_elemento x, Nodo p){


/*Coloca el elemento x delante de la celda apuntada por p es exactamente igual que una lista
lineal */
Nodo aux;
aux =new(nodo);
//Se reserva memoria para el nuevo nodo
aux->elemento=x; //Se almacena el elemento
aux->ant =p;
aux->sig=p->sig; //Se enlaza con el siguiente nodo de p
if (p->sig==p)
p->ant = aux
//p se enlaza con el nuevo nodo
else
p->sig->ant =aux;
p->sig =aux;
}
void SUPRIME(Nodo p){

Pag 73

//Suprime el nodo siguiente al apuntado por p


Nodo aux;
aux=p->sig->sig;
delete (p->sig);
p->sig = aux;
aux->ant=p;
}

Nodo LOCALIZA(tipo_elemento x,Nodo p){


/*Si se encuentra el dato en la lista devuelve el apuntador al nodo anterior a donde lo encontr,
en caso contrario regresa nil, en este caso hay que almacenar la direccin del nodo de
encabezado para saber cuando recorrimos toda la lista*/
Nodo aux;
aux=p;
while ((p->sig!=aux) && (p->sig->elemento!=x)) {
p=p->sig;
if (p->sig==aux) then
return NULL;
else
return p;
}
tipo_elem RECUPERA(Nodo p){
//Regresa el elemento del nodo siguiente al apuntado por p
if (p->sig!=p)
return =p->sig->elemento;
else
return -1;
}
int VACIA(Nodo p){
return p->sig==p;
}

//Si el que sigue del nodo de encabezado, es l mismo


//

entonces no hay datos

void IMPRIME(Nodo p){


Nodo q;
if (VACIA(p ))
printf (Error, Lista Vaca);
else{
q=p;
while(p!=q->sig)
printf(%d,RECUPERA(p));
p=p->sig;
}
}
Listas sin encabezado
Lista simplemente ligada sin encabezado
typedef int tipo_elemento;
struct nodo{
tipo_elemento elemento;
nodo *sig;

Pag 74

}
typedef nodo *Nodo;
void INICIALIZA (Nodo L){
L =NULL;
}
void INSERTA (tipo_elemento x,Nodo p,Nodo L){
//Coloca el elemento x delante de la celda que apuntada por p
Nodo aux,nuevo;
if (p==NULL){
nuevo = new(nodo);
nuevo->elemento=x; //Se almacena el elemento
nuevo->sig =L; //Se enlaza con el siguiente nodo de p
L=nuevo;}
//p se enlaza con el nuevo nodo
else{
aux =L->sig;
nuevo = new(nodo);
nuevo->tipo_elemento:=x;
nuevo->sig = aux;
L->sig =Nuevo;
}
}
void SUPRIME(Nodo p,Nodo &L){
Nodo aux;
if (p==NULL) {
aux:=L->sig;
delete(L);
L=aux;
}
else
{
aux=p->sig->sig;
delete (p->sig);
p->sig =aux;
}
}

{Suprime el nodo siguiente al apuntado por p}

Nodo LOCALIZA(tipo_elemento x,Nodo L){


/*Si encuentra el dato en la lista devuelve el apuntador al nodo anterior a donde lo encontr, en
caso contrario regresa nil*/
if (L->info==x) then
LOCALIZA:=nil
else
{
while (L->sig!NULL && L->sig->elemento!=x){
L =L->sig;
if (L->sig==NULL)
return NULL;
else
return L;
}
tipo_elemento RECUPERA (Nodo p){

Pag 75

//regresa el elemento del nodo siguiente al apuntado por p


if (!VACIA(p))
return p->sig->elemento;
else
printf(Error, no hay elemento);
}
int VACIA (Nodo p){
return L==NULL;
}
void IMPRIME (Nodo p){
while (L!=NULL){
printf(%d,L->elemento);
L=L->sig;
}
}
void ANULA (Nodo L){
Nodo aux;
while (L!= NULL){
aux=L->sig;
delete (L);
L=aux;
}
}
Implementacion de Pilas basadas en apuntadores
La representacin de pilas basadas en apuntadores es similar a la de una lista simplemente ligada
lineal, en donde el encabezado es el topo de la pila, y las inserciones y supresiones siempre se
hacen en el tope (encabezado).
typedef char tipo_elem;
struct Nodo{
Tipo_elem elemento;
Nodo *sig;
};
typedef Nodo *posicion;
typedef int logico;

void INICIALIZA (posicin P){


P = new Nodo;
P ->sig=NULL
}
logico PILA_VACIA(posicion P){
if (P=nil)
return 1;
else
return 0;
}
void METER(tipo elem x; posicion p){
posicion aux;

Pag 76

aux = new(Nodo);
aux->elemento=x;
aux->sig:=P->sig;
P ->sig = aux;
}
void SACAR(posicin P){
posicion Aux:;
if (!PILA_VACIA(P)) {
Aux=P->sig;
P->sig =Aux->sig;
delete(Aux);
}
else
printf(Pila vaca\n);
}
elemento TOPE(posicion P){
if (PILA_VACIA (P))
return -1;
else
return P->sig->elemento;
}
Implementacion de Colas basadas en apuntadores
typedef char tipo_elem;
struct nodo{
Tipo_elem elemento;
nodo *sig;
};
typedef nodo *Nodo;
typedef int logico;
struct Cola{
Nodo Fondo,Frente;
}

void INICIALIZA (Cola C){


C.Frente=NULL;
C.Fondo=NULL;
}
int VACIA(Cola C){
if (C.Frente=NULL)
return 1;
else
return 0;
}
void METER (elemento x;Cola C);
Nodo Aux;
Aux =new(Nodo);
Aux->elemento =x;

Pag 77

Aux->sig =NULL;
if (C.Fondo!=NULL) {
C.Fondo->sig =Aux;
C.Fondo =Aux;
}
else{
C.Frente =Aux;
C.Fondo =Aux;
}
}
void SACAR (Cola C){
Nodo Aux:;
if (! VACIA( C)) {
Aux:=C.Frente;
C.Frente =Aux->.sig;
delete(aux);
}
else
printf(lista vaca);
}

elemento PRIMERO (Cola C){


if (!VACIA( C))
return C.Frente->elemento;
else
return -1;
}
elemento ULTIMO (Cola C){
if (!VACIA( C))
return C.Fondo->elemento;
else
return -1;
}

Estructura de datos no lineales, representaciones secuencial y ligada


Teora general de rboles
Un rbol impone una estructura jerrquica sobre una coleccin de objetos. Los rboles
genealgicos y los organigramas son ejemplos comunes de rboles. Entre otras aplicaciones, los
rboles se emplean para analizar circuitos elctricos y para representar la estructura de frmulas
matemticas, as como para organizar la informacin de bases de datos y para representar la
estructura sintctica de un programa fuente en compiladores. A continuacin se representan las
definiciones bsicas y algunas de las operaciones ms comunes con rboles y veremos como esta
estructura de datos puede ser representada en Pascal.
rboles binarios
rbol Binario
Un rbol binario es un conjunto finito de elementos que puede estar vaco o contener un elemento
denominado la raiz del rbol, esta raz contiene cuando mucho un subrbol izquierdo y ubrbol
derecho; los cuales a su vez tambin son rboles binarios. A cada elemento de un rbol binario se
le denomina Nodo del rbol.

Pag 78

Formalmente, un rbol se puede definir de manera recursiva como sigue:


1. Un nodo es, por si mismo, un rbol. Ese nodo es tambin la raz de dicho rbol.
2. Supongamos que n es un nodo y que A1, A2,...Ak son rboles con races n1,n2,...nk,
respectivamente. Se puede construir un nuevo rbol haciendo que n se convierta en el
padre de los nodos n1,n2,..., nk. En dicho rbol, n es la ras y A1,A2,..,Ak son los
subrboles de la raz. Los nodos n1,n2,....nk reciben el nombre de hijos del nodo n.

raz

Subrbol
izquierdo

Subrbol
derecho

Una forma de visualizar un rbol binario es considerar cada nodo conformado por tres campos
fundamentales, uno para almacenar la informacin que contiene el nodo, y dos para almacenar la
direccin del subrbol izquierdo y derecho. Si el subrbol izquierdo o derecho est vaco, contiene
un apuntador nulo o nil.

Arboles binarios de bsqueda


Los rboles binarios pueden ser implementados como un arreglo o mediante el uso de
apuntadores. Como caso particular representaremos la implementacin con apuntadores de un
rbol Binario de bsqueda. Este tipo especial de rbol tiene como caracterstica la siguiente: Para
cada nodo, todos los elementos que estn a su izquierda son menores que l y todos los
elementos que estn a su derecha son mayores, y esta definicin es recursiva.

Pag 79

Representacin ligada
typedef int tipo_elemento;
struct nodo{
Tipo_elemento Info;
Nodo *Izq, *Der
}
typedef nodo *Nodo;
void INICIALIZA( Nodo R){
R = NULL;
}
void INSERTA(tipo_elemento x,Nodo R){
If (R==NULL){
R= new(nodo);
R->info =x;
R->Izq =NULL;
R->Der =NULL;
}
else
if (x>R->info)
{Si el dato a insertar es mayor}
INSERTA(x, R->Der)
{Se revisa el lado derecho}
else
if (x<R->Info)
INSERTA(x,R->Izq);
}

Nodo BUSCAR (Info x,Nodo R){


Nodo P;
P=Raiz;
if ((P==NULL) || (x=P->Info))
return P;
else
if (x<P->Info)
return BUSCAR(x,P->Izq);
else
return BUSCAR(x,P->Der);
}
Info MXIMO (Nodo P){
while (P->Der !=NULL)
P =P->Der;
return P-> Info;
printf(%d,P->info);
}
Info MINIMO (Nodo P){
while (P->Izq !=NULL)
P=P->Izq;
return P-> Info;
printf(P->Info);
}

Pag 80

Representaciones secuenciales
Una forma conveniente de estructurar datos para representar un rbol binario consiste en dar a
sus nodos los nombres 1, 2, ...,n y utilizar un arreglo de registros declarado como:
Struct Nodo{
int Hijo_izq;
int Hijo_der;
}Espacio_celdas[TAM_NODOS];
La idea es que espacio_celdas[i]. Hijo_izq sea el hijo izquierdo del nodo i, y que suceda lo mismo
con hijo_der. Un valor 0 en cualquiera de esos campos indicar la ausencia de un hijo
Recorridos En-Orden, Pre-Orden y Post-Orden
Existen tres mtodos de recorrer todos los nodos de un rbol, todos ellos sern definidos de
manera recursiva, de tal manera que el recorrer un rbol binario comprende la visita a la raz y el
recorrido de los subrboles izquierdo y derecho. La nica diferencia entre estos mtodos es el
orden en que se realizan estas operaciones.
Recorrido en Preorden u Orden Previo
1. Visitar la raz
2. Recorrer el subrbol izquierdo en Preorden
3. Recorrer el subrbol derecho en Preorden
Recorrido en Entreorden u Orden Simtrico
1. Recorrer el subrbol izquierdo en Entreorden
2. Visitar la raz
3. Recorrer el subrbol derecho en Entreorden
Recorrido en Postorden u Orden Posterior
1. Recorrer el subrbol izquierdo en Postorden
2. Recorrer el subrbol derecho en Postorden
3. Visitar la raz
typedef int tipo_elemento;
struct nodo{
Tipo_elemento Info;
Nodo *Izq, *Der;
}
typedef nodo *Nodo;
void PREORDEN(Nodo R)
if (R!=NULL){
printf(%d,R->info);
PREORDEN(R->izq);
PREORDEN(R->der);
}
}
void ENTREORDEN (Nodo R){
if (R!=NULL) {
ENTREORDEN(R->Izq);
printf(%d,R->Info);
ENTREORDEN(R->Der);

//Visitamos la raz
//Recorremos el subrbol izquierdo
//Recorremos el subrbol derecho

//Recorremos el subrbol izquierdo


//Visitamos la raz
//Recorremos el subrbol derecho

Pag 81

}
}
void POSTORDEN(Nodo R){
if (R =! NULL){
POSTORDEN(R->Izq);
POSTORDEN(R->Der);
pirntf(%d,P->info);
}
}

Grafos
En los problemas originados en la computacin, matemticas, ingeniera y muchas otras
disciplinas, a menudo es necesario representar relaciones arbitrarias entre objetos de datos. Los
grafos los grafos dirigos y los no dirigos son modelos naturales de tales relaciones
Grafo dirigido
Un grafo dirigido G consiste en un conjunto de vrtices V y un conjunto de arcos A. Los vrtices se
denominan tambin nodos o puntos; los arcos pueden llamarse arcos dirigidos o lineas dirigidas.
Un arco es un par ordenado de vrtces (v, w); y es la cola y w la cabeza del arco. El arco (v, w)
se expresa a menudo como v w va de v a w, y que w es adyacente a v.
Los vrtices de un grafo dirido pueden usarse para representar objetos, y los arcos relacionados
ente los objetos. Por ejemplo, los vrtices pueden representar ciudades y los arcos, vuelos areos
de de una ciudad a otra. Un grafo dirigo puede emplearse para representar el flujo de control en
un programa de computador. Los vrtces representan bloques bsicos, y los arcos posibles
tranasferencias del flujo de control.
Un camino en un grafo dirigo es una secuencia de vrtices v1, v2, ...vn, tal que v1 v2,
v2 v3,.....vn-1 vn.son arcos. Este camino va del vrtices v1 al vrtice vn, pasa por los vrtices
v2, v3,...vn-1 y termina en el vrtice vn. La longitud de un camino es el nmero de arcos en ese
camino, en este caso n-1. Como caso especial, un vrtice sencillo, v, por si mismo denota un
camino de longitud cero de v a v. En la figura la secuencia 1, 2, 4, es un camino de longitud 2 que
va del vrtice 1 al vrtice 4.

Grafo dirigido

Pag 82

Un camino es simple si todos los vrtices, excepto tal vez el primero y el ltimo, son distintos. Un
ciclo simple es un camino simple de longitud por lo menos uno, que empieza y termina en el
mismo vrtice. En la figura, el camino 3, 2, 4, 3 es un ciclo de longitud 3.
En muchas aplicaciones es til asociar informacin a los vrtices y arcos de un grafo dirigido. Para
este propsito es posible usar un grafo dirigido etiquetado, en el cual cada arco, cada vrtice o
ambos pueden tener una etiqueta asociada. Una etiqueta puede ser un nombre, un costo o un
valor de cualquier tipo de datos dado.
La siguiente figura muestra un grafo dirigido etiquetado en el que cada arco esta etiquetado con
una letra que causa una transicin de un vrtice a otro. Este grafo dirigido etiquetado tiene la
interesante propiedad de que las etiquetas de los arcos de cualquier ciclo que sale del vrtice 1 y
vuelve e l producen una cadena de caminos a y b en el cual los nmeros de a y de b son pares.
Un grafo dirido etiquetado, un vrtice puede tener a la vez un nombre y una etiqueta. A menudo
se emplear la etiqueta del vrtice como si fuera el nombre. As, los nmeros de la figura pueden
interpretarse como nombres o como etiquetas de vrtices.

a
1

2
a

a
3

Representacin de grafos dirigidos


Para representar un grafo dirigido se pueden emplear varias estructuras de datos; la seleccin
apropiada depende de las operaciones que se aplicarn a los vrtices y a los arcos del grafo. Una
representacin comn para un grafo dirido es G= (V,A) es la matriz de adyacencia. Supngase
que V= {1,2,...,n}.La matriz de adyacencia para G es una matriz una matriz A de dimensin n X
n, de elementos bolanos, donde A[i, j] es verdadero si, y slo si, existe un arco que vaya del
vrtice i al j. Con frecuencia se exhibirn matrices de adyacencias con 1 para verdadero y 0 para
falso.; las matrices de adyacencia pueden incluso obtenerse de esa forma. En la representacin
con una matriz de adyacencia, el tiempo de acceso requerido a un elemento es independiente del
tamao de V y A. As la representacin con matriz de adyacencia es til en algoritmos para grafos,
en los cuales suele ser necesario saber si un arco dado est presente.
Algo muy relacionado con esto es la representacin con matriz de adyacencia etiquetada de un
grafo dirido, donde a[i,j] es la etiqueta del arco que va del vrtice i al vrtice j. Si no existe un
arco de i a j, debe emplearse como entrada para A[i,j] un valor que no pueda ser una etiqueta
vlida.

Pag 83

1
1
2

4
B

3
4

b
b

Matriz de adyacencia etiquetada para el grafo dirigido de la anterior figura.


La principal desventaja de usar una matriz de adyacencia para representar un grafo dirido es que
requiere un espacio (n) aun si el grafo dirido tiene menos de n arcos. Slo leer o examinar la
matriz puede llevar un tiempo O(n), lo cual invalidara los algoritmos O(n) para la manipulacin
de grafos dirigidos con O(n) arcos.
Para evitar esta desventaja se puede utilizar otra representacin comn para un grafo dirigido
G=(V,A) llamada representacin con lista de adyacencia. La lista de adyacencia para un vrtice i
es una lista, en algn orden, de todos los vrtices adyacentes a i. Se puede representar G por
medio de un arreglo CABEZA, donde CABEZA[i] es un apuntador a la lista de adyacencia del
vrtice i. La representacin con lista de adyacencia de un grafo dirigido requiere un espacio
proporcional a la suma del nmero de vrtices ms el nmero de arcos; se usa bastante cuando el
nmero de arcos es mucho menor que n . Sin embargo, una desventaja potencial de la
representacin con lista de adyacencia es que puede llaeva un tiempo O(n) determinar si existe
un arco del vrtice i al vrtice j, ya que puede haber O(n) vrtices en la lista de adyacencia para
el vrtice i.
La figura muestra una representacin con lista de adyacencia para el grafo dirigido de la primera
figura, donde se usan listas enlazadas sencillas. Si los arcos tienen etiquetas, stas podran
incluirse en las celdas e la lista ligada.

Si hubo inserciones y supresiones en las listas de adyacencias, sera preferible tener el arreglo
CABEZA apuntando a celdas de encabezamiento que no contienen vrtices adyacentes. Por otra
parte, si se espera que el grafo permanezca fijo, sin cambios (o con muy pocos) en las listas de
adyacencia, sera preferible que CABEZA[i] fuera un cursor a un arreglo ADY, donde
ADY[CABEZAA[i]], ADY[CABEZA[i]+1], ..., y as sucesivamente, contuvieran los vrtices
adyacentes al vrtice i, hasta el punto en ADY donde se encuentra por primera vez un cero, el
cual marca el fin de la lista de vrtices adyacentes a i.

Pag 84

Grafos no dirigidos
Un grafo no dirigido G =(V,A) consta de un conjunto finito de vrtices V y de un conjunto de
aristas A. Se diferencia de un grafo dirigido en que cada arista en A es un par no ordenado de
vrtices. Si (v,w) es una arista no dirigida, entonces (v,w) =(w,v).
Los grafos se emplean en distintas disciplinas para modelar relaciones simtricas entre objetos.
Los objetos se representan por los vrtices del grafo, y dos objetos estn conectados por una
arista si estn relacionados entre s.

El siguiente programa pone de manifiesto el uso de operadores de miembro de estructura y de


apuntador de estructura.

#include <stdio.h>
struct card {
char *face;
char *suit;
};
main()
{
struct card a;
struct card *aPtr;
a.face = Ace;
a.suit = Spades;
aPtr = &a;
printf(%s%s%s\n%s%s%s\n%s%s%s\n,a.face, of , a.suit, aPtr->face,
of, aPtr->suit, (*aPtr).face, of, (*aPtr).suit);
return 0;
}

Ace of Spades
Ace of Spades
Ace of Spades

Pag 85

También podría gustarte