Académique Documents
Professionnel Documents
Culture Documents
DATOS
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 1
TEMA 1.
Introduccin a la programacin.
1.1. CONCEPTOS BSICOS.
Un programa es un conjunto ordenado de instrucciones, que se aloja en la memoria
del ordenador. Estas instrucciones operan sobre datos, normalmente (aunque no
necesariamente) procedentes del mundo exterior a dicha memoria: usuarios, dispositivos de
almacenamiento (electrnicos, magnticos, pticos, etc), redes de comunicaciones, etc, para
producir resultados tanto en forma de acciones como de nuevos datos (informacin).
Acciones
Datos
ORDENADOR
(memoria)
Resultados
PROGRAMA
Informacin
2 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
Ordenador
TRADUCTOR
Programa
ejecutable
Por el contrario, sera la tcnica ms eficiente (mayor velocidad de ejecucin y menor consumo de
memoria). No obstante, y como consecuencia de la incesante mejora y abaratamiento de la tecnologa, esta
alternativa no ha sido nunca tomada en consideracin.
2
Difcilmente se podr encontrar otra actividad ms viva que el desarrollo de lenguajes de programacin:
en tan solo cincuenta aos de existencia de los ordenadores y de la Informtica algunos autores llegan a
identificar en torno a medio millar de ellos. Se puede encontrar una referencia en:
http://www.lenguajesdeprogramacion.com/
3
Se trata de un modelo muy elemental. La realidad es algo ms compleja.
4
Existen otras soluciones intermedias.
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 3
4 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
o protected: tienen acceso las clases del resto del paquete, as como desde
subclases definidas fuera del paquete.
o public: se puede acceder desde cualquier otra clase.
1.1.1.4. Excepciones.
Las excepciones son elementos que almacenan informacin para detectar hechos
excepcionales, como por ejemplo errores. En Java existen muchos tipos de excepciones
estndar y las ms habituales son del tipo IOException (errores de lectura), as como del
tipo NumberFormatException (que se genera cuando se espera leer un nmero y se recibe
algo diferente).
1.1.2. Entorno de programacin (IDE).
Para realizar la actividad de programacin se requiere, adems del correspondiente
programa traductor (compilador o intrprete), un conjunto de herramientas (software
development tools) que proporcionan funcionalidades tales como escribir / modificar
(editar) el cdigo fuente, facilitar la puesta a punto de programas (debugger), cargar
(load), montar (link) y ejecutar (run) programas, gestionar ficheros con cdigo fuente y
ejecutable, etc. Normalmente estas herramientas se ofrecen en forma de paquete integrado
(Integrated Development Environment IDE-). Uno de ellos, de libre distribucin para
programacin en Java es Eclipse (http://www.eclipse.org, donde adems de descargar la
aplicacin, se pueden encontrar distintos recursos como por ejemplo tutoriales para
aprender el manejo del entorno).
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 5
Explicacin
Lnea de comentario.
Se indica el nombre del programa.
Delimitador de inicio del programa.
Clase principal
Delimitador de inicio de la clase
Ejemplo de accin: sentencia println (escribir en el dispositivo
de salida system.out y avanzar al comienzo de la lnea
siguiente) que acta sobre un sujeto (dato): la cadena de
caracteres Hola EUI.
Delimitador de fin de clase.
Delimitador de fin de programa.
Semntica
import <nombre>;
public class <nombre de la clase general>
{
6 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 7
El concepto tipo de datos se asocia implcitamente al los datos elementales (simples). Ms adelante
(apartado 1.4) se contemplar la posibilidad de agrupar datos simples en unidades de orden superior para dar
lugar a diferentes estructuras de datos.
9
Las operaciones con ms de dos operandos las consideramos dentro del epgrafe de expresiones.
8 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
Tipo
Operacin
Operador
Entero (int)
Suma
Resta
Multiplicacin
Cociente
Resto
Suma
Resta
Multiplicacin
Divisin
Negacin
Unin (or)
Interseccin (and)
No existen
Concatenacin
+
*
/
%
+
*
/
!
||
&&
Ejemplo
Operacin
3+5
1-3
2 * (-5)
7/3
7%3
1,23 + 8,77
1,23 - 8,77
-3,2 * 4,6
3,2 / (-4,6)
! true
true || false
true && false
Hola + Antonio
Real (float)
Lgico (boolean)
Carcter (char)
Cadena (String)
Resultado
8
-2
-10
2
1
10,0
-7,54
-14,72
-0,6956
false
true
false
10
Hola Antonio
Operador
>
<
==
>=
<=
!=
Result.
true
false
false
true
true
false
Result.
false
12
true
false
true
true
true
10
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 9
14
Adems de las componentes (clases) proporcionadas por el fabricante (en este caso Eclipse) el
programador puede incorporar otras de desarrollo propio (ver tema 2: Tipos Abstractos de Datos) o
adquiridas a terceros.
10 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
1.2.3.2.3. Expresiones.
Una expresin es una combinacin (coherente) de datos (literales, constantes y/o
variables), operaciones y funciones, enlazados entre s por medio de operadores.
Como consecuencia de evaluar una expresin, siguiendo las reglas
correspondientes, se obtiene un resultado de tipo acorde con la naturaleza de la expresin.
1.2.4. Sentencias.
Las sentencias son construcciones sintcticas que indican al ordenador qu
operaciones debe realizar y, normalmente, con qu datos. Materializan la parte operativa
de un programa que implementa el algoritmo (definicin de Wirth, 1985) que se deber
ejecutar15. Dicha parte constituye un bloque delimitado por { y }.
Se describe a continuacin, la sintaxis de las sentencia de Java, agrupadas en funcin
de su naturaleza.
1.2.4.1. Asignacin.
Permite, como su propio nombre indica, asignar un valor a una variable (ver 1.2.2)
definida en la parte declarativa. Su sintaxis es:
16
Ejemplo (HolaEui2.Java):
//Ejemplo de asignacion a variables.
public class HolaEui2 {
public static void main (String [ ] args) {
String cadena = "Hola EUI";
System.out.println (cadena);
}
}
15
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 11
cadena = linea.readLine();
.
n = Integer.parseInt (linea.readLine());
.
12 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
import java.io.*;
//Ejemplo de sentencias de entrada/salida.
public class HolaEui3 {
public static void main(String [] args) throws
NumberFormatException,IOException{
String cadena, cadena2;
int edad, ao = 2010;
BufferedReader linea=new BufferedReader (new InputStreamReader (System.in));
System.out.println ("Hola, como te llamas? ");
cadena = linea.readLine();
System.out.println ("Encantado de conocerte, " + cadena);
System.out.println ("Cuantos aos tienes? ");
edad = Integer.parseInt (linea.readLine());
edad = edad+3;
ao = ao+3;
cadena2 = cadena+", en algun momento de "+ao+" tendrs "+edad+" aos";
System.out.println (cadena2);
System.out.println (cadena);
}
}
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 13
Ejemplo:
El siguiente programa informa al usuario de la paridad de un nmero entero
introducido por el teclado.
import java.io.*;
//Ejemplo de alternativa simple.
public class PruebaIf {
public static void main (String [] args) throws NumberFormatException,
IOException {
int dato;
BufferedReader linea=new BufferedReader (new InputStreamReader (System.in));
System.out.print("Numero: ");
dato = Integer.parseInt (linea.readLine());
if ((dato % 2) == 0)
System.out.println (" es par");
else System.out.println (" es impar");
}
}
Operador condicional
El operador condicional ?: se puede usar como abreviatura de la sentencia if, cuya
sintaxis es:
expresionCondicional ? expresionSI : expresionNO;
18
14 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
Ejemplo:
El programa siguiente espera recibir desde el teclado un dgito, entre 1 y 7,
correspondiente al ordinal del da de la semana (lunes a domingo) y mostrar por la
pantalla el literal del da asociado o un mensaje de error si el cdigo no es vlido.
import java.io.*;
//Ejemplo de alternativa multiple.
public class PruebaSwitch {
public static void main (String [ ] args) throws NumberFormatException,
IOException {
BufferedReader linea = new BufferedReader (new InputStreamReader
(System.in));
System.out.print ("Opcion: ");
int opc = Integer.parseInt (linea.readLine ());
switch (opc) {
case 1: System.out.println ("lunes");
break;
case 2: System.out.println ("martes");
break;
case 3: System.out.println ("miercoles");
break;
case 4: System.out.println ("jueves");
break;
case 5: System.out.println ("viernes");
break;
case 6: System.out.println ("sabado");
break;
case 7: System.out.println ("domingo");
break;
default: System.out.println ("opcion no valida");
break;
}
}
}
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 15
Ejemplo:
El siguiente programa muestra por la pantalla el valor de los cuadrados de 5
nmeros introducidos por el teclado.
import java.io.*;
//Ejemplo de bucle for.
public class PruebaFor {
public static void main(String[] args) throws NumberFormatException,IOException{
int i, dato, cuadrado;
BufferedReader linea = new BufferedReader (new InputStreamReader (System.in));
for (i = 1; i <= 5; i ++) {
System.out.print ("Numero: ");
dato = Integer.parseInt (linea.readLine ());
cuadrado = dato * dato;
System.out.println ("El cuadrado de " + dato + " es: " + cuadrado);
}
}
}
19
En consecuencia, podra ser que el bloque de cdigo pudiera no ejecutarse ninguna vez.
16 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
Ejemplo:
El siguiente programa ejecuta reiteradamente el ejemplo de los das de la
semana, salvo que el usuario teclee 0 como opcin20.
import java.io.*;
//Ejemplo de bucle while.
public class PruebaWhile {
public static void main (String [] args) throws NumberFormatException,
IOException {
int opc;
BufferedReader linea = new BufferedReader (new InputStreamReader
(System.in));
System.out.print ("Opcin: ");
opc = Integer.parseInt (linea.readLine());
while (opc != 0) {
switch (opc) {
case 1: System.out.println ("lunes");
break;
case 2: System.out.println ("martes");
break;
case 3: System.out.println ("miercoles");
break;
case 4: System.out.println ("jueves");
break;
case 5: System.out.println ("viernes");
break;
case 6: System.out.println ("sabado");
break;
case 7: System.out.println ("domingo");
break;
default: System.out.println ("opcin no valida");
break;
}
System.out.print ("Opcin: ");
opc = Integer.parseInt (linea.readLine ());
}
}
}
<grupo de sentencias;>
(<condicin>);
20
21
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 17
Ejemplo:
El programa siguiente constituye una variante del ejemplo anterior en el que
el bloque de cdigo se ejecuta una vez y volver a repetirse reiteradamente, o
no, hasta que el usuario teclee 0 como opcin22.
import java.io.*;
//Ejemplo de bucle do ... while.
public class PruebaDoWhile {
public static void main (String [] args) throws NumberFormatException,
IOException {
int opc = 7;
BufferedReader linea=new BufferedReader (new InputStreamReader (System.in));
System.out.println("Empezamos en domingo");
do {
switch (opc) {
case 1: System.out.println ("lunes");
break;
case 2: System.out.println ("martes");
break;
case 3: System.out.println ("miercoles");
break;
case 4: System.out.println ("jueves");
break;
case 5: System.out.println ("viernes");
break;
case 6: System.out.println ("sabado");
break;
case 7: System.out.println ("domingo");
break;
default: System.out.println ("opcin no valida");
break;
};
System.out.print ("Opcin: ");
opc = Integer.parseInt (linea.readLine ());
} while (opc != 0);
}
}
22
18 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
23
Internet es una fuente casi inagotable donde obtener este tipo de recursos.
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 19
Zona de
algoritmo
Subprograma (mdulo)
Zona de datos
>
<retorno
Zona de
algoritmo
---------------------
<Llamada>
---------------------
Programa principal
24
20 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
27
Lo que se explica en el apartado debe entenderse con carcter general. El lenguaje Java solo
admite el paso de argumentos por valor. Esta afirmacin es extensiva al caso de que el argumento sea un
objeto (por ejemplo, un vector) dado que lo que se pasa como argumento por valor es un puntero (referencia)
a dicho objeto que no puede ser modificado por el mdulo subordinado (aunque s el propio objeto).
28
No hay ningn inconveniente en que dos variables locales de mdulos diferentes tengan el mismo
nombre.
29
Una modificacin de una variable global realizada por un mdulo afectar al resto.
30
En este caso si habra ambigedad en caso de coincidencia de nombres de una variable local y otra
global. Esto no supone ningn error de compilacin y la ejecucin podra producir resultados no esperados (ni
deseados).
31
No tiene sentido pasar como argumentos variables globales. Ya estn accesibles desde todos los
mdulos.
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 21
Los nombres de los argumentos son formales. No tienen por qu coincidir con los
nombres reales de las variables utilizadas en la llamada al mtodo32. El compilador solo
verifica que las listas de argumentos empleadas en la llamada (reales) y en la cabecera
(formales) coinciden en nmero, tipo y orden.
Las sintaxis de las llamadas es similar a la de las cabeceras, si bien en este caso se
utiliza una versin reducida de la <lista de argumentos> en la que solo aparecen sus
nombres (reales), separados por comas.
El mtodo est delimitado por las llaves de inicio y fin de bloque ({ y }), y a
continuacin aparece la declaracin de variables locales del subprograma y el algoritmo.
Los mtodos que no sean de tipo void deben acabar con la siguiente sentencia:
return <variableDeTrabajo>;
32
22 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
Dado que el lenguaje Java solo admite el paso de argumentos por valor no es posible
que el modulo subordinado modifique una variable del mdulo de llamada (salvo que se
trate del valor devuelto por el mtodo). En tales situaciones optamos por crear una clase
esttica que declare dicha variable como global de la clase (lo que no contraviene la
recomendacin general de no utilizar variables globales)33 por lo que carecera de sentido
pasarla como argumento.
Como consecuencia de la utilizacin de la tcnica de subprogramacin, el esquema de
estructura general de un programa en Java visto en la seccin 1.2.1 queda ampliado tal
como se muestra a continuacin.
Sintaxis
import <nombre>
public class <nombre de la clase general>
{
Semntica
Llamada a una (o varias) componente(s) de la biblioteca.
Nombre de la clase general (obligatorio)
Principio de la clase.
{
<constantes y variables del mtodo>
....
......
public static void main (String [ ] args)
{
33
Algunos programadores optan por la alternativa de declarar dicha variable como vector (objeto) y pasar el
puntero (referencia) correspondiente como argumento (por valor).
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 23
1.3.4.1. Ejemplo.
El siguiente programa pide al usuario una serie de cinco nmeros enteros y muestra
por la pantalla dos de sus estadsticas: valor medio y rango.
import java.io.*;
public class PruebaMetodos {
static float media (int dato1, int dato2, int dato3, int dato4, int dato5) {
float resul;
resul = (dato1 + dato2 + dato3 + dato4 + dato5) / 5;
return resul;
}
static int max (int dato1, int dato2, int dato3, int dato4, int dato5) {
int resul;
resul=dato1;
if (dato2 > resul)
resul = dato2;
if (dato3 > resul)
resul = dato3;
if (dato4 > resul)
resul = dato4;
if (dato5 > resul)
resul = dato5;
return resul;
}
static int min (int dato1, int dato2, int dato3, int dato4, int dato5) {
int resul;
resul = dato1;
if (dato2 < resul)
resul = dato2;
if (dato3 < resul)
resul = dato3;
if (dato4 < resul)
resul = dato4;
if (dato5 < resul)
resul = dato5;
return resul;
}
public static void main(String[] args) throws NumberFormatException,IOException{
int d1, d2, d3, d4, d5, rango;
float media;
BufferedReader linea = new BufferedReader(new InputStreamReader(System.in));
System.out.println ("Introduce cinco nmeros enteros: ");
d1 = Integer.parseInt (linea.readLine ());
d2 = Integer.parseInt (linea.readLine ());
d3 = Integer.parseInt (linea.readLine ());
d4 = Integer.parseInt (linea.readLine ());
d5 = Integer.parseInt (linea.readLine ());
media = media (d1, d2, d3, d4, d5);
System.out.println("El valor medio es: " + media);
rango = max (d1, d2, d3, d4, d5) - min (d1, d2, d3, d4, d5);
System.out.println ("y el rango: " + rango);
}
}
24 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
1.3.5. Recursividad.
1.3.5.1. Concepto.
Se define objeto recursivo como: aquel que forma parte de s mismo o que forma
parte de su propia definicin.
La recursividad es un concepto matemtico que permite formular definiciones
como, por ejemplo, la de nmero natural:
o El 1 es un nmero natural.
o El siguiente de un nmero natural es un nmero natural.
Otro ejemplo sera la definicin de factorial de nmero natural:
o 0! = 1;
o
N > 0, N! = N * (N-1)!
1.3.5.2. Aplicacin del concepto de recursividad en programacin.
Los ejemplos anteriores se pueden implementar mediante programas informticos que
proporcionan un mtodo sencillo, til y potente de resolucin de infinidad de problemas.
De hecho, hay algunos cuya solucin no recursiva sera de elevada complejidad y escasa
eficiencia34. Frente a las ventajas indicadas (robustez y legibilidad) de la recursividad frente
al tratamiento iterativo se contrapone el inconveniente del mayor consumo de memoria, por
las razones que se explican a continuacin.
La recursividad en programacin se obtiene mediante subprogramas que se llaman a
s mismos (es decir, una de las sentencias del cuerpo del subprograma coincide con el
nombre del mismo), no obstante sera ms correcto decir que llama a otra copia (instancia)
del mismo, esa copia a otra nueva y as sucesivamente hasta que se alcanza una condicin
denominada de terminacin o de parada.
Una vez que se alcanza la condicin de terminacin, en la instancia n-sima se
retorna (como en todo subprograma) al punto del modulo de llamada de la instancia previa
desde donde sta se realiz, y as sucesivamente, teniendo lugar una fase de vuelta por las
instancias anteriores, hasta llegar al punto del programa principal en que se produjo la
llamada al subprograma recursivo.
La implementacin en ordenador de algoritmos recursivos requiere una tecnologa
dinmica, diferente a la esttica (explicada en el apartado 1.3.2), dado que no se sabe, a
priori, cuantas instancias se van a necesitar. Durante la fase de ida se cargan en la
memoria nuevas copias del subprograma35 hasta alcanzar la terminacin (fase de
34
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 25
Explicacin:
El programa principal llama al subprograma factorial y le pasa como argumento la
variable d. Cuando ste termine de ejecutarse, el programa de llamada dispondr de
un resultado que podr mostrar por la pantalla.
El subprograma factorial es recursivo.
o
36
Su nmero de orden ser uno ms que el dato cuyo factorial se quiere calcular.
26 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
37
static void B () {
<sentencia 1>;
...
A ();
......
<sentencia m>;
}
En algunos casos la terminacin anticipada es necesaria para el correcto funcionamiento del programa
mientras que en otros, aunque el programa funcione se debe usar por consideraciones de eficiencia.
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 27
1.3.5.4. Ejemplos.
Ejemplo 1. (Utilizacin de un mdulo de llamada).
El programa que se muestra a continuacin utiliza un mtodo que obtiene la suma de
los divisores de un nmero natural. Por ejemplo: la suma de los divisores de 40 (2, 4, 5,
8, 10, 20) es 49.
import java.io.*;
public class Recursividad1 {
static int sumaDivisores (int dato, int presuntoDivisor) {
int resul = 0;
if ((presuntoDivisor*2) <= dato) {
resul = sumaDivisores (dato, presuntoDivisor+1);
if ((dato % presuntoDivisor) == 0)
resul = resul + presuntoDivisor;
}
return resul;
}
static int sumaDivisores (int dato) {
return sumaDivisores (dato, 2);
}
public static void main(String[] args) throws NumberFormatException,IOException{
int d, suma;
BufferedReader linea = new BufferedReader (new InputStreamReader(System.in));
do {
System.out.print ("Introduzca un nmero mayor que cero: ");
d = Integer.parseInt (linea.readLine ());
} while (d <= 0);
suma = sumaDivisores (d);
System.out.print ("La suma de los divisores de " + d + " es " + suma);
}
}
El diseador del programa principal no tiene por qu saber que se necesitan otros
argumentos adicionales al dato (d), sin embargo, el subprograma recursivo realmente
necesita otro argumento (presuntoDivisor, de tipo entero), para probar recursivamente
desde 2 hasta d/2 y controlar la terminacin (pesimista).
Ejemplo 2. (Terminacin anticipada).
El siguiente ejemplo consiste en una funcin booleana (esPrim) que indica si un
nmero (d) que se introduce desde el teclado es primo (true) o no (false).
La condicin de terminacin pesimista es d >
dato
28 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 29
import java.io.*;
public class Recursividad3 {
static boolean esPrim (int dato, int presuntoDivisor) {
boolean resul;
if ((presuntoDivisor*presuntoDivisor) <= dato)
if ((dato % presuntoDivisor) != 0)
resul = esPrim (dato, presuntoDivisor+1);
else resul = false;
else resul = true;
return resul;
}
public static class Suma {
static int numeroFactores = 0; //variable global de la clase Suma
static int sumaPrimos (int dato, int presuntoPrimo) {
int resul, orden;
if ((presuntoPrimo * 2) <= dato)
if ((dato % presuntoPrimo) == 0)
if (esPrim (presuntoPrimo, 2)) {
numeroFactores= numeroFactores + 1;
orden = numeroFactores;
resul = sumaPrimos(dato, presuntoPrimo + 1);
if ((numeroFactores% 2) == 0) {
if (orden <= (numeroFactores / 2))
resul = resul + presuntoPrimo;
}
else {
if (orden > ((numeroFactores / 2) + 1))
resul = resul + presuntoPrimo;
}
}
else resul = sumaPrimos (dato, presuntoPrimo + 1);
else resul = sumaPrimos (dato, presuntoPrimo + 1);
else resul = 0;
return resul;
}
static int sumaPrimosCondicionada (int dato) {
int resul;
resul = sumaPrimos (dato, 2);
return resul;
}
}
public static void main(String[] args) throws NumberFormatException,IOException{
int d, suma;
BufferedReader linea = new BufferedReader (new InputStreamReader(System.in));
do {
System.out.print("Introduzca un nmero mayor que cero: ");
d = Integer.parseInt (linea.readLine());
} while (d <= 0);
suma = Suma.sumaPrimosCondicionada (d);
System.out.println ("El resultado es: " + suma);
}
}
30 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
primos, por lo que no se sabe qu hay que sumar. La parte de proceso que se realiza
en ella consiste en:
o Identificar si un nmero (argumento presuntoPrimo, pasado por valor) es
primo y factor de d.
En caso negativo se realiza una nueva llamada recursiva con
presuntoPrimo+1.
En caso afirmativo:
Se contabiliza en la variable numeroFactores global dentro de la clase
Suma, inicializado a 0 (pues se utilizar su valor final en la fase de
vuelta).
Se toma nota del nmero de orden (orden) del factor primo
encontrado (variable local que recoge el valor actual de
numeroFactores)38.
NOTA IMPORTANTE: Evitar el error de intentar pasar a la siguiente instancia el valor
de una variable local.
En caso contrario:
Se recibe el valor devuelto por el mtodo desde la instancia siguiente
(resul).
Si el valor de orden se encuentra dentro del rango adecuado (primeros o
ltimos, segn proceda) se suma al valor de resul el de presuntoPrimo.
Se devuelve el resultado a la instancia anterior.
38
En las instancias correspondientes a valores de presuntoPrimo que no son factores primos el valor de la
variable orden es aleatorio
39
Vamos marcha atrs.
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 31
32 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
40
Este concepto toma su suporte fsico en el mecanismo de direccionamiento indirecto tal como se maneja en
los lenguajes de bajo nivel.
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 33
Variable de trabajo
(apuntada por puntero)
puntero
Memoria
dinmica
Memoria
esttica
se declara una variable (puntVector) de tal forma que, al realizar la operacin new se
reserve el espacio necesario para almacenar un vector de 100 caracteres.
Adems de la operacin ya indicada de reserva (new), las referencias admiten las
siguientes operaciones:
34 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
Aunque, como se ha indicado, una variable de tipo puntero apunta a una zona de
memoria (nodo) existe una situacin excepcional consistente en no apuntar a ninguno. En
Java se utiliza para esto la constante null.
Sobre las variables referencia, se realizan las operaciones propias del tipo de datos a
que pertenezcan.
41
Este tipo de operaciones deber hacerse con especial cuidado pues, si no se han tomado previamente las
precauciones oportunas, podra perderse la informacin almacenada en el nodo inicialmente apuntado por
<puntero1> (se perder si no tenemos otra referencia a esa informacin)
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 35
20
40
60
80
100
int [] vector1;
Declara una variable llamada vector1 que es un vector de enteros inicialmente vaco.
Para indicar el tamao del vector, se puede hacer directamente en la propia lnea de
declaracin:
Int [] vector1 = new int [5];
Acceso:
o Al conjunto. Por ejemplo asignar un vector a otro del mismo tipo:
vector2 = vector1.
42
36 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
Con lo que se podr realizar cualquier operacin acorde con el tipo del elemento
correspondiente. Por ejemplo, si datos es un vector de nmeros enteros podramos hacer:
datos [3] = datos [3] * 2;
Ejemplo.
A continuacin se retoma el ejemplo expuesto en el apartado 1.3.4.1 (valores medio y
rango de un conjunto de 5 nmeros enteros) utilizando un vector.
import java.io.*;
public class PruebaVectores {
static float media (int [ ] dato) {
float resul = 0;
int i;
for (i = 0; i < 5; i ++)
resul = resul + dato [i];
resul = resul / i;
return resul;
}
static int max (int [] dato) {
int resul,i;
resul = dato[0];
for (i = 1; i<5; i++)
if (dato[i] > resul)
resul = dato[i];
return resul;
}
static int min (int [] dato) {
int resul,i;
resul = dato[0];
for (i = 1; i < 5; i ++)
if (dato [i] < resul)
resul = dato [i];
return resul;
}
public static void main(String [] args)throws NumberFormatException,IOException{
int [ ] d = new int [5];
int i, rango;
float media;
BufferedReader linea = new BufferedReader(new InputStreamReader(System.in));
System.out.println ("Introduce cinco nmeros enteros: ");
for (i = 0; i < 5; i ++)
d[i] = Integer.parseInt (linea.readLine ());
media = media (d);
System.out.println ("El valor medio es: " + media);
rango = max (d) - min (d);
System.out.println ("y el rango: " + rango);
}
}
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 37
7
8
6
5
7
6
5
15
17
13
14
14
16
13
1
2
3
4
5
6
(Con lo que se podr realizar cualquier operacin acorde con el tipo del elemento
correspondiente). Por ejemplo: temperaturas [3] [1] = temperaturas [3] [1] + 2;
Ejemplo.
El siguiente cdigo permite encontrar la temperatura mnima de la semana y el da en
que se produjo la mxima diferencia (en caso de coincidencia de varias se muestra el
primero de ellos). En el ejemplo anterior los resultados seran:
Temperatura mnima: 5 grados.
Da de mxima diferencia de temperaturas: 5 (10 grados).
38 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
import java.io.*;
public class PruebaMatrices {
static BufferedReader linea=new BufferedReader(new
InputStreamReader(System.in));
public static void leerMatriz (int [][] temperaturas) throws
NumberFormatException, IOException{
int i,j;
for (i = 0;i < 7; i ++)
for (j = 0; j < 2; j ++) {
System.out.println ("Valor dia: " + i + " extremo: " + j + ": ");
temperaturas [i] [j] = Integer.parseInt (linea.readLine ());
}
}
public static int min (int [][] temperaturas) {
int resul, i;
resul = temperaturas [0] [0];
for (i = 1; i < 7; i++)
if (temperaturas [i] [0] < resul)
resul = temperaturas [i] [0];
return resul;
}
public static int maxDif (int [] [] temperaturas) {
int resul, i, dif;
resul = 0;
dif = temperaturas [0][1]- temperaturas [0][0];
for (i = 1; i < 7; i++) {
if (temperaturas [i][1] - temperaturas [i][0] > dif) {
dif = temperaturas [i][1] - temperaturas [i][0];
resul = i;
}
}
return resul;
}
public static void main(String[] args) throws NumberFormatException,
IOException{
int [][] temperaturas = new int [7][2];
int minimaTemperatura, diferenciaTemperaturas;
leerMatriz (temperaturas);
minimaTemperatura = min (temperaturas);
diferenciaTemperaturas = maxDif (temperaturas);
System.out.println ("Resultados:");
System.out.println ("Temperatura minima: " + minimaTemperatura);
System.out.println ("Dia extremo: " + diferenciaTemperaturas);
}
}
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 39
1.4.2.1.3. N-dimensionales.
Por extensin, lo explicado para una y dos dimensiones se puede aplicar al caso de
matrices N-dimensionales.
1.4.2.2. Estructuras de datos heterogneas.
Como ya se ha indicado, estn constituidas por un conjunto de tipos de datos (ya sean
datos simples u otras estructuras de datos) de diferente naturaleza. La forma bsica de
estructura de datos heterognea es el registro cuyos elementos se llaman campos (o
atributos)44.
Por ejemplo, la figura siguiente muestra un registro (alumno) cuyos campos son: el
nmero de matrcula (numeroMatricula), apellidos (apellidos), nombre (nombre), direccin
de correo electrnico (eMail), ao de nacimiento (anio) y calificacin (calificacion).
alumno
numeroMatricula
apellidos
nombre
ao
calificacion
bc2658
Snchez Arellano
Estela
esanchez@servidor.es
1987
6.75
String numeroMatricula;
String apellidos;
String nombre;
String eMail;
int ao;
float calificacion;
44
Con frecuencia uno de los campos (o combinacin de ellos) se utiliza como identificativo del registro. A
dicho campo (o conjunto) se le denomina clave (key).
45
Existen otras operaciones. Consultar el manual del lenguaje.
40 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
Acceso:
o Al conjunto. Por ejemplo apuntar con una variable de tipo registro mismo sitio
que apunta otra del mismo tipo:
variable2_RegistroAlumno = variable1_RegistroAlumno;
Con lo que se podr realizar cualquier operacin acorde con el tipo del
elemento correspondiente. Por ejemplo: alumno.eMail = esanchez@servidor.es;
Normalmente, el trabajo con un registro (o con un conjunto pequeo de variables
independientes de tipo registro) ofrece poco juego. Lo habitual es utilizar una coleccin
de registros estructurados en un vector, o mucho mejor, almacenarlos, como un fichero
en un dispositivo de almacenamiento externo (tpicamente disco).
La utilizacin de ficheros en dispositivos de almacenamiento externos se explica en el
apartado 1.5. A continuacin se muestra un ejemplo que utiliza un vector de registros del
tipo anterior cuyo modelo se ilustra grficamente en la figura siguiente:
0
1
2
3
4
5
numeroMatricula
apellidos
nombre
ao
calificacion
aa1253
ax0074
mj7726
lp1523
bc2658
gb1305
Arias Gonzlez
Garca Sacedn
Lpez Medina
Ramrez Heredia
Snchez Arellano
Yuste Pelez
Felipe
Manuel
Margarita
Jorge
Estela
Juan
farias@servidor.es
mgarcia@servidor.es
mlopez@servidor.es
jramirez@servidor.es
esanchez@servidor.es
jyuste@servidor.es
1988
1985
1990
1998
1989
1990
3.50
8.35
7,70
4,50
6.75
5,50
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 41
Import java.io.*;
class RegistroAlumno {
public RegistroAlumno () {
numeroMatricula= null;
apellidos = null;
nombre = null;
eMail= null;
ao = 1980;
calificacion = 0;
}
public String aCadena () {
return numeroMatricula + " " + apellidos + " " + nombre + " " + eMail +
" " + ao + " " + calificacion;
}
public String numeroMatricula;
public String apellidos;
public String nombre;
public String eMail;
public int ao;
public float calificacion;
public void cargarRegistro () throws IOException {
BufferedReader linea = new BufferedReader (new InputStreamReader (System.in));
System.out.println ("Numero de matricula: ");
numeroMatricula = new String (linea.readLine ());
System.out.println ("Apellidos: ");
apellidos = new String (linea.readLine ());
System.out.println ("Nombre: ");
nombre = new String (linea.readLine ());
System.out.println ("Correo electronico: ");
eMail = new String (linea.readLine ());
System.out.println ("Ao de nacimiento: ");
ao = Integer.parseInt (linea.readLine());
System.out.println ("Calificacin: ");
calificacion = Float.parseFloat (linea.readLine());
System.out.println (this.aCadena ());
}
}
42 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
import java.io.*;
public class PruebaRegistro {
static void cargarTabla (RegistroAlumno [ ] alumnos) throws IOException {
int i;
for (i = 0; i < 6; i++) {
System.out.println ("Datos del alumno N: "+ i);
alumnos [i].cargarRegistro ();
}
}
static float mediaCalif (RegistroAlumno [ ] alumnos) {
float resul = 0;
int i;
for (i = 0; i < 6; i++) {
System.out.println(alumnos [i].aCadena ());
resul = resul + alumnos [i].calificacion;
}
return resul/6;
}
public static void main (String [ ] args) throws IOException {
RegistroAlumno [ ] alumnos = new RegistroAlumno [6];
float media;
int i;
for (i = 0; i < 6; i++)
alumnos [i]= new RegistroAlumno ();
cargarTabla (alumnos);
media = mediaCalif (alumnos);
System.out.println ("La media de las calificaciones es: " + media);
}
}
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 43
Entre cada una de las lneas existen cdigos invisibles cuyo efecto es hacer saltar al
inicio de la lnea siguiente. Estos cdigos se generan automticamente al pulsar la tecla
Intro. As mismo, para indicar el final del fichero de texto, el usuario deber haber
pulsado la tecla de funcin F6.
La figura siguiente muestra el cdigo ASCII correspondiente al ejemplo.
46
Este concepto est heredado de los antiguos ficheros (o archivadores) que contenan fichas (de papel)
cada una de las cuales representaba una informacin unitaria: ficheros de pelculas, personas, asignaturas.
44 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
import java.io.*;
public class prueba_fichero_texto {
lineaLeida
Marse.txt
47
La ruta, nombre y extensin del fichero se eligen libremente (con las restricciones propias del sistema
operativo). En el ejemplo se han utilizado:
Ruta: (por omisin) la misma que el programa.
Nombre: archivo.
Extensin txt (para poder visualizarlo mediante el bloc de notas notepad- de Windows).
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 45
import java.io.*;
public class PruebaFicheroSalida {
public static void main (String [ ] args) throws IOException {
FileWriter fich_s = new FileWriter ("archivo.txt");
BufferedWriter bw = new BufferedWriter (fich_s);
PrintWriter salida = new PrintWriter (bw);
BufferedReader linea = new BufferedReader (new InputStreamReader(System.in));
String lineaLeida;
System.out.println ("Escriba la primera
lineaLeida = new String (linea.readLine
salida.println (lineaLeida);
System.out.println ("Escriba la segunda
lineaLeida = new String (linea.readLine
salida.println (lineaLeida);
salida.close ();
linea: ");
());
linea: ");
());
}
}
46 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
establece una vinculacin entre el nombre fsico del fichero y el nombre lgico.
Se utiliza una variable de tipo String (en el ejemplo: lineaLeida) como puente
entre la memoria del ordenador y el dispositivo de almacenamiento (disco). Segn
sea el sentido de la transferencia se puede hablar de lectura: disco memoria
(readline) o de escritura memoria disco (println).
Hay que preparar el fichero en disco para utilizarlo (apertura) y dejarlo disponible
para posteriores usos (cierre).
1.5.1.2. Sintaxis de las principales operaciones relacionadas con los ficheros de texto49.
Acceso (Asignacin y apertura) y declaracin de variables:
o Crear un nuevo fichero y destruir, en su caso, un fichero previo.
Posteriormente se podr escribir en l:
FileWriter <nombre lgico> = new FileWriter (<nombre fsico>);
BufferedWriter <buffer escritura> = new BufferedWriter (<nombre lgico>);
PrintWriter <variable> = new PrintWriter (<buffer escritura>);
Proceso:
o Leer (transferir a la variable correspondiente) el contenido de una lnea del
fichero y prepararse para la siguiente.
<variable tipo String> = <buffer lectura>.readline();
48
Dicho fichero estar gestionado por el sistema operativo. Con frecuencia se cambia de ubicacin los
ficheros (fsicos) y de no seguir esta filosofa, esto implicara re-escribir parte del cdigo cada vez que un
fichero cambiase de ubicacin.
49
Para mayor informacin consultar el manual de programacin.
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 47
Terminacin:
o Dejar el fichero preparado para usos posteriores:
<variable>.close ();
Por ejemplo, si queremos leer un fichero hasta llegar al final lo podemos hacer
utilizando lo siguiente:
import java.io.*;
public class PruebaFicheroEntrada {
public static void main (String [ ] args) throws IOException {
String lineaLeida;
FileReader fichLeido = new FileReader ("archivo.txt");
BufferedReader entrada = new BufferedReader (fichLeido);
System.out.println ("Contenido del fichero: ");
while ((lineaLeida = entrada.readLine ()) != null)
System.out.println (lineaLeida);
entrada.close ();
}
}
Para poder leer y escribir objetos que se han declarado como serializables se utilizan
las clases ObjectInputStream y ObjectOutputStream, que cuentan con los mtodos
writeObject() y readObject().
Para escribir un objeto en un fichero se utilizar:
ObjectOutputStream <objEscrito> = new ObjectOutputStream (new
FileOutputStream("<nombre fichero>"));
<objEscrito>.writeObject (<variable>);
50
48 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
Por simplicidad no se han considerado situaciones excepcionales (por excepcin). Por ejemplo:
No tiene sentido utilizar la opcin [2]: Cargar tabla de registros, si no existe el fichero en disco.
Tampoco lo tiene utilizar la opcin [3]: Calcular calificacin media, si no se ha ejecutado (con xito)
previamente la opcin [2].
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 49
Inicio
menu
Mdulo
principal
Fin
crearFichero
cargarTabla
op
mediaCalif
50 INTRODUCCIN A LA PROGRAMACIN
ESTRUCTURAS DE DATOS
("OPCIONES:");
("Opcion 1: Crear fichero.");
("Opcion 2: Cargar tabla de registros.");
("Opcion 3: Calcular calificacion media.");
("Opcion 0: Salir.");
("\n Introduzca opcion: ");
ESTRUCTURAS DE DATOS
INTRODUCCIN A LA PROGRAMACIN 51
TEMA 1. ....................................................................................................................... 1
1.1.
1.1.1.
1.1.2.
1.2.
1.2.1.
1.2.2.
1.2.3.
Los datos................................................................................................. 6
1.2.4.
Sentencias. ............................................................................................ 10
1.3.
1.3.1.
1.3.2.
1.3.3.
1.3.4.
1.3.5.
Recursividad. ........................................................................................ 24
1.4.
1.4.1.
1.4.2.
1.5.
1.5.1.
1.5.2.
ESTRUCTURAS DE DATOS
TEMA 2
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
apilar
5
4
1
7
2
cima
fondo
Operacin
2
apilar
desapilar
pilaVacia
leerPila
imprimirPila
numElemPila
cima
decapitar
eliminarPila
Especificacin semntica
Mtodo que entrega un elemento (x) para
que quede incorporado en la cima de la
pila.
Mtodo que elimina el elemento que ocupa
la cima de la pila y devuelve como
resultado dicho elemento.
Mtodo que al ejecutarse devuelve true si la
pila est vaca (no tiene elementos), y false
en caso contrario.
Mtodo que se utiliza para realizar la carga
inicial de elementos de la pila.
Mtodo que muestra en la pantalla el
contenido de la pila.
Mtodo que devuelve el nmero de
elementos de la pila.
Mtodo que devuelve la cima de la pila (sin
alterarla).
Mtodo que elimina el elemento de la cima
de la pila.
Mtodo que recibe una pila (que puede
tener elementos o no) y la devuelve vaca.
ESTRUCTURAS DE DATOS
Especificacin sintctica
void apilar (int x)
boolean pilaVacia ()
Se puede producir una situacin de excepcin cuando el nmero de elementos de la pila supere determinado
valor (lgicamente no podrn ser infinitos). Dicha situacin se manifestar al intentar ejecutar la operacin de
apilar sobre una pila en dicho estado.
3
Se produce una excepcin (PilaVacia) si se intenta desapilar de una pila vaca. Lo mismo ocurre con las
operaciones cima y decapitar.
4
Puede resultar innecesario y forzado en Java, pero queremos transmitir la idea de la obligacin de crear y
destruir los objetos cuando se trabaje en Programacin Orientada a Objetos.
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
(elem1, elem2)5. Para ello se utilizan los argumentos booleanos apilar1 y apilar2. Su
interpretacin es: un valor true indica que el elemento (elem1|2) an no se ha tratado,
por lo que queda pendiente de apilar en la fase de vuelta (y, en su caso, de tratar) y no
deber desapilarse de la pila correspondiente en la siguiente instancia.
Se realiza una llamada recursiva con los argumentos actualizados durante el tratamiento
anterior.
Se escribe el cdigo que deber ejecutarse la fase de vuelta correspondiente a la
instancia actual que, entre otros posibles aspectos, deber ocuparse de (re)apilar los
elementos desapilados en dicha instancia.
Consideracin inicial: Los argumentos apilar1 y apilar2 deben inicializarse a false
(no hay ningn elemento pendiente por tratar). Los valores iniciales de elem1 y elem2 no
tienen relevancia.
Condicin de terminacin:
Obsrvese que el hecho de recibir una pila vaca es una condicin necesaria para dar
por finalizado su tratamiento, pero no suficiente. Es posible que el elemento del fondo de
una pila se haya desapilado en instancias anteriores, por lo que la pila se propaga vaca pero
aun no se ha tratado su ltimo elemento. As pues una pila se mantiene vigente en el
proceso recursivo si:
!pila1|2.pilaVacia () || apilar1|2
En este caso elem1, elem2 no se utilizan como variables locales tal como se hace en el caso de tratamientos
con una sola pila).
6
Entendidas como pendiente.
ESTRUCTURAS DE DATOS
tratar). Se debern apilar (y, en su caso, procesar) los elementos pendientes desapilados
en instancias anteriores (identificados mediante la condicin apilar1|2 == true). La fase
de transicin finaliza y se inicia la de vuelta. (Un posible ejemplo sera: obtener una
pila con los elementos comunes de otras dos).
Para que el tratamiento acabe es necesario procesar ambas pilas (unin o modalidad
OR). (Por ejemplo, si se desea obtener una pila con los elementos de otras dos). En este
caso:
o Si una pila est procesada (pend1|2 == false) y la otra no (pend2|1 == true):
Se (re)apila, si procede, el elemento desapilado de la pila pendiente de procesar
(apilar2|1) y se realiza, si procede, el tratamiento oportuno con dicho elemento
(elem2|1).
Se invoca a un (nuevo) tratamiento recursivo que opera nicamente sobre la pila
pendiente de procesar.
o Si ambas pilas estn procesadas por completo (pend1 == false y pend2 == false), el
proceso de transicin finaliza y se inicia la fase de vuelta.
Fase de vuelta: Desde las correspondientes instancias se realiza el tratamiento
adecuado que deber contemplar, normalmente, la restitucin (apilar) de los valores
desapilados en la fase de ida.
2.2.6.3.1. Ejemplo1. Realizar la interseccin de dos pilas.
Dadas dos pilas (pila1 y pila2) ordenadas ascendentemente desde la cima hacia el
fondo (sin elementos repetidos en cada una de las pilas), se desea obtener una nueva pila
(pila3), tambin ordenada ascendentemente y sin elementos repetidos, con los elementos
comunes de ambas.
Aplicando a este caso el tratamiento genrico, se trata de:
Fase de ida. Desapilar si procede (en funcin del valor de los argumentos apilar1 y
apilar2. Existen los siguientes casos:
o elem1 > elem2. Habr que (re)apilar elem2 en pila2 en la fase de vuelta. La llamada
recursiva se hace con apilar1 = true y apilar2 = false.
o
elem1 < elem2. Tendremos que (re)apilar elem1 en pila1 en la fase de vuelta. La
llamada recursiva se hace con apilar1 = false y apilar2 = true.
ESTRUCTURAS DE DATOS
2
4
77
pila1
apilar2
false
ep2
?
1
2
3
4
5
6
7
pila2
pila3
2
4
77
pila1
apilar2
indif
ep2
indif
1
2
3
4
5
6
7
pila2
2
4
pila3
ESTRUCTURAS DE DATOS
static void mezclarPilaAND (Pila pila1, Pila pila2, Pila pila3, boolean apilar1,
boolean apilar2, int elem1, int elem2) throws PilaVacia {
boolean pend1, pend2;
pend1 = !pila1.pilaVacia () || apilar1;
pend2 = !pila2.pilaVacia () || apilar2;
if (pend1 && pend2) {
if (!apilar1)
elem1 = pila1.desapilar ();
if (!apilar2)
elem2 = pila2.desapilar ();
if (elem1 < elem2) {
mezclarPilaAND (pila1,pila2,pila3,false,true,elem1,elem2);
pila1.apilar (elem1);
}
else if (elem2 < elem1) {
mezclarPilaAND (pila1,pila2,pila3,true,false,elem1,elem2);
pila2.apilar (elem2);
}
else {
mezclarPilaAND (pila1,pila2,pila3,false,false,elem1,elem2);
pila1.apilar (elem1);
pila2.apilar (elem2);
pila3.apilar (elem1);
}
}
else if (apilar1)
pila1.apilar (elem1);
else if (apilar2)
pila2.apilar (elem2);
}
ESTRUCTURAS DE DATOS
elem1 < elem2. Tendremos que apilar elem1 en pila3 (y reapilar en pila1) en la fase
de vuelta. La llamada recursiva se hace con apilar1 = false y apilar2 = true.
apilar1
false
ep1
?
ESTRUCTURAS DE DATOS
2
4
77
pila1
apilar2
false
ep2
?
1
2
3
4
5
6
7
pila2
pila3
2
4
77
pila1
apilar2
indif
ep2
indif
1
2
3
4
5
6
7
pila2
1
2
3
4
5
6
7
77
pila3
ESTRUCTURAS DE DATOS
int elem;
if (! pilaO.pilaVacia ()) {
elem = pilaO.desapilar ();
copiarPila (pilaO, pilaD);
pilaO.apilar (elem);
pilaD.apilar (elem);
}
}
static void mezclarPilaOR (Pila pila1, Pila pila2, Pila pila3, boolean apilar1,
boolean apilar2, int elem1, int elem2) throws PilaVacia {
boolean pend1, pend2;
pend1 = !pila1.pilaVacia () || apilar1;
pend2 = !pila2.pilaVacia () || apilar2;
if (pend1 && pend2) {
if (!apilar1)
elem1 = pila1.desapilar ();
if (!apilar2)
elem2 = pila2.desapilar ();
if (elem1 < elem2) {
mezclarPilaOR (pila1, pila2, pila3, false, true, elem1, elem2);
pila1.apilar (elem1);
pila3.apilar (elem1);
}
else if (elem2 < elem1) {
mezclarPilaOR (pila1,pila2,pila3,true,false,elem1,elem2);
pila2.apilar (elem2);
pila3.apilar (elem2);
}
else {
mezclarPilaOR (pila1,pila2,pila3,false,false,elem1,elem2);
pila1.apilar (elem1);
pila2.apilar (elem2);
pila3.apilar (elem1);
}
}
else if (pend1 && !pend2) {
copiarPila (pila1, pila3);
if (apilar1) {
pila1.apilar (elem1);
pila3.apilar (elem1);
}
}
else if (pend2 && !pend1) {
copiarPila (pila2, pila3);
if (apilar2) {
pila2.apilar (elem2);
pila3.apilar (elem2);
}
}
}
ESTRUCTURAS DE DATOS
elem1 < elem2. Hay que reapilar elem1 en pila1 en la fase de vuelta. La llamada
recursiva se hace con apilar1 = false y apilar2 = true.
o elem1 == elem2. En la fase de vuelta se reapilan los dos elementos en pila1 y pila2.
La llamada recursiva se hace con apilar1 = false y apilar2 = false.
Condicin de terminacin. El proceso finaliza cuando se acaba con el tratamiento de
una de las pilas (pend1 && pend2) == false.
Fase de transicin
o Si queda algn elemento pendiente de tratar en alguna de las pilas (apilar1 == true
o apilar2 == true), habr que apilarlo en la pila que corresponda y asignar el
resultado correspondiente al mtodo.
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
2.3.
2.4.2.3. TAD COLA DE NMEROS ENTEROS.
2.4.1.2.3.1. Concepto.
Una cola es una agrupacin de elementos de determinada naturaleza o tipo (datos de
personas, nmeros, procesos informticos, automviles, etc.) entre los que existe definida
una relacin de orden (estructura de datos). En funcin del tiempo, algunos elementos
pueden llegar a la cola o salir de ella (operaciones / acciones). En consecuencia el estado
de la cola vara.
Una cola presenta comportamiento FIFO (First Input First Output) y se respeta como
criterio de ordenacin el momento de la llegada: el primer elemento de la cola, ser el que
primero lleg a ella y, en consecuencia, el primero que saldr, y as sucesivamente.
2.4.2.2.3.2. Modelo grfico.
Podramos representar grficamente una cola segn aparece en la Figura 2.6: una
estructura de datos horizontal, en la que los elementos se insertan por el extremo derecho, y
se extraen por la parte izquierda.
desencolar
principio
fin
5 1 4 3 2 7 9 6 8
encolar
ESTRUCTURAS DE DATOS
Operacin
7
encolar
desencolar
colaVacia
leerCola
imprimirCola
invertirCola
numElemCola
primero
quitarPrimero
eliminarCola
Especificacin semntica
Mtodo que entrega un elemento (x) para
que quede incorporado al final de la cola.
Mtodo que elimina el elemento de la cola
que ocupa el primer lugar, devolvindolo
como resultado.
Mtodo que al ejecutarse devuelve true si
la cola est vaca, y false en caso
contrario.
Mtodo mediante el que se produce la
carga inicial de elementos de la cola.
Mtodo que muestra en el dispositivo de
salida (pantalla) el contenido actual de la
cola.
Mtodo que devuelve la cola con sus
elementos invertidos
Mtodo que devuelve el nmero de
elementos de la cola.
Mtodo que devuelve el primer elemento
de la cola sin desencolarlo.
Mtodo que elimina el primer elemento de
la cola.
Mtodo que recibe una cola (que puede
tener elementos o no) y la devuelve vaca.
Especificacin sintctica
void encolar (int x)
int desencolar () throws ColaVacia
boolean colaVacia ()
Se puede producir una situacin de excepcin cuando el nmero de elementos de la cola supere determinado
valor (lgicamente no podrn ser infinitos) y se intente encolar sobre una cola en dicho estado.
8
Se produce una excepcin (ColaVacia) si se intenta desencolar de una cola vaca. Lo mismo ocurre con las
operaciones primero y quitarPrimero.
ESTRUCTURAS DE DATOS
Condiciones normales.
2.4.5.2.2.3.5.2.
Situaciones de excepcin.
ESTRUCTURAS DE DATOS
2.4.6.2.2.3.6.2.
Si hay que hacer un mtodo que cuente los elementos de una cola, evidentemente no
se conoce a priori el nmero de elementos. La nica posibilidad para realizar el mtodo es
un tratamiento recursivo que, aunque cuente correctamente el nmero de elementos de la
cola, los devolvera en el orden contrario al inicial. Se necesita, pues, una ejecucin (antes o
despus) del mtodo visto en el apartado anterior (invertir) fuera del tratamiento recursivo.
ESTRUCTURAS DE DATOS
2.4.6.3.2.3.6.3.
Siempre que vayamos a trabajar con colas, tenemos tres formas posibles de hacerlo:
Si no conocemos el nmero de elementos de la cola, necesariamente tendremos que
realizar un tratamiento recursivo siguiendo el esquema desencolartratamiento
recursivoencolar. El problema que tenemos es el que ya se ha planteado
previamente: este tratamiento deja la cola invertida. Por lo tanto, posteriormente habr
que invertir la cola resultante.
Cuando conocemos el nmero de elementos de la cola, podemos optar entre las dos
siguientes posibilidades:
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
if (n > 0) {
elem = colaO.desencolar ();
colaO.encolar (elem);
copiaRecursiva2Invertida (colaO, colaD, n-1);
colaD.encolar (elem);
}
n = colaO.numElemCola ();
for (i = 1; i <= n; i++) {
elem = colaO.desencolar ();
colaD.encolar (elem);
colaO.encolar (elem);
}
Si lo que se pretende es obtener la cola resultante (colaD) con sus elementos en orden
contrario al inicial (colaO) sera necesario invertir posteriormente el resultado (ejecucin
del mtodo invertir) una vez ejecutado el tratamiento iterativo.
static void copiaIterativaInvertida (Cola colaO, Cola colaD) throws ColaVacia {
int elem, i, n;
n = colaO.numElemCola ();
for (i = 1; i <= n; i++) {
elem = colaO.desencolar ();
colaD.encolar (elem);
colaO.encolar (elem);
}
colaD.invertirCola ();
}
ESTRUCTURAS DE DATOS
2.4.6.4.2.3.6.4.
2.4.6.5.2.3.6.5.
Terminacin anticipada.
ESTRUCTURAS DE DATOS
10
12
14
16
18
20
16
18
20
12
10
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
2.4.6.6.2.3.6.6.
ESTRUCTURAS DE DATOS
Condicin de terminacin.
En este caso el control de la condicin de finalizacin se realiza mediante los
argumentos n1 y n2 que representan inicialmente el nmero de elementos de las respectivas
colas. Dichos argumentos debern pasarse por valor y decrementarse en cada llamada
recursiva. La condicin ((n1 == 0) || (n2 == 0)) significa que se ha desencolado el ltimo
elemento de la cola correspondiente (condicin necesaria) pero no suficiente, dado que no
se asegura que dichos elementos se hayan tratado (lo que se deber hacer en la fase
detransicin). As pues el proceso recursivo tiene lugar si (n1 >= 0 && n2 >= 0)9
Fase de ida:
Se realiza el tratamiento especfico con los elementos (elem1 y elem2) que se reciben
como argumentos.
Se desencola-encola de una de las colas o de ambas.
Se realiza una llamada recursiva.
Fase de transicin:
Se realiza, si procede, el tratamiento especfico del ejercicio en cuestin.
Se restaura, si procede, el orden establecido de las colas.
Fase de vuelta:
Se realiza, si procede, el tratamiento especfico del ejercicio en cuestin.
En general no ser necesario realizar la operacin de encolar dado que ya se ha hecho
en la fase de ida (mecanismo desencolar-encolar).
2.4.6.6.1.2.3.6.6.1. Ejemplo 1. Realizar la interseccin de dos colas.
En este ejemplo se parte de dos colas (cola1 y cola2) ordenadas ascendentemente
desde el punto de salida hacia el de llegada para obtener una nueva cola (cola3) con los
elementos comunes de ambas ordenados en el mismo sentido. La Figura 2.11. muestra un
ejemplo.
2
77
cola1
2
2
6
cola 3
cola2
Figura 2.11.Ejemplo de obtencin de una cola con los elementos comunes de otras dos
ESTRUCTURAS DE DATOS
Fase de ida:
Se comparan los elementos procedentes de ambas colas. Tanto elem1 como elem2
proceden de operaciones de desencolar-encolar ejecutadas en instancias anteriores por
lo que se proceder a encolar el menor de ellos (o uno cualquiera si son iguales) en
cola3 (como cola3 debe tener sus elementos ordenados en el mismo sentido que cola1 y
cola2, los elementos se encolarn en cola3 antes de realizar la correspondiente llamada
recursiva).
Se desencola-encola de las cola/s pertinentes si es posible (n1 |2 > 0), pasando as
elem1|2 a la instancia siguiente.
Fase de transicin:
Si una de las colas tiene elementos por tratar y la otra no, se llama al mtodo auxiliar
reOrdenar, que recoloca la cola que tiene elementos pendientes por tratar.
Fase de vuelta:
No hay que realizar ningn tratamiento especfico, ni es necesario realizar la operacin
de encolar dado que ya se ha hecho en la fase de ida (mecanismo desencolar-encolar).
A continuacin se muestra el algoritmo que resuelve el problema
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
77
cola1
2
2
5
77
cola3
cola2
Figura 2.12.Ejemplo de obtencin de una cola con los elementos de otras dos
Para resolver este ejemplo, utilizaremos la tcnica recursiva conociendo el nmero de
elementos. Como en este caso queremos introducir en la cola3 todos los elementos de la
cola1 y la cola2 sin repeticiones, la condicin de parada de la recursividad ser cuando
hayamos tratado todos los elementos de ambas colas (n1 < 0 && n2 < 0).
El diseo propuesto requiere el empleo de instrucciones externas al algoritmo
recursivo: Previamente es necesario desencolar y encolar de ambas colas para disponer de
los valores iniciales de elem1 y elem2.
As pues la cabecera del mtodo recursivo quedara:
Static void MezclaOrR2 (Cola cola1, Cola cola2,Cola cola3,int elem1,int elem2,int
n1 ,int n2);
ESTRUCTURAS DE DATOS
Fase de vuelta:
No hay que realizar ningn tratamiento especfico, ni es necesario realizar la operacin
de encolar dado que ya se ha hecho en la fase de ida (mecanismo desencolar-encolar).
A continuacin se muestra el algoritmo que resuelve el problema.
static void copiarcola (Cola origen, Cola destino, int n) throws ColaVacia {
int elem;
if (n > 0) {
elem = origen.desencolar ();
destino.encolar (elem);
origen.encolar (elem);
copiarcola (origen, destino, n-1);
}
}
static void mezclaOrR2 (Cola cola1, Cola cola2, Cola cola3, int elem1, int elem2,
int n1 , int n2) throws ColaVacia {
if ((n1 >= 0) && (n2 >= 0))
if (elem1 < elem2) {
cola3.encolar (elem1);
if (n1 >0) {
elem1 = cola1.desencolar ();
cola1.encolar (elem1);
}
mezclaOrR2 (cola1, cola2, cola3, elem1, elem2, n1-1, n2);
}
else if (elem1 > elem2) {
cola3.encolar (elem2);
if (n2 > 0) {
elem2 = cola2.desencolar ();
cola2.encolar (elem2);
}
mezclaOrR2 (cola1,cola2,cola3,elem1,elem2,n1,n2-1);
}
else {
cola3.encolar (elem1);
if (n1 > 0) {
elem1 = cola1.desencolar ();
cola1.encolar (elem1);
}
if (n2 > 0) {
elem2 = cola2.desencolar ();
cola2.encolar (elem2);
}
mezclaOrR2(cola1,cola2,cola3,elem1,elem2,n1-1,n2-1);
}
else {
if (n1 >= 0) {
cola3.encolar (elem1);
copiarcola (cola1, cola3, n1);
}
else if (n2 >= 0) {
cola3.encolar (elem2);
copiarcola (cola2, cola3, n2);
}
}
}
ESTRUCTURAS DE DATOS
static void mezclarColaOrR2 (Cola cola1, Cola cola2, Cola cola3) throws ColaVacia {
int elem1 = -9999, elem2 = -9999, n1 , n2;
n1 = cola1.numElemCola ();
n2 = cola2.numElemCola ();
if (n1 > 0) {
elem1 = cola1.desencolar ();
cola1.encolar (elem1);
}
if (n2 > 0) {
elem2 = cola2.desencolar ();
cola2.encolar (elem2);
}
mezclaOrR2 (cola1, cola2, cola3, elem1, elem2, n1-1, n2-1);
}
2.4.6.7.2.3.6.7.
Dadas dos colas (cola1 y cola2) ordenadas ascendentemente desde el inicio hasta el
final (sin elementos repetidos en cada una de las colas), se desea realizar un mtodo
booleano que indique si los elementos de la cola2 estn contenidos en la cola1.
Este ejemplo se puede resolver a partir de la consideracin de mezcla de colas en la
modalidad AND (termina cuando se ha procesado por completo cualquiera de las colas).
En este caso se produce una situacin de terminacin anticipada cuando, en su caso,
aparece por primera vez un elemento de cola2 que no est en cola1 (elem1 > elem2). El
proceso debe terminar y el mtodo devuelve false.
En caso contrario (terminacin pesimista) pueden darse las siguientes
circunstancias:
Se ha procesado completa cola1 (n1 < 0) pero cola2 no (n2 >=0). An quedan
elementos en cola2 por tanto no cumple la condicin de estar contenida en cola1, y
en consecuencia el resultado ser false.
Se ha procesado cola2 completa (n2 < 0) y pero cola1 no (n1 >= 0). Por tanto, cola2
estar contenida en cola1, y en consecuencia el resultado ser true.
Se ha conseguido llegar a la terminacin pesimista (se han procesado completamente
ambas colas: n1 < 0 y n2 < 0). Por lo tanto, cola2 est contenida en cola1 y el mtodo
devolver el valor true.
El diseo propuesto requiere el empleo de instrucciones externas al algoritmo
recursivo: Previamente es necesario desencolar-encolar de ambas colas para disponer de los
valores iniciales de elem1 y elem2.
Aplicando a este caso el tratamiento genrico, se trata de:
Fase de ida.
Desencolar-encolar si procede (en funcin del valor de los argumentos n1 y n2). Se
pueden dar los siguientes casos:
ESTRUCTURAS DE DATOS
o elem1 > elem2. Es imposible que la cola2 se encuentre contenida en la cola1, por lo
que habr que recolocar ambas colas, utilizando el mtodo auxiliar ordenada, y
devolver false como resultado.
o elem1 < elem2. Hay que desencolar de cola1 en la siguiente ejecucin. La llamada
recursiva se hace con n1-1 y n2.
o elem1 == elem. La llamada recursiva se hace con n1-1 y n2-1.
Fase de transicin
Si queda algn elemento pendiente de tratar en alguna de las colas (n1 >= 0 o
n2 >= 0), habr que reordenar la cola que corresponda (con ordenada) y asignar el
resultado correspondiente al mtodo.
Fase de vuelta:
No hay que realizar ningn tratamiento especfico, ni es necesario realizar la operacin
de encolar dado que ya se ha hecho en la fase de ida (mecanismo desencolar-encolar).
El cdigo se muestra a continuacin:
static void ordenar (Cola cola, int n) throws ColaVacia {
int elem;
if (n > 0) {
elem = cola.desencolar ();
cola.encolar (elem);
ordenar (cola, n-1);
}
}
static boolean contenida (Cola cola1, Cola cola2, int elem1, int elem2, int n1 , int
n2) throws ColaVacia {
boolean resul;
if ((n1 >= 0) && (n2 >= 0))
if (elem1 < elem2) {
if (n1 > 0) {
elem1 = cola1.desencolar ();
cola1.encolar (elem1);
}
resul = contenida (cola1, cola2, elem1, elem2, n1-1, n2);
}
else if (elem1 > elem2) {
ordenar (cola1, n1 );
ordenar (cola2, n2);
resul = false;
}
else {
if (n1 > 0) {
elem1 = cola1.desencolar ();
cola1.encolar (elem1);
}
if (n2 > 0) {
elem2 = cola2.desencolar ();
cola2.encolar (elem2);
}
resul = contenida (cola1, cola2, elem1, elem2,n1-1,n2-1);
}
else {
if (n1 >= 0) {
ordenar (cola1, n1);
resul = true;
}
ESTRUCTURAS DE DATOS
}
return resul;
}
static boolean estaContenida (Cola cola1, Cola cola2) throws ColaVacia {
int elem1, elem2, n1, n2;
boolean resul;
n1 = cola1.numElemCola ();
n2 = cola2.numElemCola ();
if ((n1 > 0) && (n2 > 0)) {
elem1 = cola1.desencolar ();
cola1.encolar (elem1);
elem2 = cola2.desencolar ();
cola2.encolar (elem2);
resul = contenida (cola1, cola2, elem1, elem2, n1-1, n2-1);
}
else if (n2 > 0)
resul = false;
else resul = true;
return resul;
}
ESTRUCTURAS DE DATOS
0
10
1
0
2
30
3
0
4
50
ESTRUCTURAS DE DATOS
import java.io.IOException;
import java.io.InputStreamReader;
import tadPila.Pila;
import tadPila.TadPila;
import tadPila.PilaVacia;
public class TadVector implements Vector {
Pila vector;
public int tamano;
public void crearVector () throws NumberFormatException, IOException {
int i;
BufferedReader linea = new BufferedReader(new InputStreamReader
(System.in));
Pila auxv = new TadPila ();
private int leer (int i, int posicion, Pila vector) throws PilaVacia {
int resul, elem;
if (i < posicion) {
elem = vector.desapilar ();
resul = leer (i+1, posicion, vector);
vector.apilar (elem);
}
else {
elem = vector.desapilar ();
resul = elem;
vector.apilar (elem);
}
return resul;
private void escribir (int i, int posicion, int contenido, Pila vector) throws
PilaVacia {
int elem;
if (i < posicion) {
elem = vector.desapilar ();
escribir (i+1, posicion, contenido, vector);
vector.apilar (elem);
}
else {
elem = vector.desapilar ();
vector.apilar (contenido);
}
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
TEMA 2 ...................................................................................................................... 51
2.1.
Concepto ....................................................................................................... 51
2.2.
2.2.1.
Concepto. .............................................................................................. 53
2.2.2.
2.2.3.
Especificaciones ................................................................................... 53
2.2.4.
2.2.5.
2.2.6.
2.3.
2.3.1.
Concepto. .............................................................................................. 70
2.3.2.
2.3.3.
Especificaciones ................................................................................... 70
2.3.4.
2.3.5.
2.3.6.
2.4.
ESTRUCTURAS DE DATOS
LISTAS 93
TEMA 3
Listas.
3.1. CONCEPTOS GENERALES.
Una lista es una estructura de datos lineal que se puede representar simblicamente
como un conjunto de nodos enlazados entre s.
Las listas permiten modelar diversas entidades del mundo real como por ejemplo, los
datos de los alumnos de un grupo acadmico, los datos del personal de una empresa, los
programas informticos almacenados en un disco magntico, etc.
La figura 3.1 muestra un ejemplo de lista correspondiente a los nombres y apellidos
de un conjunto de alumnos con su cdigo de matrcula.
Arias Gonzlez, Felipe
aa1253
Garca Sacedn, Manuel
ax0074
lp1523
gb1305
mj7726
94 LISTAS
ESTRUCTURAS DE DATOS
Tal vez resulte conveniente identificar a los diferentes elementos de la lista (que
normalmente estarn configurados como una estructura de registro) mediante uno de sus
campos (clave) y en su caso, se almacenar la lista respetando un criterio de ordenacin
(ascendente o descendente) respecto al campo clave.
Una definicin formal de lista es la siguiente:
Una lista es una secuencia de elementos del mismo tipo, de cada uno de los cuales
se puede decir cul es su siguiente (en caso de existir).
Existen dos criterios generales de calificacin de listas:
Por la forma de acceder a sus elementos.
o Listas densas. Cuando la estructura que contiene la lista es la que determina la
posicin del siguiente elemento. La localizacin de un elemento de la lista es la
siguiente:
Est en la posicin 1 si no existe elemento anterior.
Est en la posicin N si la localizacin del elemento anterior es (N-1).
o Listas enlazadas: La localizacin de un elemento es:
Estar en la direccin k, si es el primer elemento, siendo k conocido.
Si no es el primer elemento de la lista, estar en una direccin, j, que est
contenida en el elemento anterior.
Por la informacin utilizada para acceder a sus elementos:
o Listas ordinales. La posicin de los elementos en la estructura la determina su orden
de llegada.
o Listas calificadas. Se accede a un elemento por un valor que coincide con el de un
determinado campo, conocido como clave. Este tipo de listas se pueden clasificar a
su vez en ordenadas o no ordenadas por el campo clave.
ESTRUCTURAS DE DATOS
LISTAS 95
aa1253
ax0074
mj7726
lp1523
gb1305
Figura 3.2. Implementacin de una lista densa mediante una estructura esttica
(matriz).
El problema de esta alternativa es el derivado de las operaciones de insercin y
modificacin.
En efecto, la declaracin de una lista mediante una matriz implica conocer de
antemano el nmero (o al menos el orden de magnitud) de elementos que va a
almacenar, pudiendo darse las circunstancias de que si se declara pequeo podra
desbordarse su capacidad o, en caso contrario, declararlo desproporcionadamente
elevado provocara un decremento de eficiencia.
Otro problema asociado es el tratamiento de los elementos eliminados. Dado que
en el caso de no informar, de alguna manera, de la inexistencia de dicho elemento el
nodo previamente ocupado (y ahora no vlido) quedara como no disponible.
Adicionalmente, si se desea trabajar con listas ordenadas el algoritmo de
insercin debera alojar a los nuevos elementos en la posicin o con la referencia
adecuada.
Algunas soluciones, ms o menos ingeniosas, permiten tratar estas
circunstancias. La figura 3.3 muestra un ejemplo basado en una matriz de registros.
0 1
1 10 77 12 26 21 11 13 18
2 3 4 7 6 0 8 5 0
96 LISTAS
ESTRUCTURAS DE DATOS
10
12
13
21
Memoria esttica
Lista
10
21
1
Memoria dinmica
12
13
ESTRUCTURAS DE DATOS
LISTAS 97
lista1
Variable
esttica
nombre
10
inicio
Clase Lista
dato
13
sig
NodoLista
dato
sig
NodoLista
21
null
dato
sig
NodoLista
98 LISTAS
ESTRUCTURAS DE DATOS
Los siguientes algoritmos se han desarrollado considerando implementaciones de la lista como estructuras
dinmicas. A efectos de la realizacin de prcticas se utiliza la sintaxis del lenguaje java.
ESTRUCTURAS DE DATOS
LISTAS 99
En la primera llamada recursiva, nodoLista es el contenido del campo sig del nodo de
clave 10. Es decir, una referencia al nodo de clave 13.
En la segunda, nodoLista es el contenido del campo sig del nodo de clave 13. Es decir,
una referencia al nodo de clave 21.
En la tercera, nodoLista es el contenido del campo sig del nodo de clave 21, es decir,
null. Cuando se ejecuta esta tercera llamada se cumple la condicin de finalizacin y, en
consecuencia, se inicia el proceso de vuelta. Ahora nodoLista toma sucesivamente los
valores:
o Referencia al nodo de clave 21 (campo sig del nodo de clave 13).
o Referencia al nodo de clave 13 (campo sig del nodo de clave 10).
o Referencia al nodo de clave 10 (el primer elemento de la lista).
El recorrido de una lista es una operacin necesaria en los algoritmos de eliminacin
y, en muchos casos, tambin en los de insercin. La condicin de finalizacin pesimista
consiste en alcanzar el final de la lista (nodoLista == null). No obstante, normalmente se
produce una terminacin anticipada que se implementa no realizando nuevas llamadas
recursivas.
En los siguientes apartados se van a presentar los diferentes tipos de listas, sobre las
cuales se explican algunos algoritmos bsicos: inicializacin, bsqueda, insercin y
eliminacin.
100 LISTAS
ESTRUCTURAS DE DATOS
apilar
5
4
1
7
2
cima
fondo
null
Pila
apilar
desapilar
ESTRUCTURAS DE DATOS
LISTAS 101
package tadPila;
//En esta clase se define el nodo:
class NodoPila {
// Constructor
NodoPila (int elemento, NodoPila n) {
dato = elemento;
siguiente = n;
}
// Atributos accesibles desde otras rutinas del paquete
int dato;
NodoPila siguiente;
}
102 LISTAS
ESTRUCTURAS DE DATOS
3.5.2. Colas.
Como se ha visto en el tema 2, una cola es una agrupacin de elementos de
determinada naturaleza o tipo (datos de personas, nmeros, procesos informticos,
automviles, etc.) entre los que existe definida una relacin de orden. En funcin del
tiempo, pueden llegar a la cola o salir de ella algunos elementos de dicha naturaleza
(operaciones/acciones). En consecuencia el estado de la cola vara.
En una cola (comportamiento FIFO -First In First Out-) se respeta como criterio de
ordenacin el momento de la llegada: el primero de la cola, ser el que primero lleg a ella
y, en consecuencia, el primero que saldr, y as sucesivamente. Las figuras 2.14 y 2.15
ilustran respectivamente el concepto de cola de nmeros enteros y su implementacin
mediante una lista dinmica.
desencolar
2 1 4 3 5
encolar
fin
Cola
2
desencolar
null
encolar
ESTRUCTURAS DE DATOS
LISTAS 103
package tadCola;
//En esta clase se define el nodo:
class NodoCola {
// Constructor
NodoCola (int elemento, NodoCola n) {
dato = elemento;
siguiente = n;
}
// Atributos accesibles desde otras rutinas del paquete
int dato;
NodoCola siguiente;
}
104 LISTAS
ESTRUCTURAS DE DATOS
Se propone otra solucin basada en una lista circular (apartado 3.7.1.) en la que la referencia a la lista es la
del ltimo nodo. De esta forma tambin se tiene acceso a ambos extremos (cola: ltimo y cola.sig: primero).
ESTRUCTURAS DE DATOS
LISTAS 105
106 LISTAS
ESTRUCTURAS DE DATOS
3.6.1.1. Bsqueda.
Se trata de localizar una clave de valor determinado (pasado como argumento) sin
entrar en consideraciones de qu se va a hacer con ella. En cualquier caso este tipo de
algoritmos no tienen efecto alguno sobre la estructura (no se modifica el nmero de nodos).
En principio la condicin de finalizacin se consigue al llegar al final de la lista
(inicio == null). Se produce una terminacin anticipada en caso de encontrar la clave
buscada.
El siguiente algoritmo es un ejemplo de mtodo booleano de objeto (busqueda) que
recibiendo como argumento un dato (elem) devuelve true en caso de encontrar el elemento,
y false si el elemento no est en la lista.
static boolean busqueda (NodoLista nodoLista, int x) {
boolean resul = false;
if (nodoLista != null)
if (nodoLista.clave == x)
resul = true;
else resul = busqueda (nodoLista.sig, x);
return resul;
}
public boolean busqueda (int x) {
return busqueda (inicio, x);
}
3.6.1.2.Insercin.
El efecto de este tipo de algoritmos es incrementar el nmero de nodos. Para crear un
nuevo nodo es necesario conocer tanto la naturaleza de la estructura utilizada (esttica o
dinmica) como los recursos del lenguaje de programacin empleado. Por ejemplo, en el
caso de las estructuras dinmicas en java el mtodo es el siguiente:
NodoLista aux = new NodoLista (dato, null);
De esta forma se crea un nuevo nodo (apuntado por aux) cuya clave contiene el dato a
insertar. De momento el nuevo nodo no est enlazado en la lista. El punto de insercin
depender del criterio que se establezca.
Lo ms sencillo y eficiente es insertar el nuevo nodo al principio de la lista. El
resultado ser el ilustrado en la figura 3.7.
ESTRUCTURAS DE DATOS
inicio
aux
LISTAS 107
Situacin inicial
10
13
11
21
null
null
Insercin al principio
11
inicio
10
13
21
inicio
Situacin final
11
10
13
21
null
El problema que tendra este algoritmo es que, dado que no comprueba si el elemento
existe o no en la lista, podr insertar claves repetidas. Para evitarlo, se podra realizar
primero una bsqueda, y si la clave no estuviese ya en la lista (resultado del mtodo
busqueda (dato) == true), se insertara. Otra posibilidad es realizar la insercin al final de
la lista, comprobando si existe ya algn nodo con la clave buscada, utilizando un algoritmo
recursivo.
Se utilizar un mtodo de objeto de la clase Lista, que invoca a un mtodo static al
que se le pasa como argumento un NodoLista, y devuelve como resultado un NodoLista. En
el mtodo static vamos avanzando por la lista, haciendo las llamadas recursivas con
nodoLista.sig. Si llegamos hasta el final de la lista sin localizar la clave buscada, se crea un
nuevo nodo (aux), y lo devuelve como resultado.
Para enlazar correctamente el nodo, a la vuelta de la recursividad, se hace que
nodoLista.sig apunte al mismo sitio que nos ha devuelto la llamada anterior como resultado.
static NodoLista insertarAlFinal (NodoLista nodoLista, int dato) {
NodoLista aux = nodoLista;
if (nodoLista!= null)
if (nodoLista.clave != dato)
nodoLista.sig = insertarAlFinal (nodoLista.sig, dato);
else System.out.println ("la clave ya existe");
else aux = new NodoLista (dato, nodoLista);
return aux;
}
public void insertar (int dato) {
inicio = insertarAlFinal (inicio, dato);
}
108 LISTAS
ESTRUCTURAS DE DATOS
inicio
Situacin inicial
10
13
21
null
Insercin al final
aux
11
inicio
10
13
21
inicio
Situacin final
10
13
21
null
11
null
Obsrvese que el algoritmo es vlido cuando se recibe una lista inicialmente vaca.
ESTRUCTURAS DE DATOS
LISTAS 109
3.6.1.3.Eliminacin.
Este tipo de algoritmos reduce el nmero de nodos de la estructura. En la mayora de
los lenguajes de programacin deber prestarse atencin especial a liberar el espacio de
memoria de los nodos eliminados para posibles usos posteriores.6
Se procede a recorrer la lista comparando las sucesivas claves con el argumento
recibido (dato).
La condicin de finalizacin pesimista sera alcanzar el final de la lista, lo que
significara que no se habra encontrado la clave a eliminar. No obstante lo normal es que se
produzca una terminacin anticipada en el momento en que se encuentra la clave a
eliminar.
La figura 3.9 ilustra grficamente el mecanismo de eliminacin.
Situacin inicial y localizacin de la clave a borrar
aux
inicio
10
23
21
null
21
null
10
23
inicio
Situacin final
10
21
null
En java no es necesario porque se realiza automticamente, pero en los ejemplos se liberar la memoria no
utilizada.
110 LISTAS
ESTRUCTURAS DE DATOS
inicio
Situacin inicial
10
15
13
21
14
null
inicio
Despus de buscarYSaltar
10
15
13
21
14
null
inicio
Situacin final
13
15
21
14
null
aux
10
ESTRUCTURAS DE DATOS
LISTAS 111
112 LISTAS
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
LISTAS 113
3.6.2.2. Insercin.
En este caso se realiza un tratamiento recursivo recorriendo la lista y terminando
anticipadamente en cuanto se accede a la primera clave de valor superior a la que se desea
insertar (la condicin de terminacin general sera llegar al final de la lista, es decir,
nodoLista == null). El nuevo nodo se deber insertar en la posicin anterior al nodo actual.
La Figura 3.10 ilustra el proceso de insercin de un nodo de clave 11 en una lista en el
momento de la finalizacin anticipada.
Inicio
Inicio
Situacin inicial
10
13
11
10
13
Insercin en su lugar
aux
21
null
21
null
11
Inicio
10
13
21
Inicio
Situacin final
10
11
13
21
null
Obsrvese que el algoritmo es vlido para insertar un elemento nuevo delante del primero, detrs del ltimo
y en una lista vaca. As mismo, contempla el caso de intentar insertar una clave ya existente. Este ltimo caso
tambin produce una situacin de terminacin anticipada.
114 LISTAS
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
LISTAS 115
3.6.2.3. Eliminacin.
Para borrar un elemento, se procede a recorrer la lista comparando las sucesivas
claves con el argumento pasado. La condicin de finalizacin pesimista se alcanza al
llegar al final de la lista, lo que significa que no se ha encontrado ni la clave a eliminar ni
ninguna mayor. No obstante lo normal es que se produzca una terminacin anticipada en el
momento en que se encuentra o bien la clave a eliminar, o bien una clave de valor mayor
que la buscada.
La figura 3.11 ilustra grficamente el mecanismo de eliminacin.
Situacin inicial y localizacin de la clave a borrar
aux
inicio
10
13
21
null
21
null
10
13
inicio
Situacin final
10
21
null
116 LISTAS
ESTRUCTURAS DE DATOS
3.6.2.4.2. Obtencin de una lista con todos los elementos de otras dos.
En este caso hay que recorrer ambas listas en su totalidad. La condicin de
finalizacin ser ((nodoLista1 == null) && (nodoLista2 == null)).
Si una de las listas est vaca, o la otra tiene un elemento menor, lo insertaremos en la
lista resultado y avanzaremos por esa lista. En caso de que ambas listas tengan el mismo
elemento, lo insertaremos y avanzaremos por ambas a la vez.
El proceso presenta tres situaciones (1+2) en funcin de que haya elementos en las dos
listas o en una s y en otra no:
ESTRUCTURAS DE DATOS
LISTAS 117
118 LISTAS
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
LISTAS 119
3.7.1.1.Insercin.
Si se desea realizar la insercin en una lista calificada ordenada circular, hay que
tener en cuenta tres casos diferentes:
La lista est vaca (ultimo == null): deberemos crear un nodo y enlazarlo consigo
mismo.
Vamos a insertar al final, despus del ltimo elemento: tendremos que cambiar la
referencia ultimo.
El elemento se inserta en cualquier otra posicin.
Para realizar la insercin de manera iterativa siguiendo los anteriores criterios, se
puede utilizar el siguiente algoritmo, que crea el nodo y lo enlaza en su hueco
correspondiente, una vez localizado el sitio donde se va a aadir el elemento:
public void insertar (int dato) {
NodoLista aux, actual, anterior;
if (ultimo == null) {
aux = new NodoLista (dato);
ultimo = aux;
ultimo.sig = ultimo;
}
else {
anterior = ultimo;
actual = ultimo.sig;
while ((actual.clave < dato) && (actual != ultimo)) {
anterior = actual;
actual = actual.sig;
}
if (actual.clave != dato) {
aux = new NodoLista (dato);
if ((actual != ultimo) || (actual.clave > dato)) {
aux.sig = actual;
anterior.sig = aux;
}
else if (actual.clave < dato) {
aux.sig= actual.sig;
actual.sig= aux;
ultimo = aux;
}
}
else System.out.println ("error, el elemento ya existe");
}
}
120 LISTAS
ESTRUCTURAS DE DATOS
3.7.1.2.Eliminacin.
Si se va a realizar la eliminacin de un nodo en una lista circular calificada ordenada
de manera iterativa hay que contemplar, como en el caso de la insercin, tres casos
diferentes:
La lista tiene un solo nodo, que deseamos eliminar: deberemos borrar el nodo y apuntar
la lista a null.
Vamos a borrar el nodo final, (el que estamos apuntando con ultimo): tendremos que
cambiar la referencia ultimo.
El elemento se elimina de otra posicin cualquiera.
Para realizar la eliminacin de manera iterativa siguiendo los anteriores criterios, se
puede utilizar el siguiente algoritmo:
public void eliminar (int x){
NodoLista ant, act;
if (ultimo != null) {
ant = ultimo;
act = ultimo.sig;
while (act != ultimo && act.clave < x) {
ant = act;
act = act.sig;
}
if (act.clave == x) {
ant.sig = act.sig;
if (ultimo == act)
if (ultimo != ant)
ultimo = ant;
else ultimo = null;
}
else System.out.println ("No existe el nodo de clave " + x);
}
else System.out.println ("La lista est vaca ");
}
ESTRUCTURAS DE DATOS
LISTAS 121
null
null
Se sugiere al alumno que realice los algoritmos correspondientes para listas calificadas no ordenadas.
122 LISTAS
ESTRUCTURAS DE DATOS
3.7.2.1. Insercin.
Con carcter general la insercin se produce la primera vez que se encuentra un nodo
cuya clave es de un valor superior al dato que se pretende insertar. Esto implica la
modificacin de cuatro referencias (dos en el nuevo nodo, otro en el que apunta al nodo de
clave superior y otro del nodo siguiente que apunta al actual. La figura 3.18 ilustra el
proceso (se supone que se intenta insertar un nodo de clave 5 en el momento de haber
encontrado un nodo de clave superior, 6).
inicio
null
Aux
inicio
null
null
Nuevo
null
La terminacin del proceso debe realizarse cuando se alcance el nodo cuyo campo sig
sea null (inicio.sig == null) pues en caso de progresar ms all se perdera la referencia al
nodo anterior. Si la clave que queremos insertar es superior a la ltima de la lista, habr que
insertarla en este momento, a la derecha del ltimo nodo. El cdigo siguiente indica como
implementarlo y la figura 3.19 ilustra grficamente el proceso.
nuevo.sig = null;
nuevo.ant = inicio;
inicio.sig = nuevo;
ESTRUCTURAS DE DATOS
LISTAS 123
null
2
inicio
4
null
77
aux
inicio
null
aux
77
null
124 LISTAS
ESTRUCTURAS DE DATOS
3.7.2.2.Eliminacin.
Al realizar la eliminacin de manera iterativa, de forma similar que en el caso de la
insercin, se utilizan dos referencias auxiliares: anterior y actual para ir recorriendo la lista.
Adems, necesitamos utilizar la variable booleana encontrado, para salir del bucle si
localizamos el nodo o una clave mayor.
Si hemos encontrado el nodo que queremos eliminar, ser necesario modificar dos
referencias:
El campo ant del nodo que sigue al que se va a eliminar deber apuntar al anterior al
eliminado (actual.sig.ant = actual.ant)
Adems ser necesario distinguir dos casos:
o si queremos borrar el primer nodo, y por tanto debemos modificar inicio,
(inicio = inicio.sig)
o o bien si queremos borrar un nodo intermedio (anterior.sig = actual.sig)
La figura 3.21 ilustra el proceso (eliminacin del nodo de clave 4).
null
inicio
null
actual
null
inicio
null
ESTRUCTURAS DE DATOS
La codificacin es la siguiente:
public void eliminar (int clave) {
NodoLista anterior, actual;
boolean encontrado = false;
anterior= inicio;
actual= inicio;
while ((actual != null) && !encontrado)
if (actual.clave < clave) {
anterior = actual;
actual = actual.sig;
}
else encontrado = true;
if (actual == null)
System.out.println ("Error, el elemento no existe");
else if (actual.clave > clave)
System.out.println ("Error, el elemento no existe");
else if (inicio == actual) {
inicio = inicio.sig;
inicio.ant = null;
}
else {
anterior.sig = actual.sig;
actual.sig.ant = anterior;
}
}
LISTAS 125
126 LISTAS
ESTRUCTURAS DE DATOS
cent
cab
67
Cabecera
Centinela
ESTRUCTURAS DE DATOS
LISTAS 127
Anterior
Actual
cent
cab
Cabecera
Primer elem.
Figura 3.23. Tcnica de cabecera ficticia con valores iniciales de las referencias
anterior y siguiente
El campo clave del nodo apuntado por cab a veces se utiliza para guardar algn tipo
de informacin relativa a la lista, por ejemplo el nmero de elementos de la misma.
La referencia centinela (cent) apunta a otro nodo ficticio (no contiene informacin de
la lista) que se inserta al final. La tcnica del centinela se basa, tanto en las operaciones de
bsqueda y eliminacin como en las de insercin, en copiar antes de la ejecucin del
tratamiento iterativo la clave pasada como argumento en el nodo centinela (cent.clave =
dato). Con esto se consigue simplificar la lgica de las condiciones de finalizacin dado
que siempre se va a encontrar la clave buscada. El cumplimiento de la condicin (actual
== cent), se interpreta en el sentido de que hemos llegado al final de la lista y la clave
buscada no se encuentra realmente en la lista.
Combinando las dos tcnicas anteriores se consigue una gran mejora de rendimiento
en la localizacin de informacin de una lista calificada as como una simplificacin de la
lgica. El consumo adicional de espacio (necesario para alojar los nodos cab y cent) suele
quedar compensado por las ventajas anteriormente expuestas.
3.7.3.1. Creacin.
Para crear una lista con cabecera y centinela (constructor vaco), primero crearemos
los dos nodos ficticios y despus pondremos el centinela como siguiente de la cabecera:
Lista () {
cab = new NodoLista (0);
cent = new NodoLista (0);
cab.sig = cent;
}
128 LISTAS
ESTRUCTURAS DE DATOS
3.7.3.2.Recorrido completo.
Si lo que deseamos hacer es recorrer completamente una lista, como por ejemplo,
para escribir todas las claves que contiene, tendremos que tener en cuenta que las claves
contenidas en la cabecera y el centinela no forman parte de la lista real.
void imprimirLista () {
NodoLista actual;
actual = cab.sig;
while (actual != cent) {
System.out.print (actual.clave + " ");
actual = actual.sig;
}
System.out.println (" FIN");
}
3.7.3.3. Bsqueda.
Para realizar una bsqueda de una clave en la lista con cabecera y centinela,
utilizaremos las referencias auxiliares anterior (que apuntar inicialmente a la cabecera), y
actual (que al principio apuntar al primer nodo de la lista, si ya hay nodos reales en la
lista, y al centinela si est vaca), para recorrer la lista. Al finalizar el recorrido de la lista,
devolveremos true si hemos encontrado la clave buscada, y false en caso de no haberla
localizado (o bien hemos localizado una clave mayor, o bien hemos llegado al centinela).
public boolean busqueda (int dato) {
NodoLista anterior, actual;
boolean resul = false;
anterior = cab;
actual = anterior.sig;
cent.clave = dato;
while (actual.clave < dato) {
anterior = actual;
actual = actual.sig;
}
if ((actual != cent) && (actual.clave == dato))
resul = true;
return resul;
}
3.7.3.4. Insercin.
Para insertar un nuevo elemento en la lista, utilizaremos las referencias auxiliares
anterior y actual para recorrer la lista, as como aux para crear el nuevo nodo. A
continuacin, copiamos la clave buscada en el centinela, y buscamos el hueco donde
insertar el nuevo nodo. Una vez localizado el hueco (si la clave no existe), vamos a realizar
la insercin siempre de la misma forma, ya que siempre insertaremos el nodo en la parte
interior de la lista, nunca en un extremo de la misma.
ESTRUCTURAS DE DATOS
LISTAS 129
3.7.3.5. Eliminacin.
De forma similar a lo que ocurra en la insercin, para eliminar un elemento de la
lista, utilizaremos las referencias auxiliares anterior y actual para recorrer la lista. Una vez
localizada la clave en la lista, verificaremos que no hemos llegado al centinela (en ese caso
la clave no estara en la lista), y procederemos a desenganchar el nodo correspondiente.
public void eliminar (int dato) {
NodoLista anterior, actual;
anterior = cab;
actual = anterior.sig;
cent.clave = dato;
while (actual.clave < dato) {
anterior = actual;
actual = actual.sig;
}
if ((actual == cent) || (actual.clave > dato))
System.out.println ("Error, elemento inexistente");
else anterior.sig = actual.sig;
}
130 LISTAS
ESTRUCTURAS DE DATOS
numNodos = 5
N = 10
Como en las pilas los elementos se insertan y eliminan por el mismo extremo,
consideraremos que el primer elemento se apilar en la posicin 0 de la matriz, el segundo
en la posicin 1, y as sucesivamente.
Utilizaremos la variable miembro numNodos, para saber cul es el ltimo nodo
apilado (numNodos 1, que sera el primero a desapilar), y si hay espacio todava para
apilar nuevos elementos.
Para implementar el TadPila con la misma interfaz que hemos visto en el tema de
Tipos Abstractos de Datos (y en la implementacin mediante una lista enlazada), podramos
utilizar las siguientes variables miembros y constructor:
public class TadPila implements Pila {
int [ ] matriz;
final int N = 10;
int numNodos;
TadPila () {
matriz = new int [N];
numNodos = 0;
}
.....
}
ESTRUCTURAS DE DATOS
LISTAS 131
132 LISTAS
ESTRUCTURAS DE DATOS
numNodos = 5
N = 10
ESTRUCTURAS DE DATOS
LISTAS 133
3.8.1.2.2. Insercin.
Para realizar la insercin en una lista densa calificada ordenada, primero se
comprueba si hay espacio para el nuevo nodo con el mtodo insertar (int dato)
(comprobando si numNodos < N), y en caso afirmativo, se utiliza un mtodo auxiliar
esttico privado (insertar (int i, int dato)), que recorre la lista hasta localizar la posicin en
la que se debe insertar un nuevo elemento.
public void insertar (int dato) {
if (numNodos < N)
insertar (0, dato);
else System.out.println ("la lista est llena");
}
private void insertar (int i, int dato) {
if (i == numNodos) {
matriz [numNodos] = dato;
numNodos++;
}
else if (matriz[i] < dato)
insertar (i+1, dato);
else if (matriz [i] > dato) {
for (int j = numNodos; j > i; j--)
matriz [j] = matriz [j-1];
matriz [i] = dato;
numNodos++;
}
else System.out.println ("la clave ya existe");
}
numNodos = 5
12
numNodos = 6
Sin embargo, si queremos insertar un elemento por la parte central de la lista (por
ejemplo, el 5), desplazaremos todos los elementos a partir de la posicin 3 una posicin a la
derecha e incrementaremos el valor de numNodos:
0
12
numNodos = 7
134 LISTAS
ESTRUCTURAS DE DATOS
3.8.1.2.3. Eliminacin.
Para realizar la eliminacin en una lista densa calificada ordenada, primero se
comprueba si hay algn elemento con el mtodo eliminar (int dato) (comprobando si
numNodos > 0), y en caso afirmativo, se utiliza un mtodo auxiliar esttico privado
(eliminar (int i, int dato)), que recorre la lista hasta localizar la posicin en la que se debe
eliminar el elemento.
public void eliminar (int dato) {
if (numNodos != 0)
eliminar (0, dato);
else System.out.println ("la lista est vaca");
}
private void eliminar (int i, int dato) {
if (i < numNodos)
if (matriz[i] < dato)
eliminar (i+1, dato);
else if (matriz [i] > dato)
System.out.println ("la clave no existe");
else {
for (int j = i; j < numNodos-1; j++)
matriz [j] = matriz [j+1];
numNodos--;
}
}
12
numNodos = 7
Si queremos eliminar el ltimo elemento (12), tan solo sera necesario cambiar el
valor de numNodos:
0
12
numNodos = 6
Sin embargo, si deseamos eliminar un elemento situado por la parte central de la lista
(por ejemplo, el 4), desplazaramos hacia la izquierda todos los elementos a partir de la
posicin 3 y decrementaramos el valor de numNodos.
0
12
numNodos = 5
ESTRUCTURAS DE DATOS
LISTAS 135
");
136 LISTAS
ESTRUCTURAS DE DATOS
clave
sig
1 10 77 12 26 21 11 13 18
2 3 4 7 6 0 8 5 0
12
13
21
ESTRUCTURAS DE DATOS
LISTAS 137
class NodoLista {
int clave, sig;
NodoLista () {
clave = 0;
sig = 0;
}
}
public class Lista {
final int NULL = 0, N = 9;
NodoLista [] matriz;
Lista () {
int i;
matriz = new NodoLista [N];
for (i = 0; i < N-1; i++) {
matriz [i] = new NodoLista ();
matriz [i].sig = i + 1;
}
matriz [i] = new NodoLista ();
}
....
}
Utilizaremos la clase NodoLista para incluir los campos clave y sig. La clase Lista
contendr las constantes N (con valor 9, que representa el nmero mximo de nodos de la
lista + 1) y NULL (con valor 0, que representa la posicin vaca, equivalente a null en las
listas enlazadas); adems incluye la variable miembro matriz (que es un vector de
elementos de la clase NodoLista), que contiene la lista vaca.
A continuacin desarrollaremos los mtodos de objeto de la clase Lista.
3.8.2.1.1. Bsqueda.
Para realizar la bsqueda de una clave, recorreremos la matriz siguiendo los enlaces
hasta encontrar una clave mayor o igual que la buscada, o bien llegar hasta el final de la
lista. Se desarrollan dos mtodos: busqueda (int dato), que si la lista no est vaca, invoca a
otro auxiliar recursivo privado (buscar (int pos, int dato) pasndole como argumento la
posicin del primer elemento de la lista. El mtodo buscar se encarga de localizar si el
elemento aparece en la matriz o no:
public boolean busqueda (int dato) {
boolean resul = false;
int pos = matriz [0].clave;
if (pos != 0)
resul = buscar (pos, dato);
return resul;
}
138 LISTAS
ESTRUCTURAS DE DATOS
3.8.2.1.2. Insercin.
Para realizar la insercin en una lista calificada ordenada enlazada sobre matriz,
primero se comprueba en el mtodo insertar (int dato):
si la lista est llena (la lista de huecos estara vaca: matriz [0].sig == NULL),
en cuyo caso se producira un mensaje de error,
o bien si la lista est vaca vaca (comprobando si matriz [0].clave != 0), en
dicho caso se inserta directamente el elemento utilizando el mtodo auxiliar
inser,
en cualquier otro caso, se llama a un mtodo auxiliar esttico privado
(insertar (int pos, int ant, int dato)), que recorre la lista hasta localizar la
posicin en la que se debe insertar un nuevo elemento (y volveramos a
llamar al mtodo auxiliar inser).
public void insertar (int dato) {
if (matriz [0].sig != NULL) {
int pos = matriz [0].clave;
if (pos != 0)
insertar (matriz [0].clave, 0, dato);
else inser (0, 0, dato);
}
else System.out.println ("lista llena");
}
private void insertar (int pos, int ant, int dato) {
if (matriz [pos].clave < dato)
if (matriz [pos].sig != 0)
insertar (matriz [pos].sig, pos, dato);
else inser (0, pos, dato);
else if (matriz [pos].clave > dato)
inser (pos, ant, dato);
else System.out.println ("la clave ya existe");
}
ESTRUCTURAS DE DATOS
LISTAS 139
3.8.2.1.3. Eliminacin.
Para realizar la eliminacin de un elemento, se ha optado por hacer un mtodo
iterativo. Primero se verifica si la lista est vaca, y en caso contrario, se recorre la lista
hasta encontrar la clave buscada (desenganchando el elemento de la lista de claves, y
enlazndolo en la lista de huecos), o bien una clave mayor que la buscada (en cuyo caso se
producir un mensaje de error).
public void eliminar (int d) {
int ant, pos, posAnt = 0;
if (matriz [0].clave != NULL) {
pos = matriz [0].clave;
ant = matriz [pos].clave;
while (ant < d) {
posAnt = pos;
pos = matriz [pos].sig;
ant = matriz [pos].clave;
}
if (ant == d) {
if (pos == matriz [0].clave)
matriz [0].clave = matriz [pos].sig;
else matriz [posAnt].sig = matriz[pos].sig;
matriz [pos].sig = matriz [0].sig;
matriz [0].sig = pos;
}
else System.out.println ("la clave no existe");
}
else System.out.println ("Error. La lista est vaca");
}
140 LISTAS
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
LISTAS 141
142 LISTAS
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
LISTAS 143
TEMA 3 ................................................................................................................................ 93
3.1.
3.2.
3.3.
3.4.
3.5.
3.6.
3.7.
3.8.
3.9.
3.5.2.
3.6.2.
3.7.2.
3.7.3.
3.8.2.
ESTRUCTURAS DE DATOS
RBOLES 143
TEMA 4.
RBOLES
4.1. CONCEPTOS GENERALES.
Un rbol es una estructura de datos ramificada (no lineal) que puede representarse
como un conjunto de nodos enlazados entre s por medio de ramas. La informacin
contenida en un nodo puede ser de cualquier tipo simple o estructura de datos.
Los rboles permiten modelar diversas entidades del mundo real tales como, por
ejemplo, el ndice de un libro, la clasificacin del reino animal, el rbol genealgico de un
apellido, etc.
La figura 4.1. muestra un ejemplo de estructura en rbol (la numeracin de los nodos
es arbitraria). Se entiende por topologa de un rbol a su representacin geomtrica.
1
10
11
12
144 RBOLES
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
RBOLES 145
Finalmente, indicar que se dice que un rbol es completo cuando todos sus nodos
(excepto las hojas) tienen el mismo grado y los diferentes niveles estn poblados por
completo. A veces resulta necesario completar un rbol aadindole nodos especiales. La
figura 4.2. representa el resultado de completar el rbol de la figura 4.1. (en la figura los
nodos especiales aparecen sombreados)
1
10
11
12
g
g
1
1
146 RBOLES
ESTRUCTURAS DE DATOS
25
20
10
45
0
15
3
1
1
20
5
2
2
5
4
*
3
25
*
*
4
45
*
*
5
10
*
*
ESTRUCTURAS DE DATOS
RBOLES 147
Puntero al rbol
raz
20
15
25
10
5
*
45
4.2.2.1.Recorridos.
Se entiende por recorrido el tratamiento realizado para acceder a los diferentes nodos
de un rbol. El recorrido puede afectar a la totalidad de los nodos del rbol (recorrido
completo), por ejemplo si se desea conocer el nmero de nodos, o finalizar anticipadamente
en funcin de determinada/s circunstancia/s, por ejemplo al encontrar el valor de una clave
determinada.
En cualquier caso, el recorrido se puede realizar basndose en las siguientes
modalidades:
Los siguientes algoritmos se han desarrollado en Java considerando la implementacin del rbol por medio
de una estructura dinmica. A efectos de la realizacin de prcticas se utiliza la sintaxis del lenguaje Java.
148 RBOLES
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
RBOLES 149
Puede realizarse indistintamente con cualquiera de las modalidades de recorrido, en la solucin propuesta se
hace un recorrido en preorden.
150 RBOLES
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
RBOLES 151
4.2.2.2.Bsqueda.
Hasta ahora se han presentado distintos modos de recorrer el rbol completo. En
algunas ocasiones, ser necesario finalizar antes de completar el recorrido, no realizando
posteriores llamadas recursivas. En algunos casos se requiere el empleo de un argumento
adicional (pasado por referencia) que permita evitar, en su caso, la ejecucin de posteriores
llamadas recursivas.
El siguiente ejemplo implementa un mtodo (bsqueda) que recibe como argumentos
un rbol y una clave (ambos pasados por valor) y devuelve true si dicha clave se encuentra
en el rbol, y false en caso contrario.
Se procede a recorrer en principio todo el rbol. Cada vez que se alcanza un extremo
(llamada desde una hoja) se cumple la condicin arbol == null y el mtodo devuelve el
valor false. Si a lo largo del recorrido se encuentra la clave buscada, el mtodo devolver el
puntero a dicho nodo, y ya no se realizan nuevas llamadas recursivas, siendo este valor el
que se entrega al mdulo que llam a el mtodo, lo que evita el error que supondra
alcanzar la condicin de finalizacin en el extremo derecho del rbol (hijo derecho de la
ltima hoja).
Por razones de eficiencia se realiza un recorrido en preorden.
static boolean busqueda (NodoArbol arbol, int dato) {
boolean resul = false;
if (arbol != null)
if (arbol.clave == dato)
resul = true;
else {
resul = busqueda (arbol.iz, dato);
if (!resul)
resul = busqueda (arbol.de, dato);
}
return resul;
}
public boolean busqueda (int dato) {
return busqueda (raiz, dato);
}
152 RBOLES
ESTRUCTURAS DE DATOS
void main
new Arbol
new Arbol
new Arbol
new Arbol
new Arbol
new Arbol
new Arbol
(String [] args) {
(1) ;
(3) ;
(5) ;
(7) ;
();
();
();
ESTRUCTURAS DE DATOS
RBOLES 153
Recorrido en amplitud.
El algoritmo explicado para el recorrido en amplitud en el apartado 3.2.2.2., permite
recorrer el rbol en amplitud, sin embargo, no se tiene constancia del nivel en que se
encuentran los nodos a los que se accede.
En caso de que esto sea necesario debera modificarse, bien la estructura de la cola
aadiendo el nivel, o bien el algoritmo visto anteriormente de manera que su estructura sea
una iteracin anidada en dos niveles.
154 RBOLES
ESTRUCTURAS DE DATOS
Si se puede cambiar la estructura de la cola, podra utilizarse una cola con el siguiente
tipo de elementos:
TElemento (NodoArbol a, int n) {
nivel = n;
arbol = a;
}
NodoColaN (NodoArbol a, int n, NodoColaN sig) {
elem = new TElemento (a, n);
siguiente = sig;
}
ESTRUCTURAS DE DATOS
RBOLES 155
156 RBOLES
ESTRUCTURAS DE DATOS
4.2.3. Ejemplo.
A continuacin se desarrolla un mtodo que intenta verificar si dos rboles son
iguales o no.
static boolean iguales (NodoArbol a, NodoArbol b) {
boolean resul ;
if ((a == null) && (b == null))
resul = true;
else if ((a == null) || (b == null))
resul = false;
else if (a.clave == b.clave)
resul = iguales(a.iz, b.iz) && iguales (a.de, b.de);
else resul = false;
return resul;
}
static boolean iguales (Arbol a1, Arbol a2) {
return iguales (a1.raiz, a2.raiz);
}
ESTRUCTURAS DE DATOS
RBOLES 157
20
35
10
22
15
24
12
18
17
158 RBOLES
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
RBOLES 159
4.3.2.2. Eliminacin.
La eliminacin de un nodo en un rbol binario de bsqueda implica una
reorganizacin posterior del mismo con el objeto de que una vez eliminado el nodo el rbol
mantenga su naturaleza de bsqueda. Para ello se procede de la manera siguiente:
15
10
20
12
17
13
25
18
23
Tenemos que borrar un nodo hoja: procedemos a borrarlo directamente. Por ejemplo, si
en el rbol de la figura 4.11, queremos borrar la clave 13, el resultado sera la figura
4.12.
15
10
20
12
17
25
18
23
160 RBOLES
2.
ESTRUCTURAS DE DATOS
Hay que borrar un nodo con un nico descendiente: ascendemos a su descendiente. Por
ejemplo, si en el rbol de la figura 4.12, queremos borrar la clave 17, el resultado sera
la figura 4.13.
15
10
20
12
18
25
23
Figura 4.10. Borrado de un nodo con un solo hijo en un rbol binario de bsqueda
3.
El nodo que queremos borrar tiene dos hijos. En este caso, sustituimos la clave a borrar
por la clave del mayor de sus descendientes menores (el nodo ms a la derecha del
subrbol izquierdo), y borramos el nodo que tena anteriormente dicha clave. Para
poder hacer esto:
Nos situamos en la raz del subrbol izquierdo de dicho nodo.
Se desciende por la derecha de dicho subrbol hasta encontrar un nodo (n) sin
descendiente derecho.
Se sustituye la clave a eliminar por la del nodo n.
Se elimina el nodo n6. Por ejemplo, si se desea eliminar la clave 10 del rbol
representado en la figura 4.13., sustituiremos dicha clave por la mayor de sus
descendientes menores (el 7), y borraremos el nodo con la clave 7 (el nodo que
deberemos borrar ahora ser en este caso un nodo hoja, aunque tambin podramos
encontrarnos con un nodo con un solo descendiente). Como resultado, obtendremos
el rbol que se muestra en la figura 4.14.
15
20
12
17
25
23
Figura 4.11. Borrado de un nodo con dos hijos en un rbol binario de bsqueda.
A continuacin se muestra el cdigo del algoritmo de eliminacin.
Obsrvese que se elimina la clave deseada pero no el nodo fsico que la albergaba sino otro.
ESTRUCTURAS DE DATOS
RBOLES 161
4.3.3. Ejemplo.
Dado un rbol binario de bsqueda y una lista enlazada por medio de punteros,
implementar un algoritmo en Java que, recibiendo al menos un rbol y una lista ordenada
ascendentemente, determine si todos los elementos del rbol estn en la lista.
Implementaremos un mtodo booleano con el arbol y la lista como argumentos.
Como la lista est ordenada ascendentemente, y el rbol binario es de bsqueda,
realizaremos un recorrido del rbol en orden central, parando en el momento en que
detectemos algn elemento que existe en el rbol, pero no en la lista.
162 RBOLES
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
RBOLES 163
0
10
3
2
1
20
6
4
2
5
-1
-1
3
15
-1
-1
4
45
5
-1
5
15
-1
-1
6
0
-1
-1
7
0
-1
-1
8
0
-1
-1
9
0
-1
-1
10
20
15
45
25
164 RBOLES
ESTRUCTURAS DE DATOS
Recorrido en post-orden:
En el mtodo recursivo privado ordenCentralAux, se escriben las claves del rbol en
post orden: primero se avanza por la izquierda (haciendo la llamada con matriz [i].izq, ),
luego por la derecha (matriz [i].der) y por ltimo escribimos la clave del nodo (matriz
[i].clave).
private void postOrden (int i) {
if (i != NULL) {
postOrden (matriz [i].izq);
postOrden (matriz [i].der);
System.out.print (matriz [i].clave+", ");
}
}
public void postOrden () {
postOrden (0);
}
ESTRUCTURAS DE DATOS
RBOLES 165
4.4.1.2. Bsqueda.
Para realizar una bsqueda en un rbol binario de bsqueda sobre matriz, es necesario
comprobar primero si no hemos llegado a un nodo vaco (if (i != NULL), en cuyo caso
devolveremos false como resultado), y luego vamos avanzando por la rama
correspondiente:
si la clave es mayor que la buscada seguiremos por la izquierda (resul = busqueda
(matriz [i].izq, dato)),
si la clave es menor que la buscada seguiremos por la derecha (resul = busqueda
(matriz [i].der, dato)),
y si la clave es la que estamos buscando, pararemos devolviendo como resultado
true.
public boolean busqueda (int dato) {
return busqueda (0, dato);
}
private boolean busqueda (int i, int dato) {
boolean resul = false;
if (i != NULL)
if (matriz [i].clave > dato)
resul = busqueda (matriz [i].izq, dato);
else if (matriz [i].clave < dato)
resul = busqueda (matriz [i].der, dato);
else resul = true;
return resul;
}
166 RBOLES
ESTRUCTURAS DE DATOS
4.4.1.3. Insercin.
Para realizar la insercin en un rbol binario de bsqueda sobre matriz, es necesario
comprobar primero si todava no est lleno el rbol (comprobando la variable miembro
numNodos). Si se va a insertar en un rbol vaco, la insercin se har en el mtodo de
llamada (insertar):
public void insertar (int dato) {
if (numNodos == 0){
matriz [0].clave =dato;
numNodos++;
}
else if (numNodos < N)
insertar (0, dato);
else System.out.println ("rbol lleno");
}
Para el resto de los nodos utilizaremos el mtodo recursivo insertarAux. Para ello,
primero habr que localizar dnde deberamos insertar el nodo (realizando una bsqueda
guiada por el rbol). Una vez localizado, utilizaremos para el nuevo nodo la primera
posicin libre en la matriz (la posicin numNodos).
private int insertar (int i, int dato) {
int j = NULL;
if (i != NULL)
if (matriz [i].clave > dato) {
j = insertar (matriz [i].izq, dato);
if (j != NULL)
matriz [i].izq = j;
j = i;
}
else if (matriz [i].clave < dato) {
j = insertar (matriz [i].der, dato);
if (j != NULL)
matriz [i].der = j;
j = i;
}
else System.out.println ("la clave ya existe");
else {
j = numNodos;
matriz [j].clave = dato;
numNodos++;
}
return j;
ESTRUCTURAS DE DATOS
RBOLES 167
4.4.1.4. Eliminacin.
Para eliminar una clave, se sigue la misma estrategia que en el apartado 4.3.2.2:
El mtodo recursivo eliminar busca la clave que se desea eliminar.
Si es una hoja se elimina directamente,
Si es un nodo con un hijo se sustituye por el hijo,
Y si es un nodo con dos hijos se llama al mtodo eliminarDosHijos para
sustituir la clave del nodo por la inmediatamente anterior (bajando una vez a
la izquierda y luego todo el rato a la derecha hasta encontrar un nodo sin hijo
izquierdo).
public void eliminar (int dato) {
eliminar (0, dato);
}
private int eliminar (int i, int dato) {
int j = NULL;
if (i != NULL)
if (matriz [i].clave > dato) {
j = eliminar (matriz [i].izq, dato);
if (j != NULL)
matriz [i].izq = j;
j = i;
}
else if (matriz [i].clave < dato) {
j = eliminar (matriz [i].der, dato);
if (j != NULL)
matriz [i].der = j;
j = i;
}
else {
numNodos--;
if (matriz [i].der == NULL) {
j = matriz [i].izq;
borrarNodo (i);
}
else if (matriz [i].izq == NULL) {
j = matriz [i].der;
borrarNodo (i);
}
else {
matriz [i].izq = eliminarDosHijos (matriz [i].izq, i);
j = i;
}
}
else System.out.println ("la clave no existe");
return j;
}
168 RBOLES
ESTRUCTURAS DE DATOS
Por ltimo, si encontramos el nodo a eliminar, en cualquiera de los casos (tenga cero,
uno o dos hijos) se utilizar un mtodo auxiliar (borrarNodo) para desplazar los elementos
que haya a continuacin del nodo eliminado.
private void borrarNodo (int i) {
for (int j = i; j < numNodos; j++) {
matriz [j].clave = matriz [j+1].clave;
matriz [j].der = matriz [j+1].der;
matriz [j].izq = matriz [j+1].izq;
}
for (int j = 0; j <= numNodos; j++) {
if (matriz [j].der >= i)
matriz [j].der = matriz [j].der -1;
if (matriz [j].izq >= i)
matriz [j].izq = matriz [j].izq -1;
}
Por ejemplo, si en el rbol de la figura 4.13., representado por la matriz que aparece a
continuacin, eliminamos el nodo 20, el resultado sera el de la figura 4.14:
Clave
Hijo izquierdo
Hijo derecho
0
10
2
1
1
20
3
4
2
5
-1
-1
3
15
-1
-1
4
45
5
-1
5
25
-1
-1
6
0
-1
-1
7
0
-1
-1
10
20
15
45
25
8
0
-1
-1
9
0
-1
-1
ESTRUCTURAS DE DATOS
RBOLES 169
Resultado:
Clave
Hijo izquierdo
Hijo derecho
0
10
2
1
1
15
-1
3
2
5
-1
-1
3
45
4
-1
4
25
-1
-1
5
25
-1
-1
6
0
-1
-1
7
0
-1
-1
8
0
-1
-1
9
0
-1
-1
10
15
45
25
170 RBOLES
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
RBOLES 171
172 RBOLES
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
RBOLES 173
4.2.
4.2.1.
4.2.2.
4.2.3.
4.3.
4.3.1.
4.3.2.
4.3.3.
4.4.
4.4.1.
4.5.
4.5.1.
ESTRUCTURAS DE DATOS
GRAFOS 173
TEMA 5
Grafos.
5.1. DEFINICIN DE GRAFO
A menudo, cuando se observa la red de rutas areas de un pas interesa observar cmo
ir de una ciudad a otra por las rutas posibles. En consecuencia, se tiene dos conjuntos de
objetos distintos: ciudades y rutas. La Figura 5.1 muestra una manera de representar la
relacin existente entre las ciudades y las rutas, as como la distancia entre las distintas
ciudades.
BILBAO
OVIEDO
445
606
395
MADRID
531
SEVILLA
BARCELONA
622
437
538
ALICANTE
1006
534
207
MELILLA
221
MALAGA
174 GRAFOS
ESTRUCTURAS DE DATOS
En general, un grafo es una manera de representar relaciones que existen entre pares
de objetos. As, un grafo es un conjunto de objetos, llamados vrtices1, y relaciones entre
objetos que establecen una relacin entre pares de vrtices, representadas por aristas.
En el ejemplo anterior, el grafo de la Figura 5.1 representa las conexiones areas entre
ciudades. Los vrtices representaran las ciudades. Las aristas representan las conexiones
entre ciudades y, en este caso, se almacenan la distancia en kilmetros entre las ciudades
que une.
Definicin 1. Un grafo se define como un par G = (V, A), donde V es un conjunto
finito no vaco de vrtices y A es un conjunto de pares de vrtices de V, es decir, las aristas.
Definicin 2. Un grafo G se define como un par ordenado, G = (V, A), donde V es un
conjunto finito y A es un conjunto que consta de dos elementos de V.
ESTRUCTURAS DE DATOS
GRAFOS 175
Sea un grafo G = (V, A), los vrtices u y v pertenecientes a V; y una arista (u,v)
perteneciente a A, se dice que:
Incidencia: la arista (u,v) es incidente con los vrtices u y con v.
Adyacencia: Dos vrtices u y v son adyacentes si existe una arista cuyos vrtices
sean u y v:
o El vrtice u es adyacente a v
o El vrtice v es adyacente desde u
Grado: El grado de un vrtice u es el nmero de vrtices adyacentes a u. Para un
grafo dirigido, el grado de salida de un vrtice u es el nmero de vrtices
adyacentes desde u, mientras que el grado de entrada de un vrtice u es el nmero
de vrtices adyacentes a u. La Figura 5.2 muestra los grados de los vrtices para
un grafo no dirigido y un grafo dirigido.
176 GRAFOS
ESTRUCTURAS DE DATOS
Grafo no dirigido:
Grafo dirigido:
e
c
e
c
Grado (a) = 3
Grado (b) = 3
Grado (c) = 2
Grado (d) = 4
Grado (e) = 4
GradoE (a) = 2
GradoE (b) = 3
GradoE (c) = 0
GradoE (d) = 2
GradoE (e) = 1
GradoS (a) = 1
GradoS (b) = 0
GradoS (c) = 2
GradoS (d) = 2
GradoS (e) = 3
Un grafo simple es aquel que no tiene aristas paralelas o mltiples que unan el mismo
par de vrtices. Un grafo que cuente con mltiples aristas entre dos vrtices se denomina
multigrafo. La Figura 5.3 muestra un ejemplo de grafo simple y de multigrafo, donde
existen aristas paralelas incidentes a los vrtices a y d, y e y d. En este caso, se dice que el
grafo tiene multiplicidad 2 (mximo de aristas paralelas entre dos vrtices).
MULTIGRAFO:
GRAFO SIMPLE:
a
e
c
grado(v) = 2m.
v en G
ESTRUCTURAS DE DATOS
GRAFOS 177
v en G
v en G
En un grafo dirigido, una arista (u,v) contribuye una unidad al grado de
salida de su origen u y una unidad al grado de entrada de su vrtice final v.
Por tanto, la contribucin total de las aristas al grado de salida de los
vrtices es igual al nmero de aristas, y similar para los grados de salida.
Sea G un grafo simple con n vrtices y m aristas, entonces:
Un arco (u,v) se cuenta dos veces en este sumatorio, uno como ENDPOINT
o como
Si G es
no dirigido:
n(n-1)/2.
u y otro
ENDPOINT
V.m
Entonces,
la contribucin total de los arcos a
los grados de los vrtices es dos veces el nmero de los arcos.
o Si G es dirigido: m n(n-1).
5.2.4.
vrtice y termina en vrtice tal que cada arista es incidente a su vrtice predecesor y
sucesor. Es decir, un camino es un sucesin de vrtices de vi V: <v0, v1, v2, vk> que
cumple que:
(vi,,vi+1) A i {0 k-1}.
Se dice que este camino tiene longitud k. Es decir, el nmero de aristas de un camino o
ciclo es la longitud del camino.
Un camino es simple si cada vrtice en el camino es distinto, excepto posiblemente
por el primero y el ltimo vrtice. Un camino simple cumple la siguiente restriccin:
vi vj i {0k}, j {1k-1}, ij
Para todo vrtice x, existe el camino simple <x>, que sera el camino de longitud 0.
Un bucle es un camino de longitud 1 que comienza y termina en el mismo vrtice:
<xi, xi>.
Un ciclo es un camino simple <v0, vk> que cumple las siguientes restricciones:
v0= vk
Si es no dirigido, k = 1 (es un bucle) o k 3.
La Figura 5.4 ilustra estos conceptos para un grafo no dirigido y un grafo dirigido.
178 GRAFOS
ESTRUCTURAS DE DATOS
GRAFO NO DIRIGIDO:
a
GRAFO DIRIGIDO:
a
b
e
e
c
Grafos conexos
e
c
e
c
b
e
e
c
ESTRUCTURAS DE DATOS
GRAFOS 179
GRAFO ETIQUETADO
Museo Municipal
a
3.6
c
1
0.5
2
est-en
estilo
b
2
2
d
diseado-por
2.8
nacido-en
e
5
churrigueresco
estilo
Plaza Mayor
Pedro de Ribera
Madrid
est-en
Salamanca
180 GRAFOS
ESTRUCTURAS DE DATOS
ESTRUCTURAS DE DATOS
5.3.2.
GRAFOS 181
Matriz de adyacencias
b
e
c
a
b
c
d
e
a
0
0
1
1
0
b
1
0
0
1
1
c
0
0
0
0
0
d
0
0
1
0
1
e
0
0
0
0
1
b
e
c
a
b
c
d
e
a
0
1
1
1
0
b
1
0
0
0
1
c
1
0
0
1
0
d
1
0
1
0
0
e
0
1
0
0
0
b
e
VRTICES: a
NDICES:
182 GRAFOS
ESTRUCTURAS DE DATOS
grafo1
true
Variable
esttica
dirigido
maxNodos
numVertices
Clase Grafo
matrizAdy
a
b
c
d
e
a
0
0
1
1
0
b
1
0
0
1
1
c
0
0
0
0
0
d
0
0
1
0
1
e
0
0
0
0
1
ESTRUCTURAS DE DATOS
GRAFOS 183
Antes de ejecutar esta operacin deber asegurarse de que no existe previamente ningn grafo con el mismo
nombre pues su ejecucin hara que se perdiese el contenido del grafo preexistente.
184 GRAFOS
ESTRUCTURAS DE DATOS
b
e
c
a
b
c
d
e
a
0
0
1
1
0
b
1
0
0
1
1
c
0
0
0
0
0
d
0
0
1
0
1
e
0
0
0
0
1
ESTRUCTURAS DE DATOS
GRAFOS 185
El tamao de un grafo viene dado por el nmero de aristas. Debe notarse que las
aristas de un grafo no dirigido se cuentan dos veces.
public int tamano() {
int tm = 0;
for (int i = 0; i < numVertices; i++)
for (int j=0; j < numVertices; j++)
if (matrizAdy [i] [j])
tm++;
if (dirigido)
return tm;
else return tm/2;
}
Para comprobar si un grafo es dirigido o no, basta con comprobar si se trata de una
matriz simtrica, donde la posicin [i, j] = [j, i]:
public boolean esDirigido (Grafo g) {
boolean dir = true;
for (int i = 0; i < numVertices; i++)
for (int j = 0; j < numVertices; j++)
if (matrizAdy [i] [j] != matrizAdy [j] [i])
dir = false;
return dir;
}
186 GRAFOS
5.3.3.
ESTRUCTURAS DE DATOS
Lista de adyacencias
1
4
2
null
null
null
null
null
ESTRUCTURAS DE DATOS
GRAFOS 187
188 GRAFOS
ESTRUCTURAS DE DATOS
La eliminacin de la arista (i, j) consiste en eliminar el nodo con clave j de la lista con
ndice i. Si el grafo es no dirigido, habr que eliminar el nodo con clave i de la lista con
ndice j:
public void eliminaArista (int i, int j) {
if (j >= numVertices)
System.out.println("Error, no existe el vrtice en el grafo");
else {
listaAdy[i].eliminar (j);
if (!dirigido)
listaAdy[j].eliminar (i);
}
}
Dado que la eliminacin de un vrtice supondra cambiar los ndices de los vrtices,
no se va a reproducir esta operacin.
ESTRUCTURAS DE DATOS
GRAFOS 189
190 GRAFOS
ESTRUCTURAS DE DATOS
Por ltimo, el siguiente mtodo imprime la lista de adyacencias para un grafo, dicho
mtodo utiliza el mtodo de clase escribir (Lista):
public void imprimirGrafo () {
System.out.println("Tamao mximo del grafo: " + maxNodos + "\n");
System.out.println("El grafo contiene " + numVertices + " vrtices: \n");
for (int i = 0; i < numVertices; i++) {
System.out.print ("vrtice " + i + ": ");
escribir (listaAdy [i]);
}
}
static void escribir (Lista lista) {
NodoLista aux;
aux = lista.inicio;
while (aux != null) {
System.out.print (aux.clave +", ");
aux = aux.sig;
}
System.out.println ("FIN");
}
ESTRUCTURAS DE DATOS
GRAFOS 191
5.3.4. Consideraciones sobre la implementacin del grafo como matriz o como lista
de adyacencias
La principal ventaja de la matriz de adyacencias es el rpido acceso a la informacin
de aristas. Es una estructura recomendable si se van a realizar consultas frecuentes del
estilo: existe la arista (u, v) en el grafo? O, en caso de ser un grafo valorado, cul es el
coste de la arista (u, v)? Tambin es una estructura recomendable para grafos con pocos
vrtices o bien grafos con muchos vrtices y muchas aristas.
La principal desventaja que presenta la matriz es que requiere un almacenamiento
proporcional al cuadrado del nmero de vrtices del grafo, aunque el grafo contenga
muchas menos aristas de los posibles.
Respecto a las listas de adyacencias, estas ahorran memoria en la representacin de
grafos con muchos vrtices y pocas aristas. Asimismo, si el procesamiento se centra en el
tratamiento de los vrtices adyacentes a uno dado, la lista de adyacencias es preferible a la
matriz.
192 GRAFOS
ESTRUCTURAS DE DATOS
b)
5.4.1.
Recorrido en profundidad
ESTRUCTURAS DE DATOS
GRAFOS 193
Figura 5.14.
Ejemplo de grafo
Se toma el vrtice 4
v4 visitado
(el conjunto de vrtices adyacentes a v4 es 3)
//v3 ya est visitado por lo que se termina el recorrido en profundidad a partir del
vrtice 4.
//v3 ya est visitado por lo que termina el recorrido en profundidad a partir del vrtice 3.
No es posible alcanzar ms vrtices desde v1, de manera que hay que seleccionar un nuevo
vrtice desde el que recomenzar la exploracin en profundidad, se elige el vrtice 5:
v5 visitado (el conjunto de vrtices adyacentes a v5 es 4)
//v4 ya est visitado de manera que se termina el recorrido en profundidad a partir del vrtice 5
--- FIN---
El algoritmo de recorrido en profundidad cuenta con una parte recursiva que recorre
parcialmente un subgrafo a partir de un vrtice de inicio y una parte no recursiva que se
encarga de relanzar el proceso en cada vrtice no visitado. Se utiliza adems un vector de
valores lgicos para marcar los vrtices visitados. Se utilizan los ndices de los vrtices para
iniciar y marcar el proceso de recorrido.
El cdigo en Java para un recorrido en profundidad es el siguiente:
//procedimiento recursivo
public void recorrerProfundidad (Grafo g, int v, boolean [ ] visitados) {
//se marca el vrtice v como visitado
visitados [v] = true;
//el tratamiento del vrtice consiste nicamente en imprimirlo en pantalla
System.out.println (v);
//se examinan los vrtices adyacentes a v para continuar el recorrido
for (int i = 0; i < g.numVertices; i++) {
if ((v != i) && (!visitados [i]) && (g.existeArista (v, i)) )
recorrerProfundidad (g, i, visitados);
}
}
//procedimiento no recursivo
public void profundidad (Grafo g) {
boolean visitados [ ] = new boolean [g.numVertices];
194 GRAFOS
ESTRUCTURAS DE DATOS
for (int i = 0; i < g.numVertices; i++) //inicializar vector con campos false
visitados [i] = false;
for (int i = 0; i < g.numVertices; i++) { //Relanza el recorrido en cada
if (!visitados [i])
//vrtice visitado
recorrerProfundidad (g, i, visitados);
}
}
5.4.2.
En amplitud
ESTRUCTURAS DE DATOS
GRAFOS 195
5.2.
5.2.1.
5.2.2.
5.2.3.
5.2.4.
5.2.5.
5.2.6.
5.3.
5.3.1.
5.3.2.
5.3.3.
5.4.1.
5.4.2.