You are on page 1of 577

,

.',
\
<
<

.
,

<

ESTRUCTURA DE DATOS
Algoritmos, abstraccin y objetos

, <

,
."
r

CONSULTORES EDITORIALES
REA DE INFORMTICA y COMPUTACIN

Antonio Vaquero Snchez


Catedrtico de Lenguajes y Si stemas Informticos
Escuela Superior de Informtica
Universidad Complutense de Madrid
ESPAA

Gerardo Quiroz Vieyra


Ingeniero en Comunicaciones y Electrnica
por la ESIME del Instituto Politcnico Nacional
Profesor de la Universidad Autnoma Metropolitana
Unidad Xochimi1co

MEXICO

.,
orl OS,8 r8CCIOn O e OS

Luis Joyanes Aguilar


Ignacio Zahonero Martnez

Departamento de Lenguajes y Sistemas Informticos


y de Ingeniera de Software
Escuela Universitaria de Informtica
Universidad Pontificia de Salamanca en Madrid

MADRID. BUENOS AIRES. CARACAS. GUATEMALA. LISBOA. MXICO


NUEVA YORK. PANAM. SAN JUAN. SANTAF DE BOGOT. SANTIAGO. sAo PAULO
AUCKLAND HAMBURGO LONDRES. MILN. MONTREAL NUEVA DELHI PARs
SAN FRANCISCO. SIDNEY SINGAPUR ST o LOUIS TOKIO. TORONTO
,

ESTRUCTURA DE DATOS. Algoritmos, abstraccin y objetos


No est permitida la reproduccin total o parcial de este libro, ni su tratamiento in-
formtico, ni la transmisin de ninguna forma o por cualquier medio, ya sea electr-
nico, mecnico, por fotocopia , por registro u otros mtodos, sin el permiso previo
y por escrito de los titulares del Copyright.

DERECHOS RESERVADOS 1998, respecto a la primera edicin en espaol, por


McGRAW-HILL/INTERAMERICANA DE ESPAA, S. A. U.
Edificio Valrealty, 1." planta
Basauri, 17
28023 Aravaca (Madrid)

ISBN: 84-481-2042-6
Depsito legal: M. 16.148-1999

Editora: Concepcin Fernndez Madrid


Diseo de cubierta: Design Ma ster Dima
Compuesto en: Puntographic, S. L.
Impreso en: Cobra, S. L.

IMPRESO EN ESPAA - PRINTED IN SPAIN


..

... . .

.. .

.. .

A los benjamines de nuestras familias, Luis y Paloma

...,-'..
,

..

.
,


Prlogo .................................................................................................................... . XXI

PARTE I. ABSTRACCIN Y PROGRAMACiN. INTRODUCCIN


A LA INGENIERA DE SOFTWARE

Captulo 1. Ingeniera de software: introduccin a la metodologa de cons-


truccin de grandes programas .................................................. .. 3
1.1. IAbstraccin; ...................................................................................... . 4
1.2. Resolucin de problemas y programacin ..................................... . 4
l.3. Herramientas para la resolucin de problemas .............................. .
1.3.1. Diseo descendente ........................................................... . 5
1.3.2. Abstraccin procedimental ............................................... . 6
1.3.3. i Abstraccin de datos ......................................................... . 7
l.3.4. Ocultacin de la informacin .......................................... .. 7
l.3.5. I Programacin orientada a objetos ................................... .. 7
1.4. Factores en la calidad del software ............................................... .. 8
l.5. El ciclo de vida del software ......................................................... .. 9
1.5.1. Anlisis .............................................................................. . lo:"""'"
1.5.2. Diseo ................................................................................ . 11
1.5.3. Implementacin (codificacin) ........................................ .. 12
. .. Pmebas e In
154 ' tegraclon " ........................................................ . 13
1.5.5. Verificacin ....................................................................... . 13
1.5.6. Mantenimiento .................................................................. . 14
l.5.7. La obsolescencia: programas obsoletos .......................... . 15
l.5.8. Iteracin y evolucin del software ................................... . 15
1.6. Mtodos formales de verificacin de programas ........................... . 16
1.6.1. Aserciones (asertos) ......................................................... . 16
1.6.2. Precondiciones y postcondiciones ................................... . 17
l.6.3. Reglas para prueba de programas .................................... . 17
l.6.4. Invariantes de bucles ......................................................... . 19
l.6.5. Etapas a establecer la exactitud (correccin) de un pro-
grama ................................................................................. . 22
l. 7. Principios de diseo de sistemas de software ................................ . 23
1.7.1. Modularidad mediante diseo descendente ..................... . 23
1.7.2. Abstraccin y encapsulamiento ...................................... .. 24
1.7.3. Modificabilidad ......................................... .............. ......... .. 25

"
VII

viii Estructura de datos

1.7.4. Comprensibilidad y fiabilidad ......................................... . 26


1.7.5. Interfaces de usuario ........................................................ . 26
1. 7 .6. Programacin segura contra fallos .................................. . 26
1.7.7. Facilidad de uso ............................................................... . 27
1.7.8. Eficiencia .......................................................................... . 27
1.7.9. Estilo de programacin, documentacin y depuracin ... 28
1.8. Estilo de programacin ............................... o., 28
1.8.1. Modularizar un programa en subprogramas ................. .. 29
1.8.2. Evitar variables globales en subprogramas .................... . 29
1.8.3. Usar nombres significativos para identificadores .......... . 30
1.8.4. Definir constantes con nombres ...................................... . 31
1.8.5. Evitar el uso de got o ..................................................... . 31
1.8.6. Uso adecuado de parmetros valor/variable .................. .. 31
1.8.7. U so adecuado de funciones ............................................ .. 32
1.8.8. Tratamiento de errores ..................................................... . 32
1.8.9. Legibilidad ~ ...................................................................... . 33
1.9. La documentacin ................................................................. ~ .......... . 35
1.9.1. Manual del usuario ........................................................... . 35
1.9.2. Manual de mantenimiento (documentacin para progra-
madores) ........................................................................... . 36
1.9.3. Documentacin interna .................................................... . 37
1.9.4. Documentacin externa .................................................. .. 37
1.9.5. Documentacin del programa ........................................ .. 37
l. 10. Depuracin .................................... oo 38
1.1 0.1. Localizacin y reparacin de errores .............................. . 39
l.l 0.2. Los equipos de programacin ........................................ .. 41
1.11. . Diseo de algoritmos ....................................................................... . 42
1.12. Pruebas (testing) .............................................................................. . 42
1.12.1. Errores de sintaxis (de compilacin) .............................. . 44
l.l2.2. Errores en tiempo de ejecucin ...................................... .. 45
1.12.3. Errores lgicos ................................................................. . 45
1.12.4. El depurador ..................................................................... . 46
1.13. Eficiencia ......................................................................................... . 46
l.l3.1. Eficiencia versus legibilidad (claridad) .......................... . 49
1.14. Transportabilidad ............................................................................. . 49
, Resumen ........................................................................................................ . 49
, ..
,, E]erCIClos ...................................................................................................... . 50
Problemas ...................................................................................................... . 51
.
,

Captulo 2. Construccin de grandes programas: mdulos versus uni-


dades .................. ......... .................. ........................ ..... ....................... 53
2. l. Concepto de unidad.... ............. ................... ...................................... 54
2.2. Estructura de una unidad.................................................................. 54
,

Contenido ix
.
2.2.1. Cabecera de la unidad ....................................................... . 55
2.2.2. Seccin de interfaz ............................................................ . 55
2.2.3. Seccin de implementacin .............................................. . 56
2.2.4. Seccin de iniciacin (inicializacin) ............................. . 57
2.2.5. Ventajas de las unidades ................................................... . 57
2.3. Creacin de unidades ...................................................................... . 57
2.3.1. Construccin de grandes programas ................................ . 61
2.3.2. Uso de unidades ................................................................ . 61
2.3.3. Declaraciones/infonnacin pblica y privada ................. . 62
2.3.4. Clusula uses en la seccin de implementacin .......... . 63
2.4. Utilizacin de unidad estndar ....................................................... . 65
2.4.1. Unidad System ................................................................ 66
2.4.2. Unidad Crt ....................................................................... . 66
2.4.3. Unidad DOS ....................................................................... . 67
2.4.4. Unidad Printer ............................................................. . 68
2.4.5. Unidad Graph ................................................................... 68
2.5. Situacin de las unidades en sus discos: dnde busca Turbo Bor-
land Pascal las unidades? ................................................................. 69
2.6. Identificadores idnticos en diferentes unidades ............................ 71
2.7. Sntesis de unidades ......................................................................... 71
2.7.1. Estructura de una unidad ............................ ............ ........... 72
2.7.2. Excepciones en la escritura de unidades .......................... 73
2.7.3. Compilacin de unidades .................................................. 74
2.8. Otros mtodos de estructurar programas: inclusin, solapamientos
y encadenamiento ............................................................................ .

74
2.8.1. Los archivos de inclusin o incluidos (include) ............. . 74
2.8.2. Los solapamientos (overlays) ................................ :.......... . 75
2.8.3. La unidad OverIay (generacin de solapamientos) ......... . 76
2.8.4. Encadenamiento de archivos compilados ........................ . 79
Resumen .............................................................,......................................... . 79
..

E1erClClOS .................................................................................................... . 79
Referencias bibliogrficas ......................................................................... . 82

r
Captul 3.,
I Abstraccin de datos: tipos abstractos de datos y objetos ....... 83

3.1. El papel (el rol) de la abstraccin .................................................. .


3.1.1. La abstraccin como un proceso mental naturaL ........... .
3.1.2. Historia de la abstraccin del software ............................ .
3. 1.3. Procedimientos .................................................................. .
3.1.4. Mdulos ............................................................................. .
3.1.5. Tipos abstractos de datos .................................................. .
3.1.6. Objetos ............................................................................... .
3.2. Un nuevo paradigma de programacin .......................................... .
X Estructura de datos

3.3.
,.'.NI odularldad
. .
..................................................................................... . 89
3.3.1. La estructura de un mdulo ............................................. . 90
3.3.2. Reglas de modularizacin ............................................... . 91
3.4. Diseo de mdulos .......................................................................... . 94
3.4.1. Acoplamiento de mdulos .............................................. .. 94
3.4.2. Cohesin de mdulos ..................................................... .. 95
3.5. Tipos de datos ........................................ o 96
3.6. Abstraccin en lenguajes de programacin ................................... . 97
3.6.1. Abstracciones de control ................................................. . 97
3.6.2. Abstracciones de datos ................................................... .. 98
3.7. Tipos abstractos de datos (TAD) .................................................... . 99
3.7.1. Ventajas de los tipos abstractos de datos ........................ . 101
3.7.2. Implementacin de los TAD .......................................... .. 101
3.8. Tipos abstractos de datos en Turbo Borland Pascal ...................... . 102
3.8.1. Aplicacin del tipo abstracto de dato pila ..................... . 104
3 ..
9 . , b'
Orlentaclon a o ~etos ...................................................................... . 105
3.9.1. Abstraccin ...................................................................... . 107
. 3.9.2. Encapsulacin .................................................................. . 107
3.9.3. Modularidad ..................................................................... . 107
3.9.4. Jerarqua .................................................. ......................... . 108
3.9.5. Polimorfismo .................................................................... . 108
3.9.6. Otras propiedades ............................................................ . 109
3.10. Reutilizacin de software ............................................................... .. 110
3.11. Lenguajes de programacin orientados a objetos .......................... . 111
3.11.1. Clasificacin de los lenguajes orientados a objetos ...... . 112
3.12. Desarrollo tradicional frente a desarrollo orientado a objetos .... .. 116
3.13. Beneficios de las tecnologas de objetos ....................................... .. 118
Resumen ........................................................................................................ . 120
..
EjerCIClOS ...................................................................................................... . 120

PARTE 11. FUNDAMENTOS BSICOS DE ESTRUCTURAS DE DATOS


Y TIPOS ABSTRACTOS DE DATOS

Captulo 4. Estructuras de datos dinmicas: punteros ................................. 125


4.1. ' Estructuras de datos dinmicas ............ .............. .................... .......... 125
4.2. f Punteros (apuntadores) .................................................................... 127
4.2.1. Declaracin de punteros .................................................... 127
4.3. Operaciones con variables puntero: procedimientos New y Dis-
pose ....................................... A 130
4.3.1. Procedimiento New ........................................................... . 130
. 4.3.2. Variables de puntero con registros ................................... . 134
!,
4.3.3. Iniciacin y asignacin de punteros ................................. . 135
i

Contenido xi

I
4.3.4. Procedimiento Di s po s e ............. l37
4.3.5. Constante ni 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . l38
4.3.6. Naturaleza dinmica de los punteros ............................... . 138
4.3.7. Comparacin de punteros ................................................. . l39
4.3.8. Paso de punteros como parmetros .................................. . 141
4.4. El tipo genrico puntero (Pointer) .................................................. . 142
4.5. La asignacin de memoria en Turbo Borland Pascal .................... . 142
4.5.1. El montculo (heap) y los punteros .................................. .

143
4.5.2. Mtodos de asignacin y liberacin de memoria ............ . 145
4.5.3. New y Dispose ............................................................... 145
4.5.4. Mark y Release ........................................................... . 146
4.5.5. GetMem y FreeMem ...................................................... . 146
4.5.6. MemAvail y MaxAvail ............................................... . 147
Resumen ..................................................................................................'... . 148
..
EJerCICIOS ................................................................................ 149
Problemas ................................................................................................... .

152

Captulo 5. IListas -enlazadas: el TAD lista enlazada ...................................... 153


5.1. Especificacin formal del tipo abstracto de datos lista ................. . 153
5.2. Implementacin del TAD lista con estructuras estticas .............. . 156
5.3. Implementacin del TAD lista mediante variables dinmicas ...... . 159
5.4. Iniciar una lista enlazada ................................................................ . 162
5.5. Bsqueda en listas enlazadas .......................................................... . 162
5.6. Operaciones de direccin: siguiente, anterior, ltimo ................... . 163
5.7. Insercin de un elemento en una lista ............................................ . 164
5.8. Supresin de un elemento de una lista ........................................... . 166
5.9. Recorrido de una lista ..................................................................... . 168
5.10. Lista ordenada ................................................................................. . 168
5.10.1. Implementacin de una lista ordenada ............................ . 168
5.10.2. Bsqueda en lista ordenada .............................................. . 170
Resumen ........................................................................................................ . 175
..
EJerclclos ...................................................................................................... . 176
Problemas ...................................................................................................... . 177

Captulo 6. \ Listas doblemente enlazadas ......................................................... 179


6.1. Especificacin de lista doblemente enlazada .................................. 179


6.2. Implementacin de una lista doblemente enlazada mediante va-
. bl es d'
rla .
lnamlcas ............................................................................. . 180

6.2.1. Creacin de nodos en la lista ........................................... . 181
1
6.2.2. Eliminacin de nodo ......................................................... . 184
6.3. Una aplicacin resuelta con listas doblemente enlaZadas ............. . 186
6.4. Implementacin de una lista circular mediante variables dinmicas ... . 195
t

xii Estructura de datos

6.5. Implementacin de una lista circular mediante variables dinmicas ... . 196
6.6. Implementacin de listas circulares con doble enlace .................. . 200
Resumen .............................................................. o 203
..
EJerclclos .................................................................................................... . 204
Problemas ................................................................................................... . 204
Captulo 7. IPilas: el TAD pi 1 a ......................................................................... 207
7.1. Especificacin formal del tipo abstracto de datos pila ................. . 207
7.2. Implementacin del TAD pila con arrays .................................. . 208
7.3. Implementacin del TAD pi 1 a mediante variables dinmicas ... . 211
7.4. Evaluacin de expresiones aritmticas mediante pilas ................. . 215
7.4.1. Notaciones Prefija (Polaca) y Postfija (Polaca inversa) .. 215
7.4.2. Algoritmo para evaluaciones de una expresin aritmtica .... 216
7.5. Aplicacin prctica de la evaluacin de una expresin aritmtica 218

7.5.1. Unidad Pilaop ................................................................ . 218
7.5.2. Unidad ExpPost (transformacin a postfija) ............... . 220
7.5.3. Evaluacin de la expresin en postfij a ............................ . 222
Resumen ...................... a 224
..
EJerclclos .................................................................................................... . 225
Problemas ................................................................................................... . 225

Captulo 8. fColas y colas de prioridades: el TAD cola .................................. 227


8.1. Especificacin formal del tipo abstracto de datos cola ................. . 228
8.2. Implementacin del TAD cola con arrays lineales ........................ . 229
8.3. Implementacin del TAD cola con arrays circulares .................... . 231
8.4. Implementacin del TAD cola con listas enlazadas ...................... . 235
8.5. Implementacin del TAD cola con listas circulares ...................... . 237
8.6. Bicolas .............................................................................................. . 239
8.7. Colas de prioridades ........................................................................ . 244
8.8. Implementacin de colas de prioridades ....................................... .. 245
8.8.1. Implementacin mediante una nica lista ....................... . 245
8.8.2. Implementacin mediante una lista de n colas ................ . 246
8.9. Implementacin de un problema con colas de prioridades ........... . 247
Resumen ..................................................................................................... . 256
..
EJerclclos .................................................................................................... . 257
Pro b 1emas ................................................................................................... . 258
.

.
,.


PARTE UI. ESTRUCTURAS DE DATOS AVANZADAS !
1,
Captul 9 Recursividad: algoritmos recursivos .......................................... . 263 !
.~
.
j

9.1. Recursividad .................................................................................... . 263 .

!

i
j.

9.2. Cundo no utilizar la recursividad ................................................. . 264


. J
9.2.1. Eliminacin de la recursividad ......................................... . 266 1,
,1.

" -,


Contenido XIII


9.3. Algoritmos divide y vencers ...................................................... 267
9.3.1. Torres de Hanoi .................................................................. 267
9.3.2. Traza de un segmento ........................................................ 269
9.4. Implementacin de procedimientos recursivos mediante pilas...... 270
9.4.1. El problema de las Torres de Hanoi resuelto sin recur-
sividad................................................................................. 271
9.5. Algoritmos de vuelta atrs (backtracking) ...................................... 277

9.5.1. Solucin del problema Salto del caballo con esquema

IteratIVO ................................... o., 281
9.5.2. Problema de las ocho reinas ............................................ .. 286
9.5.3. Solucin no recursiva al problema de las ocho reinas .... . 288
9.5.4. Problema de la mochila .................................................... . 290
9.5.5. Problema del laberinto ..................................................... .. 293
9.5.6. Generacin de permutaciones de n elementos ................ . 296
9.6. Problema de la seleccin ptima .................................................... . 297
9.6.1. El viajante de comercio ................................................... .. 298
9.7. Problema de los matrimonios estables .......................................... .. 298
Resumen ...................................................................................................... . 306
..
E~erclclos .................................................................................................... . 306
Problemas .................................................................................................... . 308

,
Captulo 10. I Arboles binarios ....... ................................................................... . 311
10.1. Concepto
, de rbol ......................................................................... . 312
10.2. Arboles binarios ............................................................................ . 314
10.2.1. Terminologa .................... ~ ............................................. . 315
10.2.2. Nivel
, de un nodo y altura de un rbol .......................... . 316
10.2.3. Arboles binario, lleno y completo ................................ . 318
10.2.4.
, Recorrido de un rbol binario ....................................... . 320

10.3. Arboles de expresin .................................................................... . 320

10.4. Construccin de un rbol binario ................................................ .. 322



10.5. Recorrido de un rbol ................................................................... . 324
10.5.1. Recorrido en orden ..................................................... . 325
10.5.2. Recorrido preorden ................................................. .. 326
10.5.3. Recorrido postorden ................................................ . 326
10.5.4. Implementacin de los algoritmos de recorrido .......... . 328
10.6. Aplicacin de rboles binarios: evaluacin de expresiones ....... . 329

10.6.1. Notacin
, postfija: notacin polaca .............................. .. 329
10.6.2. Arbol de expresin ........................................................ . 330
10.6.3. Transformacin de expresin infija a postfija ............. . 331
, 10.6.4. Creacin de un rbol a partir de la expresin en post-
fija ................................................................................... . 331
10.6.5. Evaluacin de la expresin en postfija ......................... . 332
10.6.6. Codificacin del programa de evaluacin .................... . 334
j


xiv Estructura de datos

,
10.7. Arbol binario de bsqueda .......................................................... .. 334
10.7.1 Creacin de un rbol binario ........................................ . 336
10.8. Operaciones en rboles binarios de bsqueda ............................. . 340
10.8.1. Bsqueda ........................................................................ . 341
10.8.2. Insercin ......................................................................... . 341
1O. 8"3 . ,
El lffilnaClon .................................................................... . 342
10.8.4. Recorrido de un rbol ................................................... . 344
10.8.5. Determinacin de la altura de un rbol ........................ . 345
Resumen ..................................................................................................... . 346
..
E~erclclos .................................................................................................... . 347
Problemas .................................................................................................... . 349
Referencias bibliogrficas ......................................................................... . 350
,

,
Captulo 11. Arboles equilibrados ........................................ ..................... ....... 353

11.1. Eficiencia de la bsqueda en un rbol binario ............................ . 353


11.2. rbol binario equilibrado (AVL) ................................................. . 354
11.3. Creacin de un rbol equilibrado de N claves ............................. . 355
11.4. Insercin en rboles equilibrados: rotaciones ............................. . 356
11.4.1. Insercin de un nuevo nodo ............... .......................... .. 357
11.4.2. Proceso a seguir: rotaciones ......................................... . 357
11.4.3. Formacin de un rbol equilibrado ............................. .. 360
11. 4.4. Procedimiento de insercin con balanceo .................... . 363
11.5. Eliminacin de un nodo en un rbol equilibrado ........................ . 366
11.6. Manipulacin de un rbol equilibrado ........................................ .. 372
Resumen ..................................................................................................... . 376
..
EJerclclos .................................................................................................... . 377
Problemas ................................................................................................... . 377

,
Captulo 12. Arboles B ....................................................................................... 379

12.1. Definicn de .
un rbol B .............................................................. . 379
12.2. Representacin de un rbol B de orden m ................................... . 380
12.3. Proceso de creacin en un rbol B ............................................... .

381
12.4. Bsqueda de una clave en un rbol B .......................................... . 384
12.5. Algoritmo de insercin en un rbol B de orden m ................... ... . 385
12.6. Recorrido en un rbol B de orden m ... ................ ........................ .. 389
12.7. Eliminacin de una clave en un rbol B de orden m .................. . 390
12.8. TAO rbol B de orden m .......... .................................................... . 397
12.9. Realizacin de un rbol B en memoria externa .......................... . 400
Resumen ........................... , ......................................................................... . 414

EJerCICIos .................................................................................................... . 415
Problemas ................................................................................................... . 415
Contenido xv

Captulo 13. Grafos. Representacin y operaciones ..................................... . 417


13.1. Grafos y aplicaciones .................................................................... . 417
13.2. Conceptos y definiciones .............................................................. . 418
13.2.1. Grado de entrada, grado de salida ................................ . 419
13.2.2. Camino ........................................................................... . 420
13.3. Representacin de los grafos ........................................................ . 421
13.3.1. Matriz de adyacencia .................................................... . 421
13.3.2. Listas de adyacencia ...................................................... . 424
13.4. TAO grafo ...................................................................................... . 426
13.4.1. Realizacin con matriz de adyacencia ........................ .. 426
13.4.2. Realizacin con listas de adyacencia .......................... .. 428
13.5. Recorrido de un grafo ................................................................... . 431
13.5.1. Recorrido en anchura .................................................... . 431
13.5.2. Realizacin del recorrido en anchura .......................... .. 433
13.5.3. Recorrido en profundidad ............................................ .. 434
13.5.4. Recorrido en profundidad de un grafo ........................ .. 435
13.5.5. Realizacin del recorrido en profundidad .................... . 435
13.6. Componentes conexas de un grafo .............................................. . 437
13.7. Componentes fuertemente conexas de un grafo dirigido .......... .. 439
13.8. Matriz de caminos. Cierre transitivo ............................................ . 442
13.9. Puntos de articulacin de un grafo .............................................. . 446
Resumen ..................................................................................................... . 450
.. 451
EjerCIClos .................................................................................................... .
Problemas ........................... ~ .......................... ............................................. . 453

Captulo 4) ..
Algoritmos fundamentales con grafos ...................................... . 455
......
14.1. Ordenacin topolgica .................................................................. . 456
14.2. Matriz de caminos: algoritmo de Warshall .................................. . 459
14.3. Problema de los caminos ms cortos con un solo origen: algorit-
mo de Dijkstra ............................................................................... . 461
14.3.1. Algoritmo de la longitud del camino ms corto .......... . 462
14.4. Problema de los caminos ms cortos entre todos los pares de vr-
tices: algoritmo de Floyd .............................................................. . 467
14.4.1. Recuperacin de caminos ............................................ .. 469
14.5. Concepto del flujo ......................................................................... . 470
14.5.1. Planteamiento del problema ........................................ .. 471
, ,.
14.5.2. F ormu laClon matematlca ............................................... . 472
14.5.3. Algoritmo del aumento del flujo: algoritmo de Ford y
Fulkerson ....................................................................... . 472
14.5.4. Ejemplo de mejora de flujo .......................................... . 474
14.5.5. Esquema del algoritmo de aumento de flujo .............. .. 476
14.5.6. Tipos de datos y pseudocdigo .................................... . 478
14.5.7. Codificacin del algoritmo de flujo mximo: Ford-Fu1kerson . 479


XVI Estructura de datos

14.6. Problema del rbol de expansin de coste mnimo ..................... . 483


14.6.1. Definiciones
, ................................................................... . 483
14.6.2. Arboles de expansin de coste mnimo ...................... .. 483
14.7. Algoritmo de Prim , y Kruskal ...................................................... .. 484
14.8. Codificacin. Arbol de expansin de coste mnimo .................. .. 488
Resumen ..................................................................................................... . 493
..
EjerCIClos .................................................................................................... . 493
Problemas ...... o 496

PARTE IV. ARCHIVOS Y ORDENACiN


Captulo 15. Ordenacin, bsqueda y mezcla ................................................ 501


15.1. Introduccin .................................................................................. . 502
15.2. Ordenacin .................................................................................... . 502
15.3. Ordenacin por burbuja ................................................................ . 503
15.3.1. A na'l'lSIS . ....................................................................

503
15.3.2. Procedimientos de ordenacin .................................. .. 507
15.3.3. Algoritmo de burbuja mejorado (refinamiento) ........ . 507
15.3.4. Programacin completa de ordenacin por burbuja .. 508
15.3.5. Anlisis de la ordenacin por burbuja ...................... .. 509
15.4. , 1 "
Or denaClon por se eCC10n ............................................................. . 510
, . .,

15.5. O r d enaClon por InserClon ............................................................. . 512


15.5.1. Algoritmo de insercin binaria .................................. . 514
15.5.2. Comparacin de ordenaciones cuadrticas ................ . 514
15.6. Ordenacin Shell ........................................................................... . 514
15.7. Ordenacin rpida (quicksort) ...................................................... . 517
15.7.1. Anlisis de la ordenacin rpida ................................ . 522
15.8. Ordenacin por mezcla (mergesort) ............................................ . 522
15.9. Mtodo de ordenacin por montculos (heapsort) ...................... . 525
15.9.1. Montculo ....................................................................... . 525
15.9.2. Procedimiento empuja .................................................. .. 528
15.9.3. Montculo inicial .0 529
15.10. Mtodo de ordenacin binsort .................................................... .. 529
15.11. Mtodo de ordenacin radix-sort.. ............ .................................. .. 533 .
15.12. Bsqueda lineal ............................................................................. . 536

15.12.1. Anlisis ........................................................................ . 536


15.12.2. Eficiencia de la bsqueda lineal ................................ .. 539
15.13. Bsqueda binaria ........................................................................... . 540


15.13.1. Eficiencia de la bsqueda binaria .............................. . 542

15.14. '
B usque da b"lnarla recursIva . ........................................................... . 544


'

15.14.1. Funcin bsqueda ...................................................... .. 544 ,,

15.14.2. Procedimiento BusquedaBin ................................ .. 545
!
.~



Contenido xvii

15.15. Mezcla ............................................................................................ . 546


Resumen ........................................................................................................ . 548
..
EJerclclos ...................................................................................................... . 548
Pro b1emas ................................................................ " .................................... . 549
'"
.

Captulo 16. Anlisis de algoritmos ................................................................. 553


16.1. Medida de la eficiencia de algoritmos ........................................ .. 553
16.1.1. Anlisis del orden de magnitud .................................... . 554
16.1.2. Consideraciones de eficiencia ...................................... . 555
16.1.3. Anlisis de rendimiento ................................................ . 555
16 . 1.. d ' . ,
4 Tlempo e eJeCUClon ..................................................... . 555
16.2. Notacin O-grande ....................................................................... . 556
16.2.1. Descripcin de tiempos de ejecucin ............................ . 557
16.2.2. Definicin conceptual ................................................... .. 557
16.2.3. Funciones
,
tipo monomio .............................................. .. 558
16.2.4. Ordenes, de funciones polinmicas ............................... . 559
16.2.5. Ordenes exponenciales y logartmicas .......................... . 559
16.2.6. Bases de logaritmos distintas ....................................... .. 560
16.2.7. Inconvenientes de la notacin O-grande .. .................... . 562
16.3; La eficiencia de los algoritmos de bsqueda .............................. .. 563
16.3.1. Bsqueda secuencial .................................................... .. 563
16.3.2. Bsqueda binaria ........................................................... . 564
16.4. Anlisis de algoritmos de ordenacin ......................................... .. 565
16.4.1. Anlisis de la ordenacin por seleccin ....................... . 565
16.4.2. Anlisis de la ordenacin por burbuja ........................ .. 566
16.4.3. Anlisis de la ordenacin por insercin ....................... . 567
16.4.4. Ordenacin por mezcla ................................................. . 568
16.4.5. Ordenacin rpida ......................................................... . 569
16.4.6. Anlisis del mtodo Radix Sort ................................... .. 570
16.5. Tablas comparativas de tiempos .................................................. .. 571
Resumen ..................................................................................................... . 572
..
EJerCICIOS .................................................................................................... . 573
Problemas ................................................................................................... . 577
Referencias bibliogrficas ......................................................................... . 579

Captulo 17. Archivos (ficheros). Fundamentos tericos ............................. . 581


17.1. Nocin de archivo. Estructura jerrquica .................................... . 581
17.1.1. Campos .......................................................................... . 582
17.] .2. Registros ........................................................................ . 583
17.2. Conceptos, definiciones y terminologa ...................................... . 584

17.3. Organizacin de archivos ............................................................ .. 587


17.3.1. Organizacin secuencial ............................................... . 588
17.3.2. Organizacin directa .................................................... .. 589

XVIII Estructura de datos

17.4. Operaciones sobre archivos ......................................................... .. 589


17.4.1. Creacin de un archivo ................................................. . 590
17.4.2. Consulta de un archivo .................................................. . 590
17.4.3. Actualizacin de un archivo ......................................... . 591
17.4.4. Clasificacin de un archivo ........................................... . 592
17.4.5. Reorganizacin de un archivo ..................................... .. 592
17.4.6. Destruccin de un archivo ............................................ . 592
17 .4 .. . , ti ., d h
7 R eumon, USlOn e un arc IVO ..................................... .. 592
17.4.8. Rotura/estallido de un archivo ...................................... . 593
17.5. Gestin de archivos ....................................................................... . 593
17.6. Mantenimiento de archivos .......................................................... . 594
17.6.1. Altas ............................................................................... . 595
17.6.2. Bajas ....................... ~ .............................. ......................... . 595
17.6.3. Modificaciones .............................................................. . 596
17.6.4. Consulta ......................................................................... . 596
17.6.5. Operaciones sobre registros .......................................... . 596
17.7. Procesamiento de archivos. Problemas resueltos ........................ . 596
Resumen ..................................................................................................... . 613
..
EJerClClOS .................................................................................................... . 614
Problemas ................................................................................................... . 615

Captulo 18. Tratamiento de archivos de datos ............................................ .. 617


18.1. Archivos de texto .......................................................................... . 617
18.2. Cmo aumentar la velocidad de acceso a archivos ..................... . 622
18.2.1. Archivos con funcin de direccionamiento hash ........ . 622
18.2.2. Funciones hash .............................................................. . 623
18.2.3. Resolucin de colisiones ............................................... . 625
18.2.4. Realizacin con encadenamiento ................................. . 636
18.3. Archivos indexados ....................................................................... . 645
18.3.1. Archivo indexado de una fonoteca ............................... . 645
18.3.2. Programa de manipulacin de archivos indexados ..... . 650
Resumen ..................................................................................................... . 652
..
EJerclclos .................................................................................................... . 653
Problemas ................................................................................................... . 653

Captulo 19. Ordenacin externa .................................................................... . 655


19.1. Ordenacin externa. Mtodos de ordenacin .............................. . 655
19.2. Mtodo de mezcla directa (mezcla simple) ................................. . 656
19.2.1. Codificacin ................................................................... . 657
19.3. Mtodo de mezcla equilibrada mltiple ...................................... . 661
19.3.1. Tipos de datos ................................................................ . 661
19.3.2. Cambio de finalidad de archivo .................................... . 662
19.3.3. Control del nmero de tramos ...................................... . 662
19.3.4. Codificacin ................................................................... . 663
,

., ,._ - - - -- -- - - - - -- - - - -- - - - - - _..... . ,,'

Contenido xix

19.4. Mtodo polifsico de ordenacin externa.. .................................. . 667


19.4.1. Ejemplo con tres archivos ............................................ .. 667
19.4.2. Ejemplo con cuatro archivos ........................................ . 669
19.4.3. Distribucin inicial de tramos ...................................... . 670
19.4.4. Mezcla polifsica versus mezcla mltiple ................... . 671
19.4.5. Algoritmo de mezcla ..................................................... . 671
19.4.6. Codificacin ................................................................... . 672
Resumen ........................................................................................... 0
, 678

..
EJerclclos .................................................................................................... . 678
Problemas ................................................................................................... . 679
Referencias bibliogrficas ......................................................................... . 679

PARTE V. PROGRAMACIN ORIENTADA A OBJETOS

Captulo 20. Objetos: Conceptos fundamentales y programacin orien-


tada a objetos ............................................................................... . 683
20.1. La estructura de los objetos: sintaxis ........................................... . 684
20.1.1. Encapsulamiento ............................................................ . 691
20.2. Secciones pblica y privada ........................................................ .. 691
20.2.1. Declaracin de una base ............................................... . 692
20.2.2. Declaracin de un objeto .............................................. . 693
20.2.3. Implementacin de los mtodos .................................. .. 693
20.3. Definicin de objetos mediante unidades .................................... . 694
20.3.l. Uso de un tipo objeto .................................................... . 695
20.4. La herencia .................................................................................... . 696
20.4.l. La herencia con inher i t ed ..................................... . 702
20.5. Los mtodos ........................... o 705
20.6. Objetos dinmicos ......................................................................... . 705
20.6.l. Asignacin de objetos dinmicos ................................. . 705
20.6.2. Liberacin de memoria y destructores ......................... . 707
20.6.3. La clusula S e 1 f .......................................................... . 709
20.7. Polimorfismo ................................................................................. . 714
20.7.l. Constructores y destructores en objetos dinmicos .... . 717
20.7.2. Anulacin de mtodos heredados ................................. . 718
20.8. Constructores y destructores ........................................................ . 721
20.9. Los procedimientos New y Dispose en POO .............................. . 724
20.10. Mejoras en programacin orientada a objetos ............................ . 725
20.10.1. La ocultacin mediante public y private ................... . 726
Resumen ........................................................................................................ . 727
,. d "
Errores tlplCOS e programaclon .................................................................. . 729
, "
EJerCICIOS ....................................................................................................... . 730
Problemas ...................................................................................................... . 730
Referencias bibliogrficas ............................................................................ . 730
XX Estructura de datos

Apndices
Apndice A. Vademcum de Matemticas para la resolucin de algoritmos
, .
numerlCOS . o ' , oo 733
Apendice B. Unidades estndar de Turbo Borland Pascal 7 ............................ . 739
B.I. Las unidades estndar ........................................................ . 740
B.2. La unidad Systern ............................................................ . 740

B.3. La unidad Printer ........................................................ .. 741
8.4. La unidad DOS ................................................................... . 742
B.5. Procedimientos y funciones de la unidad DOS ................ . 744
B.6. La unidad Crt ................................................................... . 753

B.7. La unidad Str i ngs: funciones ...................................... .. 760


,
Resumen oo oo 764
Apndice C. El editor de Turbo Pascal 7.0 ...................................................... .. 765
Apndice D. El entorno integrado de desarrollo de Turbo Pascal 7.0 ............ .. 769
Apndice E. Depuracin de sus programas en Turbo Pascal .......................... .. 783
Apndice F. Mensajes y cdigos de error ........................................................ .. 797
Apndice G. Gua de referencia Turbo Borland Pascal .................................... . 805
,
Apndice H. Gua del usuario ISO/ANSI Pascal Estndar .............................. . 829
Indice ..................................................................................................................... o oo. 849

,
-

Estructura de datos como disciplina informtica


y de computacin

Una de las disciplinas clsicas en todas las carreras relacionadas con la Informtica o las
Ciencias de la Computacin es Estructura de datos. El estudio de las estructuras de
datos es casi tan antiguo como el nacimiento de la programacin, y se ha convertido en
materia de estudio obligatoria en todos los curriculum desde finales de los aos sesenta
y sobre todo en la dcada de los setenta cuando apareci el lenguaje Pascal de la mano
del profesor Niklaus Wirtz, y posteriormente en la dcada de los ochenta con la apari-
cin de su obra ya clsica Algorihtms and Data Structures en 1986.
Ha sido en la dcada de los ochenta cuando surgieron los conceptos clsicos de es-
tructuras de datos, y aparecieron otros nuevos que se han ido consolidando en la segun-
da mitad de esa dcada, para llegar a implantar la caracterstica distintiva de la dcada de
los noventa, la orientacin a objetos. Una razn para que esta caracterstica se haya
convertido en ncleo fundamental de la programacin que se realiza en los noventa, y
que se seguir realizando en el tercer milenio, ha sido que un objeto encapsula el diseo
o implementacin de un tipo abstracto de datos (TAD). Adems de encapsulacin de
datos, los objetos tambin encapsulan herencia; por ejemplo, una cola es un tipo de lista
con restricciones especficas, de modo que el diseo del tipo de dato Cola puede heredar
algunos de los diseos de mtodos (operaciones) del tipo de dato Lis t a.
As pues, Estructura de datos. Algoritmos, abstraccin y objetos trata sobre el estu-
dio de las estructuras de datos dentro del marco de trabajo de los tipos abstractos de
datos (TAD) y bajo la ptica del anlisis y diseo de los algoritmos que manipulan esos
tipos abstractos de datos u objetos.

Objetivos y caractersticas

La filosofia con la que se ha construido el libro reside en el desarrollo modular de pro-


gramas que, hoy da, conduce de modo inequvoco a los principios de ingeniera de soft-
ware que facilitan la construccin de grandes programas: abstraccin, legibilidad, com-
prensibilidad y reutilizacin o reusabilidad del software. Estos principios se consiguen
mediante especificacin del software, que supone, a su vez, la separacin entre la espe-

XXI
,

xxii Estructura de datos

cificacin y la implementacin (unidades en Pascal, paquetes en Ada 95, clases en C++,


etctera) y conduce a la construccin de bibliotecas de componentes (clases y objetos)
que facilitan la construccin de software mediante la reutilizacin de software ya exis-
tente en bibliotecas de funciones y/o componentes,
El lenguaje utilizado en el libro es Pascal y, en particular, la versin Turbo Borland
que soporta el concepto de unidad (mdulo de compilacin separada) y de clases y obje-
tos, y en consecuencia facilita la construccin de tipos abstractos de datos y la progra-
macin orientada a objetos.
Para conseguir esos principios que rigen la construccin de programas siguiendo las
, modernas teoras de la ingeniera de software, es preciso fijarse una serie de objetivos
parciales, cuya consecucin lleva al objetivo final: Enseanza. aprendizaje y dominio
de los conceptos de estructuras de datos y sus algoritmos de manipulacin.
En consecuencia, los diferentes objetivos generales que busca el libro son:

Introducir y describir en profundidad las estructuras de datos clsicas (pilas. co-


las. listas. rboles. grafos y archivos) que se encuentran en casi todos los progra-

mas de computadora.
Ensear a los estudiantes y lectores autodidactas, el uso de tcnicas de anlisis y
diseo con las que se pueden evaluar y validar algoritmos.
Proporcionar ejemplos de principios de ingeniera de software y tcnicas de pro-
gramacin que incluyen abstraccin de datos y programacin orientada a objetos.
Introduccin al uso adecuado de las caractersticas especficas de Turbo Borland
Pascal, especialmente aquellas que permiten la compilacin separada: unidades,
tanto predefinidas incorporadas en el compilador como definidas por el usuario.

El lenguaje elegido para implementar los diferentes algoritmos incluidos en el libro


ha sido, como ya se ha comentado, Pascal. La razn esencial ha sido pragmtica: Pascal
sigue siendo, y estamos seguros que as seguir, el lenguaje idneo para ensear a los
estudiantes de Computacin, Informtica y restantes Ingenieras, las tcnicas de progra-
macin estructurada. Cientos de miles, han sido los estudiantes que han aprendido Pas-
cal y ese ha sido su primer lenguaje de programacin, aunque hoy en el campo profesio-
nal haya sido desplazado por otros lenguajes tales como C, C++, Java o Visual Basic.
En cualquier forma, siempre hemos tenido la idea de que los lenguajes de computa-
dora no son slo un mecanismo de descripcin de algoritmos o de programas de compu-
tadoras, sino tambin un vehculo de concepcin, reflexin y anlisis, en la resolucin
de problemas con computadora. Por ello, pensamos que Pascal, como cualquier otro
lenguaje estructurado o incluso un pseudolenguaje, como puede ser un pseudocdigo,
servir para conseguir el rigor y el formalismo que el profesor quiera conseguir con sus
alumnos, o el propio estudiante se marque siguiendo las directrices de sus maestros o
profesores.
Desde un punto de vista cientfico, el libro se ha escrito apoyndose en las obras de
las autoridades ms reconocidas en el campo de algoritmos y estructuras de datos, fun-
damentalmente D. E. Knuth y N. Wirth, y las inestimables obras de A. V. Aho, J. Hop-
croft, 1. D. Ullman, E. Horowitz, D. Sahni, B. Liskov, entre otros, y que el lector encon-
Prlogo

trar en las referencias bibliogrficas que acompaan a algunos captulos o en la biblio-


grafia final del libro.

El libro como texto de referencia universitaria y profesional


Estructura de datos es una disciplina acadmica que se incorpora a todos los planes de
estudios de carreras universitarias de Ingeniera Informtica, Ingeniera en Sistemas
Computacionales y Licenciatura en Informtica, as como suele ser tambin frecuente la
incorporacin en planes de estudios de informtica en Formacin Profesional o Institu-
tos Politcnicos. Suele considerarse tambin Estructuras de datos como una extensin
de las asignaturas de Programacin, en cualquiera de sus niveles. Por estas circunstan-
cias han nacido numerosas iniciativas de incorporacin de esta disciplina a los diferen-
tes planes de estudios. .
Este es el caso de Espaa. Los planes de estudios de Ingeniera en Illfonntica, Inge-
niera Tcnica en Informtica de Sistemas e Ingeniera Tcnica en Informtica de Ges-
tin incluyen, todos ellos, una materia troncal llamada Estructura de datos, que luego se
convierte en asignaturas anuales o semestrales. El Consejo de Universidades no slo
obliga a las universidades a incluir esta asignatura como materia troncal, y en conse-
cuencia asignatura obligatoria, sino que adems recomienda descriptores para la mis-
ma. As estos descriptores son: tipos abstractos de datos, estructuras de datos y algoritmos
de manipulacin, ficheros (archivos)>>. En esta edicin se ha dejado fuera del contenido
del libro el descriptor bases de datos, por entender que suele constituir parte de una
asignatura especfica que an formando parte de Estructura de datos suele tener entidad
propia o complementaria. De igual fOl ma la organizacin internacional ACM recomien-
da un curriculum para la carrera de Computer Science, equivalente a las carreras univer-
sitarias espaolas ya citadas. Asimismo, todos los pases de Iberoamrica han incluido
tambin la asignatura Estructura de datos en sus currculos. As nos consta por nuestras
numerosas visitas profesionales a universidades e institutos tecnolgicos de Mxico, Cuba,
Venezuela, Guatemala, etc., donde hemos podido examinar sus planes de estudios e inter-
cambiar experiencias, tanto con profesores (maestros) como con estudiantes.
Estructuras de datos: Algoritmos, abstraccin y objetos. Siguen las recomendacio-
nes dadas por el Consejo de Universidades de Espaa para las carreras de Ingeniera
Informtica, tanto la superior como la tcnica, y se ha adaptado en la medida de lo posi-
ble al curriculum recomendado por la ACM, en particular el curso C2 (Curriculum '78,
CACM 3/79 y CACM 8/85). Asimismo se adapta a cursos tpicos sobre conocimiento de
algoritmos y estructura de datos, as como de los lenguajes de programacin, segn se
describe en el informe Computing Curricula 1991 del ACM/IEEE-CS (CommunACM 34,
6 junio 1991) Joint Curriculum Task Force. El libro trata de ajustarse a las directrices
dadas para Estructura de datos y Anlisis de algoritmos propuestos en ese informe y se
puede usar como materia fundamental y/o complementaria de un curso normal de cien-
cias de la computacin para graduados y no graduados.
El texto se ha diseado para un curso de dos cuatrimestres (semestres), de algoritmos
y estructuras de datos. Su divisin seleccin del captulo y adscripcin a uno u otro
xxiv Estructura de datos

cuatrimestre, creemos deben ser decididos por el profesor (maestro) en funcin de su


experiencia y de los objetivos marcados. Podra servir para un cuatrimestre siempre que
hubiese una seleccin adecuada del profesor y se tuviera en cuenta la formacin previa
del estudiante.

Requisitos

El nico requisito previo para los estudiantes que emplean este texto es un curso de uno
o dos semestres, de programacin con diseo de algoritmos mediante pseudocdigos, o
lenguajes estructurados, tales como FORTRAN, Pascal, C, C++ o Java. Los estudiantes
que han estudiado sus cursos de programacin sin utilizar el lenguaje Pascal, pueden
seguir este libro junto con alguno de los libros de texto que se listan en la bibliografia
final del libro o en las referencias bibliogrficas de los captulos 1 y 2. No obstante, se
han incluido varios apndices sobre Pascal y Turbo Pascal que pensamos ser suficiente,
al menos, a nivel de sintaxis para refrescar o adquirir aquellos conocimientos bsicos
necesarios para seguir la calificacin de los diferentes algoritmos del libro.

Depuracin

Todos los programas y algoritmos del texto se han probado y depurado. Adems de nuestra
tarea de puesta a punto de programas, diferentes profesores nos han ayudado en esta
tarea. Este es el caso de Matilde Femndez, Lucas Snchez, Jess Prez, Isabel Torralvo
a
y M. del Mar Garca, todos ellos profesores de la Facultad de Informtica y Escuela
Universitaria de Informtica de la Universidad Pontificia de Salamanca en el campus de
Madrid. Su entusiasmo y el cario puesto en esta actividad ha sido desbordante y siem-
pre aportaron sugerencias valiosas. Por supuesto, que cualquier error que todava pudie-
ra existir, es absoluta responsabilidad de los autores.
Los ejercicios y problemas de los diferentes captulos varan en tipo y dificultad.
Algunos son reiterativos para confirmar la comprensin de los textos. Otros implican
modificaciones a programas o algoritmos presentados. Se han incluido gran cantidad de
problemas de programacin con diferentes niveles de complejidad que confiamos sean
complementos eficientes a la formacin conseguida por el lector.

Contenido

Este libro se ha dividido en cinco partes y ocho apndices.

Parte 1: Abstraccin y Programacin: Introduccin a la ingeniera de software. Esta


parte contiene los captulos 1, 2 y 3 y describe una introduccin a la metodologa de
construccin de grandes programas, una comparacin entre los conceptos de mdulos y
unidades, as como el importante concepto de abstraccin de datos.
,

Prlogo XXV

Parte 11: Fundamentos bsicos de estructuras de datos y tipos abstractos de datos.


Esta parte contiene la descripcin del importante tipo de dato llamado puntero, junto
con la descripcin de las estructuras de datos ms tpicas: listas enlazadas, listas doble-
mente enlazadas, pilas y colas.

Parte 111: Estructuras de datos avanzadas. Las estructuras rboles binarios, equili-
brado y B, grafos, junto con el estudio de algoritmos recursivos y de manipulacin de
las citadas estructuras de datos, son el tema central de esta parte.

Parte IV: Archivos y ordenacin. En esta parte se tratan los importantes algoritmos de
manipulacin de ordenacin, bsqueda y mezcla, junto con el concepto de archivo y su
tratamiento; otro concepto importante que se estudia en esta parte, es el Anlisis de Al-
goritmos, como tcnica indispensable para conseguir algoritmos eficientes.

Parte V: En esta parte se introduce al lector en programacin orientada a objetos,


apoyada en el concepto de objeto como extensin de un tipo abstracto de datos.

Una descripcin detallada de los diferentes captulos se proporciona a continuacin.


El captulo 1 es una introduccin a la metodologa de construccin de software, as como
las tcnicas de ingeniera de software. Se describen las herramientas usuales para la
resolucin de problemas junto con las diferentes etapas del ciclo de vida del software.
Asimismo se enumeran los principios de diseo de sistemas de software, junto con nor-
mas para un estilo de programacin, documentacin, depuracin y pruebas.
En el captulo 2 se describe el concepto de mdulo y cmo se puede implementar en
Turbo Pascal, mediante unidades. Se describe el concepto de unidad, el modo de crea-
cin y de utilizacin de las mismas. El importante concepto de abstraccin de datos y su
implementacin mediante tipos abstractos de datos.
En el captulo 3 se comienza el estudio de la orientacin a objetos as como los dife-
rentes lenguajes de programacin orientados a objetos, junto al importante concepto de
reutilizacin de software.
El captulo 4 proporciona una introduccin a las estructuras de datos dinmicas. El
captulo describe el tipo de dato puntero en Pascal y muestra cmo utilizar la asignacin
dinmica de memoria.
El tipo abstracto de dato Lista, se estudia en el captulo 5. La implementacin ms
usual son las listas enlazadas y por esta razn se analizan sus algoritmos de manipula-
cin. Uno de los casos ms frecuentes en el diseo y construccin de estructura de datos
es la ordenacin de elementos. El captulo describe el caso particular de las listas enla-
zadas.
Otros tipos de listas muy utilizadas en la manipulacin de estructuras de datos son
las listas doblemente enlazadas y las listas circulares. Sus algoritmos de implementa-
cin se estudian en el captulo 6.
Las pilas y las colas son otros tipos de datos muy usuales en cualquier programa de
software. Por esta razn se estudian en detalle junto con los procedimientos y funciones
necesarios para poder utilizarlas. Estas estructuras de datos son listas, por lo que su

XXVI Estructura de datos

implementacin se realizar, no slo con arrays, sino fundamentalmente mediante listas


enlazadas o circulares. Los tipos abstractos de datos pila y cola se describen en los cap-
tulos 7 y 8.
El captulo 9 se dedica a la descripcin de la recursividad as como al uso de proce-
dimientos y funciones recursivas. La recursividad es una propiedad esencial en el diseo
de tcnicas algortmicas, por esta circunstancia se hace un estudio exhaustivo y detalla-
do de los algoritmos recursivos clsicos y aquellos otros ms complejos. As se analizan
los tpicos algoritmos de divide y vencers, como es el popular algoritmo de las Torres
de Hanoi, hasta los algoritmos de vuelta atrs (backtraking) ms famosos y eficientes
tales como: el problema de las ocho reinas, el problema de la mochila o el proble-
ma de los matrimonios estables.

El captulo 10 introduce al tipo de dato Arbol binario. Los rboles binarios son es-
tructuras de datos recursivas y la mayora de sus propiedades se pueden definir recursi-
vamente. Los rboles binarios tienen numerosas aplicaciones; entre ellas una de las ms
usuales es la evaluacin de expresiones. En el captulo se describen tambin los descen-
dientes de los rboles binarios, como es el caso de los rboles binarios de bsqueda. Las
operaciones en los rboles binarios de bsqueda son motivo de anlisis a lo largo del
captulo.
Otro tipo de extensiones rboles son los complejos y eficientes rboles B y r-
boles AVL o equilibrados. Sus algoritmos de manipulacin se describen en los cap-
tulos 11 y 12.
Los grafos son uno de los tipos de datos ms clsicos y de mayor utilidad en el
diseo de problemas complejos. La implementacin y los algoritmos de manipulacin
de grafos se estudian en el captulo 13. Sin embargo, un estudio completo de grafos y de
la teora de grafos requiere mucho ms que un captulo; por esta circunstancia, se exami-
nan aspectos avanzados en el captulo 14. As, se describen algoritmos complejos tales
como los algoritmos de Dijkstra, Warshall, Floyd o Kruskal.
Los mtodos clsicos de ordenacin, bsqueda y mezcla, tanto los ms sencillos has-
ta otros complejos, se describen en el captulo 15. As se analizan los mtodos de orde-
nacin por burbuja, seleccin, insercin, Shell, quicksort (rpido), mergesort (mezcla) o
heapsort (montculo), junto con la ordenacin binaria (binsort) o radix (Radix-sort).
Las tcnicas de anlisis de algoritmos y la medida de la eficiencia de los mismos se
analizarn en el captulo 16. La notacin O grande utilizada en el anlisis de algoritmos
se describe en dicho captulo 16.
La estructura de datos clsica en cuanto a organizacin de los datos son los archivos
(ficheros). La organizacin de archivos junto con las operaciones sobre los mismos se
describen en el captulo 17. En el captulo 18 se describen los archivos de texto y los
archivos indexados, junto con las tcnicas de direccionamiento aleatorio (hash).
La ordenacin externa de estructuras de datos junto con los mtodos de implementa-
. cin correspondiente se estudian en el captulo 19.
El captulo 20 realiza una descripcin del tipo de dato objeto junto con la implemen-
tacin de las propiedades clsicas que soportan tales como herencia y polimorfismo.
Los apndices complementan el contenido terico del libro. El Apndice A es un
vademcum de frmulas matemticas que se requieren normalmente en la construccin
Prlogo xxvii

de algoritmos no slo numricos sino de gestin. El concepto de mdulo o unidad en


Turbo Pascal es motivo de estudio en el apndice B, donde se describen las unidades
estndar del compilador. El apndice C describe el editor de texto del compilador as
como la descripcin de su funcionalidad. El apndice E describe los mtodos de depura-
cin de programas en Turbo Borland Pascal y los mensajes y cdigos de error se inclu-
yen en el apndice F. El apndice G es una amplia gua de referencia de sintaxis del
compilador de Turbo Borland Pascal. El apndice H es una gua de usuario de ISO/
ANSI Pascal pensado en aqueIlos lectores que utilicen un compilador de Pascal estndar
distinto del compilador Turbo Borland Pascal.

AGRADECIMIENTOS

Este libro no es slo fruto del trabajo de los autores, tal y como sucede con la creacin
de la mayora de los libros tcnicos. Muchas personas han colaborado de una u otra
manera para que este libro vea la luz.
Entre estas personas queremos destacar aqueIlas que ms han influido en la versin
ltima. Los profesores de Estructuras de datos, Lucas Snchez, Matilde Fernndez y
Jess Prez, del Departamento de Lenguajes y Sistemas Informticos e Ingeniera de
Software de la Facultad de Informtica y de la Escuela Universitaria de Informtica de
la Universidad Pontificia de Salamanca (UPSA), con sus aportaciones y sugerencias fru-
to de su larga experiencia como profesores de la asignatura Estructura de datos en el
campus de Madrid, han ledo y revisado las primeras pruebas de imprenta de este libro,
y nos han dado ideas y sugerencias que han mejorado notablemente el libro. Las profe-
a
soras M. Mar Garca e Isabel Torralvo y el profesor Joaqun Abeger, todos del mismo
departamento que los profesores anteriores, tambin han ledo las galeradas del texto y
han detectado erratas y depurado muchos programas del libro.
Adems de los profesores anteriores, otros profesores de la Facultad y Escuela Uni-
versitaria de Informtica de UPSA han ayudado
,
y apoyado a que esta obra sea una rea-
lidad: Paloma Centenera, Luis Villar y Angel Hermoso.
A todos deseamos agradecer nuestro reconocimiento por su arduo trabajo. No slo
nos han demostrado que son colegas, sino y sobre todo son amigos. Nuestras gracias
ms sinceras a todos eIlos, sin su apoyo y trabajo esta obra no sera la misma.
Naturalmente, no seramos justos si no reconociramos la inmensa ayuda que ha
supuesto y seguir suponiendo las sugerencias, consejos y crticas que nuestros numero-
sos alumnos de todos estos aos pasados nos han hecho tanto en Espaa como en Lati-
noamrica. Son el mejor aliciente que cualquier profesor puede tener. En nuestro caso
ha sido una realidad vivida da a da. Nuestro agradecimiento eterno.

Una ltima reflexin

Estructura de datos es una disciplina clave en los curriculum universitarios de inform-


tica y computacin. En nuestra obra hemos volcado nuestra experiencia de ms de diez



XXVIII Estructura de datos

aos en la enseanza universitaria; nuestra esperanza es que hayamos conseguido trans-


mitir dicha experiencia, y que nuestros lectores puedan no slo iniciarse en el aprendiza-
je de las estructuras de los datos, sino llegar a dominar su concepto, organizacin, dise-
o y manipulacin de los algoritmos correspondientes. El mayor deseo de los autores
sera poder conseguir los objetivos del libro, que su aprendizaje sea gradual y que lle-
guen a dominar este vital e importante campo informtico de las estructuras de datos.

Madrid, julio de 1998


Los autores

I
PARTE

,
I
,

''''f>,-.: ',',>.' ,,' ',,: ,,',,;'.

-,

1
,
CAPITULO

. , . .,
n enlerla eso are: Intro ucclon
, .,
a a meto o o la e construcclon
e es I ro
.- - _ ., _. -. .. r, '" _. :-:-, -: -/ ';"':. ','.

CONTE

1.1 . Abstraccin.'
1.2. Resolucin de problemas de programacin.
1.3. Herramientas para la resolucin de problemas.
1.4. Factores en la calidad del software.
1.5. El ciclo de vida del software.
1.6. Mtodos formales de verificacin de programas.
1.7. Principios de diseos de sistemas de software.
1.8. Estilo de programacin.
1.9. La documentacin.
1.10. Depuracin.
1.11. Diseo de algoritmos.
1.12. Pruebas (testing).
1.13. Eficiencia.
1.14. Transportabilidad (portabilidad).
RESUMEN.
EJERCICIOS.
PROBLEMAS.

La produccin de un programa se puede dividir en diferentes fases:


anlisis, diseo, codificacin y depuracin, prueba y mantenimiento.
Estas fases se conocen como ciclo de vida del software, y son los prin-
cipios bsicos en los que se apoya la ingeniera del software. Deben
considerarse siempre todas las fases en el proceso de creacin de pro-
gramas, sobre todo cuando stos son grandes proyectos. La ingeniera
de o del software trata de la creacin y produccin de programas a
gran escala.

3
4 Estructura de datos

,
1.1. ABSTRACCION

Los seres humanos se han convertido en la especie ms influyente de este planeta, debido
a su capacidad para abstraer el pensamiento. Los sistemas complejos, sean naturales o
artificiales, slo pueden ser comprendidos y gestionados cuando se omiten detalles que son
irrelevantes a nuestras necesidades inmediatas. El proceso de excluir detalles no deseados
o no significativos, al problema que se trata de resolver, se denomina abstraccin, y es
algo que se hace en cualquier momento.
Cualquier sistema de complejidad suficiente se puede visualizar en diversos niveles
de abstraccin dependiendo del propsito del problema. Si nuestra intencin es conseguir
una visin general del proceso, las caractersticas del proceso presente en nuestra abstrac-
cin constar principalmente de generalizaciones. Sin embargo, si se trata de modificar
partes de un sistema, se necesitar examinar esas partes con gran nivel de detalle. Consi-
deremos el problema de representar un sistema relativamente complejo tal como un coche.
El nivel de abstraccin ser diferente segn sea la persona o entidad que se relaciona con ,
el coche: conductor, propietario, fabricante o mecnica.
As, desde el punto de vista del conductor sus caractersticas se expresan en trminos ,
de sus funciones (acelerar, frenar, conducir, etc.); desde el punto de vista del propietario I
sus caractersticas se expresan en funcin de nombre, direccin, edad; la mecnica del ,
coche es una coleccin de partes que cooperan entre s para proveer las funciones citadas,
mientras que desde el punto de vista del fabricante interesa precio, produccin anual de

~
la empresa, duracin de construccin, etc. La existencia de diferentes niveles de abstrac-
cin conduce a la idea de una jerarqua de abstracciones.
Las soluciones a problemas no triviales tiene una jerarqua de abstracciones de modo I

que slo los objetivos generales son evidentes al nivel ms alto. A medida que se des-
ciende en nivel los aspectos diferentes de la solucin se hacen evidentes.
En un intento de controlar la complejidad, los diseadores del sistema explotan las
caractersticas bidimensionales de la jerarqua de abstracciones. La primera etapa al tratar
con un problema grande es seleccionar un nivel apropiado a las herramientas (hardware
y software) que se utilizan para resolverlo. El problema se descompone entonces en subpro-
"

blemas que se pueden resolver independientemente de modo razonable. !

, ,
1.2. RESOLUCION DE PROBLEMAS DE PROGRAMACION

El trmino resolucin del problema se refiere al proceso completo de tomar la descrip-


cin del problema y desarrollar un programa de computadora que resuelva ese proble-
ma. Este proceso requiere pasar a travs de muchas fases: desde una buena comprensin
del problema a resolver, hasta el diseo de una solucin conceptual, para implementar la
solucin con un programa de computadora.
Realmente qu es una solucin? Normalmente, una solucin consta de dos compo-
nentes: algoritmos y medios para almacenar datos. Un algoritmo es una especificacin
concisa de un mtodo para resolver un problema. Una accin que un algoritmo realiza con
frecuencia es operar sobre una coleccin de datos. Por ejemplo, un algoritmo puede
Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 5

tener que poner menos datos en una coleccin, quitar datos de una coleccin o realizar
preguntas sobre una coleccin de datos. Cuando se construye una solucin, se deben
organizar sus colecciones de datos de modo que se pueda operar sobre los datos fcil-
mente en la manera que requiera el algoritmo. .
Sin embargo, no slo se necesita almacenar los datos en estructuras de datos sino
tambin operar sobre esos datos. De este modo una entidad fundamental ser el tipo
abstracto de datos (TAO) (Abstract Data Type, ADT), que es una coleccin de datos y
un conjunto de operaciones que actan sobre esos datos. Por ejemplo, supongamos que
se necesita almacenar una coleccin de nombres de futbolistas de modo que permita una
bsqueda rpida de un nombre dado. El algoritmo de bsqueda binaria que se estudiar
en el captulo 15 pellnitir buscar en una lista (un array) eficientemente, si el array o
lista est ordenado. Por consiguiente, una solucin a este problema es almacenar los
nombres ordenados en un array y utilizar un algoritmo de bsqueda binaria para buscar
en el array un nombre especificado. Un TAD que visualice el array ordenado junto con
el algoritmo de bsqueda binaria resolver el problema.

1.3. HER ENTAS PARA LA RESOLUCiN DE PROBLEMAS

Diferentes herramientas ayudan al programador y al ingeniero de software a disear una


solucin para un problema dado. Algunas de estas herramientas son diseo descendente,
abstraccin procedimental, abstraccin de datos, ocultacin de la informacin, recursin
o recursividad y programacin orientada a objetos.

1.3.1. Diseo descendente


Cuando se escriben programas de tamao y complejidad moderada, nos enfrentamos a la
dificultad de escribir dichos programas. La solucin para resolver estos problemas
y, naturalmente, aquellos de mayor tamao y complejidad, es recurrir a la modularidad
mediante el diseo descendente. Qu significa diseo descendente y modularidad? La
filosofia del diseo descendente reside en que se descompone una tarea en sucesivos
niveles de detalle. Para ello se divide el programa en mdulos independientes proce-
dimientos, funciones y otros bloques de cdigo ,como se observa en la Figura 1.1.

Programa

principal
..'

Funcin F, Funcin F2 Procedimiento P,

Figura 1.1. Un prOgrama dividido en mdulos independientes.


6 Estructura de datos

El concepto de solucin modular se aprecia en la aplicacin de la Figura 1.2, que


busca encontrar la nota media de un conjunto de notas de una clase de informtica.
Existe un mdulo del ms alto nivel que se va refinando en sentido descendente para
encontrar mdulos adicionales ms pequeos. El resultado es una jerarqua de mdulos;
cada mdulo se refina por los de bajo nivel que resuelve problemas ms pequeos
y contiene ms detalles sobre los mismos. El proceso de refinamiento contina hasta que
los mdulos de nivel inferior de la jerarqua sean tan simples como para traducirlos direc-
tamente a procedimientos, funciones y bloques de cdigo en Pascal o C, que resuelven
problemas independientes muy pequeos. De hecho, cada mdulo de nivel ms bajo
debe ejecutar una tarea bien definida. Estos mdulos se denominan altamente cohesivos.
Cada mdulo se puede dividir en subtareas. Por ejemplo, se puede refinar la tarea de
,
, leer las notas de una lista, dividindolo en dos subtareas. Por ejemplo, se puede refinar
la tarea de leer las notas de la lista en otras dos subtareas: pedir al usuario una nota
y situar la nota en la lista.

1.3.2. Abstraccin procedimental


Cada algoritmo que resuelve el diseo de un mdulo equivale a una caja negra que ejecuta
una tarea determinada. Cada caja negra especifica lo que hace pero no cmo lo hace, y
de igual modo cada caja negra conoce cuantas cajas negras existen y lo que hacen.
Normalmente, estas cajas negras se implementan como subprogramas. Una abstrac-
cin procedimental separa el propsito de un subprograma de su implementacin. Una
vez que un subprograma se haya escrito o codificado, se puede usar sin necesidad de
conocer su cuerpo y basta con su nombre y una descripcin de sus parmetros.
La modularidad y abstraccin procedimental son complementarios. La modularidad
implica romper una solucin en mdulos; la abstraccin procedimental implica la espe-
cificacin de cada mdulo antes de su implementacin en Pascal. El mdulo implica que
se puede cambiar su algoritmo concreto sin afectar el resto de la solucin.

Encontrar
la media

Obtener el
Leer las notas Ordenar
elemento central
de la lista la lista
de la lista

Pedir al usuario Situar la nota


una lista en la lista

Figura 1.2. Diagrama de bloques que muestra la jerarqua de mdulos.


... -- --- - - - - - - -- - - -- - - - - - - -

Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 7

La abstraccin procedimental es esencial en proyectos complejos, de modo que se pue-


dan utilizar subprogramas escritos por otras personas, sin necesidad de tener que conocer
sus algoritmos.

1.3.3. Abstraccin de datos


La abstraccin procedimental significa centrarse en lo que hace un mdulo en vez de
en los detalles de cmo se implementan los detalles de sus algoritmos. De modo similar,
la abstraccin de datos se centra en las operaciones que se ejecutan sobre los datos en
vez de cmo se implementarn las operaciones.
Como ya se ha comentado antes, un tipo abstracto de datos (TAD) es una colec-
cin de datos y un conjunto de operaciones sobre esos datos. Tales operaciones pueden
aadir nuevos datos, o quitar datos de la coleccin, o buscar algn dato. Los otros mdu-
los de la solucin conocern qu operaciones puede realizar un TAD. Sin embargo, no
conoce cmo se almacenan los datos ni cmo se realizan esas operaciones.
Cada TAD se puede implementar utilizando estructuras de datos. Una estructura de
datos es una construccin que se puede definir dentro de un lenguaje de programacin
para almacenar colecciones de datos. En la resolucin de un problema, los tipos abstractos
de datos soportan algoritmos y los algoritmos son parte de los que constituye un TAD.
Para disear una solucin, se deben desarrollar los algoritmos y los TAD al unsono.

1.3.4. Ocultacin de la informacin


La abstraccin identifica los aspectos esenciales de mdulos y estructura de datos que
se pueden tratar como cajas negras. La abstraccin es responsable de sus vistas externas
o pblicas, pero tambin ayuda a identificar los detalles que debe ocultar de la vista
pblica (vista privada). El principio de ocultacin de la informacin no slo oculta los
detalles dentro de la caja negra, sino que asegura que ninguna otra caja negra pueda
acceder a estos detalles ocultos. Por consiguiente, se deben ocultar ciertos detalles dentro
de sus mdulos y TAD y los hacen inaccesibles a otros mdulos y TAD.
Un usuario de un mdulo no se preocupa sobre los detalles de su implementacin y,
al contrario, un desarrollador de un mdulo o TAD no se preocupa sobre sus usos.

1.3.5. Programacin orientada a objetos


Los conceptos de modularidad, abstraccin procedimental, abstraccin de datos y ocul-
tacin de la informacin conducen a la programacin orientada a objetos, basada en el
mdulo o tipo de dato objeto.
Las prioridades fundamentales de un tipo son: encapsulamientos, herencia y polimor-
fismo. El encapsulamiento es la combinacin de datos y operaciones que se pueden
ejecutar sobre esos datos en un objeto. En Turbo Borland Pascal el encapsulamiento en
un objeto se codifica mediante una unidad.
Herencia es la propiedad que permite a un objeto transmitir sus propiedades a otros
objetos denominados descendientes; la herencia permite la reutilizacin de objetos que
8 Estructura de datos

se hayan definido con anterioridad. El polimorfismo es la propiedad que permite deci-


dir en tiempo de ejecucin la funcin a ejecutar, al contrario que sucede cuando no exis-

te polimorfismo en el que la funcin a ejecutar se decide previamente y sin capacidad de

I
modificacin, en tiempo de ejecucin.

1.4. FACTORES EN LA CALIDAD DEL SOFTWARE

La construccin de software requiere el cumplimiento de numerosas caractersticas. Entre


ellas se destacan las siguientes:

Eficiencia
La eficiencia de un software es su capacidad para hacer un buen uso de los recursos que
manipula.

Transportabilidad (portabilidad)
La transportabilidad o portabilidad es la facilidad con la que un software puede ser
transportado sobre diferentes sistemas fisicos o lgicos.

Verificabilidad (facilidad de verificacin)


La verificabilidad o facilidad de verificacin de un software es su capacidad para sopor-
tar los procedimientos de validacin y de aceptar juegos de test o ensayo de programas.

Integridad
La integridad es la capacidad de un software a proteger sus propios componentes contra
los procesos que no tenga el derecho de acceder.

Facilidad de utilizacin
Un software es fcil de utilizar si se puede comunicar consigo de manera cmoda.

Correccin (exactitud)
Capacidad de los productos software de realizar exactamente las tareas definidas por su
especificacin.

Robustez
Capacidad de los productos software de funcionar incluso en situaciones anormales .

Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 9

Extensibilidad
Facilidad que tienen los productos de adaptarse a cambios en su especificacin. Existen
dos principios fundamentales para conseguir esto:
diseo simple;
descentralizacin.

Reutilizacin
Capacidad de los productos de ser reutilizados, en su totalidad o en parte, en nuevas
aplicaciones.

Compatibilidad
Facilidad de los productos para ser combinados con otros.

1.5. EL CICLO DE VIDA DEL SOFTWARE


Existen dos niveles en la construccin de programas: aquellos relativos a pequeos pro-
gramas (los que normalmente realizan programadores individuales) y aquellos que se
refieren a sistemas de desarrollo de programas grandes (proyectos de software) y que,
generalmente, requieren un equipo de programadores en lugar de personas individuales.
El primer nivel se denomina programacin a pequea escala; el segundo nivel se deno-
mina programacin a gran escala.
La programacin en pequea escala se preocupa de los conceptos que ayudan a crear pe-
queos programas aquellos que varan en longitud desde unas pocas lneas a unas pocas
pginas . En estos programas se suele requerir claridad y precisin mental y tcnica. En
realidad, el inters mayor desde el punto de vista del futuro programador profesional est
en los programas de gran escala que requiere de unos principios slidos y firmes de lo que
se conoce como ingeniera de software y que constituye un conjunto de tcnicas para facilitar
el desarrollo de programas de computadora. Estos programas o mejor proyectos de software
estn realizados por equipos de personas dirigidos por un director de proyectos (analista o
ingeniero de software) y los programas pueden tener ms de 100.000 lneas de cdigo.
El desarrollo de un buen sistema de software se realiza durante el ciclo de vida que
es el periodo de tiempo que se extiende desde la concepcin inicial del sistema hasta su
eventual retirada de la comercializacin o uso del mismo. Las actividades humanas rela-
cionadas con el ciclo de vida implican procesos tales como anlisis de requisitos, diseo,
implementacin, codificacin, pruebas, verificacin, documentacin, mantenimiento y
evolucin del sistema y obsolescencia. En esencia el ciclo de vida del software comienza
con una idea inicial, incluye la escritura y depuracin de programas, y contina durante
aos con correcciones y mejoras al software original l.

Carrasco, Hellman y Verof: Data structures and problem solving with Turbo Pascal, The Benjamingl
I

Cummings Publishing, 1993, pg. 210 .

10 Estructura de datos

El ciclo de vida del software es un proceso iterativo, de modo que se modificarn las
sucesivas etapas en funcin de la modificacin de las especificaciones de los requisitos
producidos en la fase de diseo o implementacin, o bien una vez que el sistema se ha
implementado, y probado, pueden aparecer errores que ser necesario corregir y depu-
rar, y que requieren la repeticin de etapas anteriores.
La Figura 1.3 muestra el ciclo de vida de software y la disposicin tpica de sus
diferentes etapas en el sistema conocido como ciclo de vida en cascada, que supone que
la salida de cada etapa es la entrada de la etapa siguiente.

1.5.1. Anlisis
La primera etapa en la produccin de un sistema de software es decidir exactamente qu
se supone ha de hacer el sistema; esta etapa se conoce tambin como anlisis de requisitos
o especificaciones y por esta circunstancia muchos tratadistas suelen subdividir la etapa
en otras dos:

Anlisis y definicin del problema.


Especificacin de requisitos.

La parte ms dificil en la tarea de crear un sistema de software es definir cul es el


problema y a continuacin especificar lo que se necesita para resolverlo. Normalmente
la definicin del problema comienza analizando los requisitos del usuario, pero estos
requisitos, con frecuencia, suelen ser imprecisos y dificiles de describir. Se deben especi-

ficar todos los aspectos del problema, pero con frecuencia las personas que describen el
problema no son programadores yeso hace imprecisa la definicin. La fase de especifica-
cin requiere normalmente la comunicacin entre los programadores y los futuros usua-
rios del sistema e iterar la especificacin, hasta que tanto el especificador como los usuarios
estn satisfechos de las especificaciones y hayan resuelto el problema normalmente.

Anlisis
..
Diseo

Implementacin

Depuracin

Mantenimiento

Figura 1.3. Ciclo de vida del software.


,


, .,.


1

Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 11

En la etapa de especificaciones puede ser muy til para mejorar la comunicacin


entre las diferentes partes implicadas construir un prototipo o modelo sencillo del sistema
final; es decir, escribir un programa prototipo que simule el comportamiento de las partes
del producto software deseado. Por ejemplo, un programa sencillo incluso ineficien-
te puede mostrar al usuario la interfaz propuesta por el analista. Es mejor descubrir
cualquier dificultad o cambiar su idea original antes que la programacin se encuentre
en estado avanzado o, incluso, terminada. El modelado de datos es una herramienta muy
importante en la etapa de definicin del problema. Esta herramienta es muy utilizada en
el diseo y construccin de bases de datos.
Tenga presente que el usuario final, normalmente, no conoce exactamente lo que desea
haga el sistema. Por consiguiente, el analista de software o programador, en su caso, debe
interactuar con el usuario para encontrar lo que el usuario desear haga el sistema. En
esta etapa se debe responder a preguntas tales como:

Cules son los datos de entrada?


Qu datos son vlidos y qu datos no son vlidos?
Quin utilizar el sistema: especialistas cualificados o usuarios cualesquiera (sin
formacin)?
Qu interfaces de usuario se utilizarn?
Cules son los mensajes de error y de deteccin de errores deseables? Cmo
debe actuar el sistema cuando el usuario cometa un error en la entrada?
Qu hiptesis son posibles?
Existen casos especiales?
Cul es el formato de la salida?
Qu documentacin es necesaria?
Qu mejoras se introducirn probablemente al programa en el futuro?
Cmo debe ser de rpido el sistema?
Cada cuanto tiempo ha de cambiarse el sistema despus que se haya entregado?

El resultado final de la fase de anlisis es una especificacin de los requisitos del


software.

Descripcin problema
Prototipos de

1.5.2. Diseo
La especificacin de un sistema indica lo que el sistema debe hacer. La etapa de diseo
del sistema indica cmo ha de hacerse. Para un sistema pequeo, la etapa de diseo puede
ser tan sencilla como escribir un algoritmo en pseudocdigo. Para un sistema grande, esta
etapa incluye tambin la fase de diseo de algoritmos, pero incluye el diseo e interaccin
de un nmero de algoritmos diferentes, con frecuencia slo bosquejados, as como una
estrategia para cumplir todos los detalles y producir el cdigo correspondiente.


12 Estructura de datos

Es preciso determinar si se pueden utilizar programas o subprogramas que ya exis-


ten o es preciso construirlos totalmente. El proyecto se ha de dividir en mdulos utili-
zando los principios de diseo descendente. A continuacin se debe indicar la interaccin
entre mdulos; un diagrama de estructuras proporciona un esquema claro de estas rela-
ciones 2.
En este punto, es importante especificar claramente no slo el propsito de cada
mdulo, sino tambin el flujo de datos entre mdulos. Por ejemplo, se debe responder a
las siguientes preguntas: Qu datos estn disponibles al mdulo antes de su ejecucin?
Qu supone el mdulo? Qu hacen los datos despus de que se ejecuta el mdulo? Por
consiguiente, se deben especificar en detalle las hiptesis, entrada y salida para cada
mdulo. Un medio para realizar estas especificaciones es escribir una precondicin, que
es una descripcin de las condiciones que deben cumplirse al principio del mdulo, y una
postcondicin, que es una descripcin de las condiciones al final de un mdulo. Por
ejemplo, se puede describir un procedimiento que ordena una lista (un array) de la forma
siguiente:

procedure o rde nar (A, n)


(Ordena un a li sta en orden asce nd e nte
precondi cin : A e s u n array de N ente r os, 1 <= n < = Max.
postcondicin: A(l) < = A[2 ) < ... < = A [ n ) , n es ina l terable }

Por ltimo, se puede utilizar pseudocdigo 3 para especificar los detalles del algorit-
mo. Es importante que se emplee bastante tiempo en la fase de diseo de sus programas.
El resultado final de diseo descendente es una solucin que sea fcil de traducir en
estructuras de control y estructuras de datos de un lenguaje de programacin especfico,
en nuestro caso, Turbo Borland Pascal.

El gasto de tiempo' en la. 'fa.S d ,<,ts~osen ahorro de tiempo cuando se escriba y


depura su programa.
'., ' "-
" r ,
, 'i '. .. , . .. '

'i '
, ,

1.5.3. Implementacin (codificacin)


La etapa de implementacin (codificacin) traduce los algoritmos del diseo en un progra-
ma escrito en un lenguaje de programacin. Los algoritmos y las estructuras de datos reali-
zadas en pseudocdigo han de traducirse a un lenguaje que entienda la computadora.

2Para ampliar sobre este tema de diagramas de estructuras, puede consultar estas obras nuestras: Fun-
damentos de programacin, 2." edicin, McGraw-Hill, 1992; Problemas de metodologa de la programa-
cin, McGraw-Hill, 1992, o bien la obra Pascal y Turbo Pascal. Un enfoque prctico, de Joyanes, Zahonero
y Hermoso, en McGraw-Hill, 1995.
J Para consultar el tema del pseudocdigo, vanse las obras: Fundamentos de programacin. A 19orit-
.

mas y estructuras de datos, 2." edicin, McGraw-Hill, 1996, de Luis Joyanes, y Fundamentos de programa-
cin. Libro de problemas, McGraw-Hill, 1996, de Luis Joyanes, Luis Rodrguez y Matilde Fernndez.

,
Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 13

La codificacin ha de realizarse en un lenguaje de programacin. Los lenguajes clsicos


ms populares son PASCAL, FORTRAN, COBOL Y C; los lenguajes orientados a obje-
tos ms usuales son C++, Java, Visual BASIC, Smaltalk, etc.
La codificacin cuando un problema se divide en subproblemas, los algoritmos que
resuelven cada subproblema (tarea o mdulo) deben ser codificados, depurados y proba-
dos independientemente.
Es relativamente fcil encontrar un error en un procedimiento pequeo. Es casi imposible
encontrar todos los errores de un programa grande, que se codific y comprob como una
sola unidad en lugar de como una coleccin de mdulos (procedimientos) bien definidos.
Las reglas del sangrado (indentacin) y buenos comentarios facilitan la escritura del
cdigo. El pseudocdigo es una herramienta excelente que facilita notablemente la codi-
ficacin.

1.5.4. Pruebas e integracin


Cuando los diferentes componentes de un programa se han implementado y comproba-
do individualmente, el sistema completo se ensambla y se integra.
La etapa de pruebas sirve para mostrar que un programa es correcto. Las pruebas nunca
son fciles. Edgar Dijkstra ha escrito que mientras que las pruebas realmente muestran
la presencia de errores, nunca puede mostrar su ausencia. Una prueba con xito en la
ejecucin significa slo que no se han descubierto errores en esas circunstancias espec-
ficas, pero no se dice nada de otras circunstancias. En teora el nico modo que una
prueba puede mostrar que un programa es correcto, es verificar si todos los casos posi-
bles se han intentado y comprobado (es lo que se conoce como prueba exhaustiva); es
una situacin tcnicamente imposible incluso para los programas ms sencillos. Supon-
gamos, por ejemplo, que se ha escrito un programa que calcule la nota media de un
examen. Una prueba exhaustiva requerir todas las combinaciones posibles de marcas y
tamaos de clases; puede llevar muchos aos completar la prueba.
La fase de pruebas es una parte esencial de un proyecto de programacin. Durante la
fase de pruebas se necesita eliminar tantos errores lgicos como pueda. En primer lugar,
se debe probar el programa con datos de entrada vlidos que conducen a una solucin
conocida. Si ciertos datos deben estar dentro de un rango, se deben incluir los valores
en los extremos finales del rango. Por ejemplo, si el valor de entrada de n cae en el
rango de 1 a 10, se ha de asegurar incluir casos de prueba en los que n est entre 1 y 10.
Tambin se deben incluir datos no vlidos para comprobar la capacidad de deteccin de
errores del programa. Se han de probar tambin algunos datos aleatorios y por ltimo
intentar algunos datos reales .

1.5.5. Verificacin
La etapa de pruebas ha de comenzar tan pronto como sea posible en la fase de diseo y
continuar a lo largo de la implementacin del sistema. Incluso aunque las pruebas son
herramientas extremadamente vlidas para proporcionar la evidencia de que un programa
es correcto y cumple sus especificaciones, es dificil conocer si las pruebas realizadas


r
,

, 14 Estructura de datos
I
son suficientes. Por ejemplo, cmo se puede conocer que son suficientes los diferentes
conjuntos de datos de prueba o que se han ejecutado todos los caminos posibles a travs
del programa?
Por esas razones se ha desarrollado un segundo mtodo para demostrar la correccin
o exactitud de un programa. Este mtodo, denominado verificacin formal, implica la
construccin de pruebas matemticas que ayudan a determinar si los programas hacen
lo que se supone han de hacer. La verificacin fOlmal implica la aplicacin de reglas
formales para mostrar que un programa cumple su especificacin: la verificacin. La
verificacin formal funciona bi<;!n en programas pequeos, pero es compleja cuando se
utiliza en programas grandes. La teora de la verificacin requiere conocimientos
matemticos avanzados y por otra parte se sale fuera de los objetivos de este libro; por
esta razn slo hemos constatado la importancia de esta etapa.
La prueba de que un algoritmo es correcto es como probar un teorema matemtico. Por
ejemplo, probar que un mdulo es exacto (correcto) comienza con las precondiciones
(axiomas e hiptesis en matemticas) y muestra que las etapas del algoritmo conducen a
las postcondiciones. La verificacin trata de probar con medios matemticos que los
algoritmos son correctos.
Si se descubre un error durante el proceso de verificacin, se debe corregir su algo-
ritmo y posiblemente se han de modificar las especificaciones del problema. Un mtodo
es utilizar invariantes (una condicin que siempre es verdadera en un punto especfico
de un algoritmo), lo que probablemente har que su algoritmo contenga pocos errores
antes de que comience la codificacin. Como resultado se gastar menos tiempo en la
depuracin de su programa.

1.5.6. Mantenimiento
Cuando el producto software (el programa) se ha terminado, se distribuye entre los posi-
bles usuarios, se instala en las computadoras y se utiliza (produccin). Sin embargo, y
aunque a priori el programa funcione correctamente, el software debe ser mantenido
y actualizado. De hecho, el coste tpico del mantenimiento excede, con creces, el coste
de produccin del sistema original.
Un sistema de software producir errores que sern detectados, casi con seguridad,

por los usuarios del sistema y que no se descubrieron durante la fase de prueba. La correc-
cin de estos errores es parte del mantenimiento del software. Otro aspecto de la fase de
mantenimiento es la mejora del software aadiendo ms caractersticas o modificando
partes existentes que se adapten mejor a los usuarios.
Otras causas que obligarn a revisar el sistema de software en la etapa de mantenimien-
to son las siguientes: 1) Cuando un nuevo hardware se introduce, el sistema puede ser
modificado para ejecutarlo en un nuevo entorno; 2) Si cambian las necesidades del usuario,
suele ser menos caro y ms rpido, modificar el sistema existente que producir un siste-
ma totalmente nuevo. La mayor parte del tiempo de los programadores de un sistema se
gasta en el mantenimiento de los sistemas existentes y no en el diseo de sistemas total-
mente nuevos. Por esta causa, entre otras, se ha de tratar siempre de disear programas
de modo que sean fciles de comprender y entender (legibles) y fciles de cambiar,

,
l

Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 15

1.5.7. La obsolescencia: programas obsoletos


La ltima etapa en el ciclo de vida del software es la evolucin del mismo, pasando por
su vida til hasta su obsolescencia o fase en la que el software se queda anticuado y es
preciso actualizarlo o escribir un nuevo programa sustitutorio del antiguo.
La decisin de dar de baja un software por obsoleto no es una decisin fcil. Un sistema
grande representa una inversin enorme de capital que parece, a primera vista, ms barato
modificar el sistema existente, en vez de construir un sistema totalmente nuevo. Este
criterio suele ser, normalmente, correcto y por esta causa los sistemas grandes se disean
para ser modificados. Un sistema puede ser productivamente revisado muchas veces.
Sin embargo, incluso los programas grandes se quedan obsoletos por caducidad de tiempo
al pasar una fecha lmite determinada. A menos que un programa grande est bien escri-
to y adecuado a la tarea a realizar, como en el caso de programas pequeos, suele ser
ms eficiente escribir un nuevo programa que corregir el programa antiguo.

1.5.8. Iteracin y evolucin del s


Las etapas de vida del software suelen formar parte de un ciclo o bucle, como su nombre
sugiere, y no son simplemente una lista lineal. Es probable, por ejemplo, que durante la
fase de mantenimiento tenga que volver a las especificaciones del problema para verifi-
carlas o modificarlas.
Obsrvese en la Figura 1.4 que las diferentes etapas rodean al ncleo documenta-
cin. La documentacin no es una etapa independiente como se puede esperar sino que
est integrada en todas las etapas del ciclo de vida del software.

,
;

I Mantenimiento Especificaciones
i,

Evolucin Diseo

Produccin Verificacin

Pruebas Codificacin

!,

Figura 1.4. Etapas del ciclo de vida del software cuyo ncleo aglutinador
es la documentacin.
16 Estructura de datos

1.6. MTODOS FORMALES DE VERIFICACiN


DE PROGRAMAS

Aunque la verificacin formal de programas se sale fuera del mbito de este libro, por su
importancia vamos a considerar dos conceptos clave, asertos (afirmaciones) y precondi-
ciones/postcondiciones invariantes que ayuden a documentar, corregir y clarificar el di-
seo de mdulos y de programas.

1.6.1. Aserciones (asertos) 4


Una parte importante de una verificacin formal es la documentacin de un programa a
travs de asertos o aserciones, sentencias lgicas acerca del programa que se declaran

verdaderas. Un aserto se escribe como un comentario y describe lo que se supone sea


verdadero sobre las variables del programa en ese punto.

Una asercin (aserto) es una frase sobre una condicin especfica en un cierto
punto de un algoritmo o programa.

EJEMPLO 1.1
El siguiente fragm ento de programa contiene una secuencia de sentencias de asigna-
cin, seguidas por un aserto:

A

-- 10 ; ( as e r t o : A e s lO )
x
-- A ,' {as er t o : X es lO }
y -
- x + A; {aser t o : Y e s 2 0}

La verdad de la primera afirmacin, { A e s lO} , sigue a la ejecucin de la pri-


mera sentencia con el conocimiento de que lOes una constante. La verdad de la segun-
da afirmacin, {X e s lO } , sigue de la ejecucin de x : = A con el conocimiento de
que A e s 1 0 . La verdad de la tercera afirmacin, {Y e s 2 O } , sigue de la ej ecucin
y : = X + A con el conocimiento de que X es 1 0 Y A es 10 . En este segmento
del programa se utilizan afirmaciones como comentarios para documentar el cambio en
una variable de programa despus que se ejecuta cada sentencia de afirmacin.
La tarea de utilizar verificacin formal es probar que un segmento de programa cumple
su especificacin. La afirmacin final se llama postcondicin (en este caso, { Y e s 2 O} )
y sigue a la presuncin inicial oprecondicin (en este caso, {l O es una co n s tan te} )
despus que se ejecuta el segmento de programa.

Este trmino se suele traducir tambin por afirmaciones o declaraciones. El trmino aserto est ms
4

extendido en la jerga informtica, y al igual que aserto , estn los dos trminos admitidos por el DRA E.


!
Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 17

1.6.2. Precondiciones y postcondiciones


Las precondiciones y postcondiciones ya citadas anteriormente son afirmaciones
sencillas sobre condiciones al principio y al final de los mdulos. Una precondicin de
un procedimiento es una afirmacin lgica sobre sus parmetros de entrada; se supone
que es verdadera cuando se llama al procedimiento. Una pos/condicin de un procedi-
miento puede ser una afirmacin lgica que describe el cambio en el estado del progra-
ma producido por la ejecucin del procedimiento; la postcondicin describe el efecto de
llamar al procedimiento. En otras palabras, la postcondicin indica que ser verdadera
despus que se ejecute el procedimiento.

,
EJEMPLO 1.2
,
{Precondiciones y postcondiciones del procedimiento LeerEnteros}
procedure LeerEnteros (Min, Max:lnteger; var N: Integer);
{
Lectura de un entero entre Min y Max en N
Pre : Min y Max son valores asignados
Post: devuelve en N el primer valor del dato entre Min y Max
I si Min <= Max es verdadero; en caso contrario
I
i N no est definido.
}

La precondicin indica que los parmetros de entrada Min y Max se definen antes
de que comience la ejecucin del procedimiento. La postcondicin indica que la ejecu-
cin del procedimiento asigna el primer dato entre Min y Max al parmetro de salida
I, siempre que Min < = Max sea verdadero.
,
Las precondiciones y postcondiciones son ms que un mtodo para resumir acciones de
I un procedimiento. La declaracin de estas condiciones debe ser la primera etapa en el
diseo y escritura de un procedimiento. Es conveniente en la escritura de algoritmos de
procedimientos, se escriba la cabecera del procedimiento que muestra los parmetros
afectados por el procedimiento as como unos comentarios de cabecera que contienen
las precondiciones y postcondiciones.

Precondicin: Predicado lgico que debe cumplirse al comenzar la ejecucin


I de una operacin.
Postcondicin: Predicado lgico .quedebecumplirs.e alacabarJa ejecucin de
una operacin; siempre que se haya cumplido previamente laprecondicin co- ." .
rrespondiente..

1.6.3. Reglas para prueba de programas


I
I
!
Un medio til para probar que un programa P hace lo que realmente ha de hacer es
,,
proporcionar aserciones (asertos) que expresen las condiciones antes y despus de que
P sea ejecutada. En realidad las aserciones son como sentencias o declaraciones
que pueden ser o bien verdaderas o bien falsas .

I,
I,

,,
~
,
18 Estructura de datos

La primera asercin, la precondicin, describe las condiciones que han de ser verda-
deras antes de ejecutar P.
La segunda asercin, la postcondicin, describe las condiciones que han de ser ver-
daderas despus de que P se ha ejecutado (suponiendo que la precondicin fue verdade-
ra antes). El modelo general es:

(precondicin) {= condiciones l gicas que son


verdaderas antes de que P se eje cut e }
(postcondicin) {= condiciones lg ica s que son ve rdaderas
despus de que P se e j ec ute}

EJE LO 1.3
I
,
ElprocedimientoOrdenarSele cc ion (A, m, n) ordena a los elementosdelarray.
A [m . . n] en orden descendente. El modelo correspondiente puede escribirse as:

{m ~ n} {preco ndicin: A ha de t e n e r al menos 1 ele me n to}


Ordena rSe l ecci on (A , m, nl {programa de or denacin a e j ecutar}
( A[m] > A [m+l ] ~ ... ~ A[n] {postcondic i n : elementos d e A en orden
descendent e }

PROBLEMA 1.1

Encontrar la posicin del elemento mayor de una lista con indicacin de precondicio-
nes y postcondiciones.
function EncontrarMax (var A:Lista; m, n: Integerl : Integer;
{preco ndicin : m < n}
{pos tcondicin : devuelv e posic in eleme nto mayor en A[m .. n]}
var i, j : In t eger ;

begin

l := m;
j : = n ; {aser c i n}
repeat
i :=i+l 0 ;
i f A [ i] > A [ j] then j : = i ;
until i = n;

En co ntrarMax : = J ; {devuelve j como elemento mayor}
end;

PROBLEMA 1.2

Ordenar por el mtodo seleccin con precondiciones y postcondiciones:


procedure Ord e nar Se l eccion ( var A:L is t a; m, n : I n t ege rl;
{prec o ndicin : m ~ n }
(postcond i c i n : A [m ,n] est o r d enado ta l que
A[m] ~ A[m+l] ~ ... ~ A[ n])
Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 19

var PosicionMax, Aux : Integer;


begin
if m < n then
begin
posicionMax := EncontrarMax(A,m,n);
{Intercambiar A[m] ~ A[PosicionMax]}
Aux := A[m];
A[m] := A[PosicionMax];
A[PosicionMax] := Aux;
OrdenarSeleccion (A,m+l,n);
{produce: A[m+l] ~ A[m+2) ~ ... A[n)}
end {if}
{Asercin final: A[m) ~ A[m+l) ~ ... ~ A[n)}
end {OrdenarSeleccion}

1.6.4. Invariantes de bucles


Una invariante de bucle es una condicin que es verdadera antes y despus de la ejecu-
cin de un bucle. Las invariantes de bucles se utilizan para demostrar la correccin (exac-
titud) de algoritmos iterativos. Utilizando invariantes, se pueden detectar errores antes
de comenzar la codificacin y por esa razn reducir tiempo de depuracin y prueba.

1.4

Un bucle que calcula la suma de los n primeros elementos del array (lista) A:

{calcular la suma de A[l), A[2], ... A[n)}


{asercin n >= 14}
Suma := O;
J' .. -- l ',
while j <= n do
begin
Suma := Suma + A[j);
j := succ(j)
end

Antes de que este bucle comience la ejecucin Suma es O y j es l. Despus que el


bucle se ha ejecutado una vez, Suma es A [1] Y j es 2.
Invariante del bucle Suma es la suma de los elementos A [1] a A [ j + 1] .

EJEMPLO 1.5

Invariante de un bucle que sume n enteros (n entero positivo); i, Suma, n son de tipo
entero.
20 Estructura de datos

{aser c i n n>= 1 } {p r e con d ici n }


su ma : = O;
1, . -- l ',
whi1e i <= n do
begin
,
Suma := Suma + l;
,
1 .
.-
- i + 1
end
{asercin : Suma es 1+2 +3 + ... +n-1 +n} {po stcond i c i n}

Una invariante del bucle puede ser:


{invariante: i <= n y S u ma es 1+2+ . . i- 1 }

lo que significa: i debe ser menor que o igual que n y despus de cada pasada o vuelta,
Suma es igual a la suma de todos los enteros positivos menores que i.
En la verificacin de programas la invariante del bucle se utiliza para probar que el
bucle cumple su especificacin. Para nuestro propsito, se puede utilizar el invariante
del bucle para documentar el comportamiento del mismo y se situar justo antes del
cuerpo del bucle.

{Suma de enteros 1 a n}
{prec o ndicin : n > = 1}
Suma := O;
1, - ,
. - 1
while i <= n do
{ in variante : i <= n +1 y Suma es 1+2+ ... i - 1}
begin
,
Suma : Suma + l ;
,
1 . -- i+1
.

end;
{p o stco ndicin : Suma es 1+2+3+ .. n-1+n}

Invariantes de bucle como herramientas de diseo


. .. .,
Otra aplicacin de los invariantes de bucle es la especificacin del bucle: InIClaClOn,
condicin de repeticin y cuerpo del bucle.

EJEMPLO 1.6
Si la variante de un bucle es:
{invariante: i <= n y Suma es la suma de todos los nmeros ledo s del
t eclado}

Se puede deducir que:


S uma := 0.0: { ini ciac i n}
l

. -- O',
1 < n {condi cin / prueba del bucle}
Read (Item);
Suma : = Suma + I tem ; {cuerpo del bucle}
i :=i+l

,
Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 21

Con toda esta informacin es una tarea fcil escribir el bucle de suma :

Suma : = 0.0;
i : = O;
while i do <{y , toma l os va lores 0,1, 2 , 3 , .. n - 1}
n
Rea d ( Item);
Su ma : = Su ma + Item ;
i : = i + 1
end;

EJEMPLO 1.7

En los bucles for es p osible declarar tambin invariantes, pero teniendo presente
la particularidad de esta sentencia: la variable de control del bucle es indefinida des-
pus que se sale del bucle, p or lo que para definir su invariante se ha de considerar que
dicha variable de control se incrementa antes de salir del bucle y mantiene su valor
.fi nal.

{preco nd icin n > = l }


Suma : = o;
for i : = 1 to n do
{i n va ri ante : i < = n +l y Su ma es 1+2+ ... i -l }
Suma : = Suma + i ;
{postcondi ci n : Su ma es 1+ 2 +3 + .. n - l +n }

PROBLEMA 1.3

Escribir un bucle controlado p or centinela que calcule el producto de un conjunto de


datos.

{Ca l cula r el pr oducto de una se rie de d at os }


{preco n dicin : cen tin e l a es con stante }
Pr o ducto := 1 ;
Wr ite ln ( ' Par a t erm in a r, i n t roduzca ', Cent i nel a : 1);
Writeln ( ' I ntr odu zca n mero :' ) ;
ReadLn (Numero);
while Nume ro <> Centinel a do
{invarian t e : Pro duc to es el produ c to d e tod os los valore s l edos en
N mero y n ing u n o era el Ce ntine l a }
begin
Pr oduc t o := P r oducto * Numer o ;
Wri t eLn ( ' I n troduzca nme ro si gu i en te :' ) ;
Rea dL n (Nu mero)
end;
{p ostco ndici n : Pr oducto es e l produc to de todos los n meros l edo s e n
Nu me ro ant e s de l ce n t i n e la }
22 Estructura de datos

1.6.5. Etapas a establecer la exactitud (correccin)


de un programa
Se pueden utilizar invariantes para establecer la correccin (exactitud) de un algoritmo
iterativo. Supongamos el algoritmo ya estudiado anteriormente.
{calcular la suma d e A[lJ, A[2J, ... A[n] }
Suma .. -- O;
J

-- 1;

while J < = N do
begin
Suma -- S u ma + A [ j ] ;
--

J suc c (j)
end
{ invar i ante: Suma es l a suma de l o s element os A[l] a A [j- l ] }

Los siguientes cuatro puntos han de ser verdaderos 5:


l. El invariante debe ser inicialmente verdadero, antes de que comience la ejecu-
cin por primera vez del bucle. En el ejemplo anterior, Suma es O y j es 1
inicialmente. En este caso, el invariante significa que Suma contiene la suma de
los elementos A [1] a A [ O] , que es verdad ya que no hay elementos en este
rango.
2. Una ejecucin del bucle debe mantener el invariante. Esto es si el invariante
es verdadero antes de cualquier iteracin del bucle, entonces se debe demostrar
que es verdadero despus de la iteracin. En el ejemplo, el bucle aade A [ j] a
Suma ya continuacin incrementa j en l. Por consiguiente, despus de una eje-
cucin del bucle, el elemento aadido ms recientemente a Suma es A [ j -1] ;
esto es, el invariante que es verdadero despus de la iteracin.
3. El invariante debe capturar la exactitud del algoritmo. Esto es, debe demos-
trar que si el invariante es verdadero cuando termina el bucle, el algoritmo es
correcto. Cuando el bucle del ejemplo termina, j contiene N + 1 Y el invariante
es verdadero: Suma contiene la suma de los elementos A [1] a A [J -1] , que es
la suma que se trata de calcular.
4. El bucle debe terminar. Esto es, se debe demostrar que el bucle termina des-
pus de un nmero finito de iteraciones. En el ejemplo, j comienza en 1 y a
continuacin se incrementa en 1 en cada ejecucin del bucle. Por consiguiente,
j eventualmente exceder a N con independencia del valor de N. Este hecho y la
caracterstica fundamental de while garantizan que el bucle terminar.

La identificacin de invariantes de bucles ayuda a escribir. bucles correct()s. Se


representa el invariante como un comentario que precede a cada bucle. En el ejem-
plo anterior:
{Invariante: 1 <= j < = N+l y Suma = A[l] + ... +A [j-l]}
while j <= N do
L

5 Carrasco, Helman y Verof, op. cit., pg. 15.


Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 23

1.7. -
PRINCIPIOS DE DISENO DE SIST S DE SOFTWARE

El diseo de sistemas de software de calidad requiere el cumplimiento de una serie de


caractersticas y objetivos. En un sentido general los objetivos a conseguir que se consi-
deran tiles en el diseo de sistemas incluyen al menos los siguientes principios:

l. Modularidad mediante diseo descendente.


2. Abstraccin y ocultamiento de la informacin.
3. Modificabilidad.
4. Comprensibilidad y fiabilidad.
5. Interfaces de usuario.
6. Programacin segura contra fallos.
7. Facilidad de uso.
8. Eficiencia.
9. Estilo de programacin.
10. Depuracin.
1 1. Documentacin.

1.7.1. Modularidad mediante diseo descendente


Un principio importante que ayuda a tratar la complejidad de un sistema es la modula-
ridad. La descomposicin del problema se realiza a travs de un diseo descendente que
a travs de niveles sucesivos de refinamiento se obtendrn diferentes mdulos. Normal-
mente los mdulos de alto nivel especifican qu acciones han de realizarse mientras que
los mdulos de bajo nivel definen cmo se realizan las acciones.
La programacin modular tiene muchas ventajas. A medida que el tamao de un
programa crece, muchas tareas de programacin se hacen ms difciles. La diferencia
principal entre un programa modular pequeo y un programa modular grande es, sim-
plemente, el nmero de mdulos que cada uno contiene, ya que el trabajo con programas
modulares es similar y slo se ha de tener presente el modo en que unos mdulos inter-
,
actuan con otros.
La modularidad tiene un impacto positivo en los siguientes aspectos de la progra-
.,
maClOn:

Construccin del programa. La descomposicin de un programa en mdulos


permite que los diversos programadores trabajen de modo independiente en cada
uno de sus mdulos. El trabajo de mdulos independientes convierte la tarea de es-
cribir un programa grande en la tarea de escribir muchos programas pequeos.
Depuracin del programa. La depuracin de programas grandes puede ser una
tarea enorme, de modo que se facilitar esa tarea, al centrarse en la depuracin de
pequeos programas ms fciles de verificar.
Legibilidad. Los programas grandes son muy difciles de leer, mientras que los
programas modulares son ms fciles de leer.


24 Estructura de datos

Eliminacin de cdigo redundante. Otra ventaja del diseo modular es que se


pueden identificar operaciones que suceden en muchas partes diferentes del pro-
grama y se implementan como subprogramas. Esto significa que el cdigo de una
operacin aparecer slo una vez, produciendo como resultado un aumento en la
legibilidad y modificabilidad.

1.7.2. Abstraccin y encapsulamiento


La complejidad de un sistema puede ser gestionado utilizando abstraccin. La abstrac-
cin es un principio comn que se aplica en muchas situaciones. La idea principal es
definir una parte de un sistema de modo que puede ser comprendido por s mismo (esto
es, como una unidad) sin conocimiento de sus detalles especficos y sin conocimiento de
cmo se utiliza esta unidad a un nivel ms alto.
Existen dos tipos de abstracciones: abstraccin procedimental y abstraccin de da-
tos. La mayora de los lenguajes de programacin soportan este tipo de abstraccin. Es '
aquella en que se separa el propsito de un subprograma de su implementacin. Una vez
que se ha escrito un subprograma, se puede utilizar sin necesidad de conocer las peculia-
ridades de sus algoritmos. Suponiendo que el subprograma est documentado adecuada-
mente, se podr utilizar con slo conocer la cabecera del mismo y sus comentarios des-
criptivos; no necesitar conocer su cdigo.
La modularidad tratada anteriormente y la abstraccin procedimental se com-
plementan entre s. La modularidad implica la rotura de una solucin en mdulos; la
abstraccin procedimental implica la especificacin de cada mdulo claramente antes
de que se implemente en Pascal. De hecho, lo importante es poder utilizar los subprogramas
predefinidos, tales como Wri teln, Sqrt, etc., o bien los definidos por el usuario sin
necesidad de conocer sus algoritmos.
El otro tipo de abstraccin es la abstraccin de datos, soportada hoy da por diversos
lenguajes Turbo Borland Pascal, C++, Ada-83, Ada-95. Modula-2, etc. El propsito de
la abstraccin de datos es aislar cada estructura de datos y sus acciones asociadas. Es de-
cir, se centra la abstraccin de datos en las operaciones que se realizan sobre los datos en
lugar de cmo se implementan las operaciones. Supongamos, por ejemplo, que se tiene
una estructura de datos Clientes, que se utiliza para contener informacin sobre los
clientes de una empresa, y que las operaciones o acciones a realizar sobre esta estructura
de datos incluyen Insertar, Buscar y Borrar. El mdulo, objeto o tipo abstracto de datos,
Ti poC 1 i en t e es una coleccin de datos y un conjunto de operaciones sobre esos datos.
Tales operaciones pueden aadir nuevos datos, buscar o eliminar datos. Estas operaciones
constituyen su interfaz, mediante la cual se comunica con otros mdulos u objetos.
Un tipo abstracto de datos (TAD) se implementar mediante unidades en Turbo
BorIand Pascal. Por su importancia se dedicar un captulo completo a tratar ms deteni-
damente el concepto de un TAD, su diseo e implementacin prctica (captulo 3).
Otro principio de diseo es la ocultacin de la informacin. El propsito de la ocul-
tacin de la informacin es hacer inaccesible ciertos detalles que no afecten a los otros
mdulos del sistema. Por consiguiente, el objeto y sus acciones constituyen un sistema
cerrado, cuyos detalles se ocultan a los otros mdulos.

i
Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 25

La abstraccin identifica los aspectos esenciales de mdulos y estructura de datos,


que se pueden tratar como cajas negras. La abstraccin indica especificaciones funcio-
nales de cada caja negra; es responsable de su vista externa o pblica. Sin embargo, la
abstraccin ayuda tambin a identificar detalles de lo que se debe ocultar de la vista
pblica detalles que no estn en las especificaciones pero deben ser privados . El
principio de ocultacin de la informacin no slo oculta detalles dentro de la caja negra
. sino que tambin asegura que ninguna otra caja negra pueda acceder a estos detalles
ocultos. Por consiguiente, se deben ocultar ciertos detalles dentro de sus mdulos y TAD,
Y hacerlos inaccesibles a los restantes mdulos y TAD.
La abstraccin de datos y su expresin ms clara el tipo abstracto de datos, se imple-
menta en Turbo Borland Pascal con unidades.

1.7.3. Modificabilidad

La modificabilidad (facilidad de modificacin) se refiere a los cambios controlados de


un sistema dado. Un sistema se dice que es modificable si los cambios en los requisitos
pueden adecuarse bien a los cambios en el cdigo. Es decir, un pequeo cambio en los
requisitos en un programa modular normalmente requiere un cambio pequeo slo en
algunos de sus mdulos; es decir, cuando los mdulos son independientes (esto es, d-
bilmente acoplados) y cada mdulo realiza una tarea bien definida (esto es, altamente
cohesivos). La modularidad asla las modificaciones.
Las tcnicas ms frecuentes para hacer que un programa sea fcil de modificar son:
uso de subprogramas y uso de constantes definidas por el usuario.
El uso de procedimientos tiene la ventaja evidente, no slo de eliminar cdigo
redundante sino tambin hace el programa resultante ms modificable. Normalmente
ser un signo de mal diseo de un programa que pequeas modificaciones a un pro-
grama requieran su reescritura completa. Un programa bien estructurado en mdulos
ser modificable ms fcilmente; es decir, si cada mdulo resuelve slo una pequea
parte del problema global, un cambio pequeo en las especificaciones del problema nor-
malmente slo afectar a unos pocos mdulos y en consecuencia eso facilitar su modi-
ficacin.
Las constantes definidas por el usuario o con nombre son otro medio para mejorar la
modificabilidad de un programa.

EJEMPLO 1.8

Los lmites del rango de un array suelen ser definidos mejor mediante constantes con
nombre que mediante constantes numricas. As, la declaracin tpica de un array y su
proceso posterior mediante un bucle es:

type T i poP unt os = array [1 .. 1 00 } of in tege r;


for i := 1 to 1 00 do
proceso d e l os e lementos
26 Estructura de datos

El diseo ms eficiente podra ser:

const NumeroDel t ems = 100 ;


type TipoPunto = array [l .. NumeroDeltemsl of i nteger ;
for i := 1 to Num e roD e l tems do
proces o de los element os

ya que cuando se desee cambiar el nmero de elementos del array slo sera necesario
cambiar el valor de la constante NumeroDeItems, mientras que en el caso anterior
supondr cambiar la declaracin del tipo y el ndice de bucle, mientras que en el segun-
do caso slo el valor de la constante.

, 1.7.4. Comprensibilidad y fiabilidad


, Un sistema se dice que es comprensible si refleja directamente una visin natural del
,
mundo 6. Una caracterstica de un sistema eficaz es la simplicidad. En general, un siste-
ma sencillo puede ser comprendido ms fcilmente que uno complejo.
Un objetivo importante en la produccin de sistemas es el de la fiabilidad. El objeti-
vo de crear programas fiables ha de ser crtico en la mayora de las situaciones.

1.7.5. Interfaces de usuario


Otro criterio importante a tener presente es el diseo de la interfaz del usuario. Algunas
directrices a tener en cuenta pueden ser:

En un entorno interactivo, se ha de tener en cuenta las preguntas posibles al usua-


rio y sobre todo aquellas que solicitan entradas de usuario.
Es conveniente que se realicen eco de las entradas de un programa. Siempre que
un programa lee datos, bien de usuario a travs de un terminal o de un archivo, el
programa debe incluir los valores ledos en su salida.
Etiquetar (rotular) la salida con cabeceras y mensajes adecuados.

1.7.6. Programacin segura contra fallos


Un programa es seguro contra fallos cuando se ejecuta razonablemente por cualquiera
que 10 utilice. Para conseguir este objetivo se han de comprobar los errores en datos de
entrada y en la lgica del programa.
Supongamos un programa que espera leer datos enteros positivos pero lee ,25. Un
mensaje tpico a visualizar ante este error suele ser:

Erro r de rang o

6Tremblay, Donrek y Bunt: Infroducfion fo Computer Science. An Algorithmic approach, McGraw-


Hill, 1989, pg. 440.

i,

,
- - - - - - - -- - ----------------------------------------------_.

Ingenierfa de software: introduccin a la metodologa de construccin de grandes programas 27

Sin embargo, es ms til un mensaje tal como ste:


-25 no es un nmero vlido de aos
Por favor vuelva a introducir el nmero

Otras reglas prcticas a considerar son:

No utilizar tipos subrango para detectar datos de entrada no vlidos. Por ejemplo,
si se desea comprobar que detelminados tipos nunca sean negativos, se pueden
cambiar las definiciones de tipo global a:
type TipoNoNeg - O .. maxint; {tipo nuevo}
TipoMillar = Bajo .. Alto; {permanece el mismo}
TipoTabla = array[TipoMillar] of TipoNoNeg;
{un array de este tipo contiene s610 enteros no negativos}

Comprobar datos de entrada no vlidos


ReadLn (Grupo, Nmero)

if Nmero >= O
then agregar Nmero a total
elee manejar el error.

Cada subprograma debe comprobar los valores de sus parmetros. As, en el caso
de la funcin S urna 1 n te rv a 1 o que suma todos los enteros comprendidos

entre m y n .
function Sumalntervalo (m,n:lnteger) : Integer;
{
precondici6n : m y n son enteros tales que m < = n
postcondici6n: Devuelve Sumalntervalo = m+(m+l)+ ... +n
m y n son inalterables
}
var Suma, Indice : Integer;
begin
Suma := O;
for Indice := m to n do
Suma := Suma + Indice;
Sumalntervalo := Suma
end;

1.7.7. Facilidad de uso


La utilidad de un sistema se refiere a su facilidad de uso. Esta propiedad ha de tenerse
presente en todas las etapas del ciclo de vida, pero es vital en la fase de diseo e implemen-
., .,
taclOn o construcclOn.

1.7.8. Eficiencia
El objetivo de la eficiencia es hacer un uso ptimo de los recursos del programa. Tradicio-
nalmente, la eficiencia ha implicado recursos de tiempo y espacio. Un sistema eficiente

- _ .. _...
28 Estructura de datos

es aquel cuya velocidad es mayor con el menor espacio de memoria ocupada. En tiempos
pasados los recursos de memoria principal y de CPU eran factores clave a considerar para
aumentar la velocidad de ejecucin. En el ao 1997 las CPU (UCP, Unidad Central de
Proceso) tpicas de los PC eran Pentium de 166 y 200 MHz. En el ao 1988 son usuales
los Pentium de 233 Mhz y Pentium 11 de 266 Mhz y son ya muy frecuentes; las memo-
rias centrales usuales son 16 Mbytes o 32 Mbytes, aunque bsicamente los tamaos de
memorias tradicionales para trabajos profesionales ya son de un mnimo de 64 Mbytes;
el factor eficiencia ya no se mide con los mismos parmetros de memoria y tiempo. Hoy
da debe existir un compromiso entre legibilidad, modificabilidad y eficiencia, aunque,
con excepciones, prevalecer la legibilidad y modificabilidad.

1.7.9. Estilo de programacin, documentacin y depuracin


Estas caractersticas hoy da son claves en el diseo y construccin de programas, por esta
causa dedicaremos por su especial importancia tres secciones independientes para tratar
estos criterios de diseo.

,
1.8. ESTILO DE PROGRAMACION

Una de las caractersticas ms importantes en la construccin de programas, sobre todo


los de gran tamao, es el estilo de programacin. La buena calidad en la produccin de
programas tiene relacin directa con la escritura de los mismos, su legibilidad y com-
prensibilidad. Un buen estilo de programacin suele venir con la prctica, pero el re-
querimiento de unas reglas de escritura del programa, al igual que sucede con la sinta-
xis y reglas de escritura de un lenguaje natural humano, debe buscar esencialmente que
no slo sean legibles y modificables por las personas que lo han construido sino tambin
-y esencialmente puedan ser ledos y modificados por otras personas distintas. No
existe una frmula mgica que garantice programas legibles, pero existen diferentes re-
glas que facilitarn la tarea y con las que prcticamente suelen estar de acuerdo casi
todos, desde programadores novatos a ingenieros de software experimentados.
Naturalmente las reglas de estilo para construir programas claros, legibles y fcil-
mente modificables, depender del tipo de programacin y lenguaje elegido. En nuestro
caso y dado que el tipo de programacin es estructurado y el lenguaje es Pascal/Turbo
Borland Pascal, nos centraremos en este enfoque, pero estas reglas sern fcilmente ex-
trapolables a otros lenguajes estructurados tales como C, C++, Ada, Modula-2, etc.

Reglas de estilo de programacin


.
l. Modularizar un programa en partes coherentes (uso amplio de subprogramas) .

2. Evitar variables globales en subprogramas.


3. Usar nombres significativos para identificadores.
4. Definir constantes con nombres al principio del programa.
5. Evitar el uso del goto y no escribir nunca cdigo spaghetti.

Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 29


6. Escribir subrutinas cortas que hagan una sola cosa y bien.


7. U so adecuado de parmetros variable.
8. Usar declaraciones de tipos.
9. Presentacin (comentarios adecuados).
10. Manejo de errores.
11. Legibilidad.
12. Documentacin.

1.8.1. Modularizar un programa en subprogramas


Un programa grande que resuelva un problema complejo siempre ha de dividirse en
mdulos para ser ms manejable. Aunque la divisin no garantiza un sistema bien organi-
zado ser preciso encontrar reglas que permitan conseguir esa buena organizacin.
Uno de los criterios clave en la divisin es la independencia; esto es, el acoplamiento
de mdulos; otro criterio es que cada mdulo debe ejecutar una sola tarea, una funcin
relacionada con el problema. Estos criterios fundamentalmente son acoplamiento y cohe-
sin de mdulos, aunque existen otros criterios que no se tratarn en esta seccin.
El acoplamiento se refiere al grado de interdependencia entre mdulos. El grado de
acoplamiento se puede utilizar para evaluar la calidad de un diseo de sistema. Es preciso
minimizar el acoplamiento entre mdulos, es decir, minimizar su interdependencia. El
criterio de acoplamiento es una medida para evaluar cmo un sistema ha sido modulari-
zado. Este criterio sugiere que un sistema bien modularizado es aquel en que las interfa-
ces sean claras y sencillas.
Otro criterio para juzgar un diseo es examinar cada mdulo de un sistema y deter-
minar la fortaleza de la ligadura (enlace) dentro de ese mdulo. La fortaleza interna
de un mdulo, esto es, lo fuertemente (estrictamente) relacionadas que estn entre s las
partes de un mdulo, se conoce como propiedad de cohesin. Un modelo cuyas par-
tes estn fuertemente relacionadas con cada uno de los otros se dice que es fuertemente
cohesivo. Un modelo cuyas partes no estn relacionadas con otras se dice que es cohesi-
vo dbilmente.

Los mdulos de un programa deben estar dbilmente acoplados y fuertemente co-


hesionados.

Como regla general es conveniente utilizar subprogramas ampliamente. Si un con-


junto de sentencias realiza una tarea recurrente, repetitiva, identificable, debe ser un
subprograma. Sin embargo, una tarea no necesita ser recurrente para justificar el uso de
un subprograma.

1.8.2. Evitar variables globales en subprogramas


Una de las principales ventajas de los subprogramas es que pueden implementar el con-
cepto de mdulo aislado. El aislamiento se sacrifica cuando un subprograma accede a

30 Estructura de datos

variables globales, dado que los efectos de sus acciones producen los efectos laterales
indeseados, normalmente.
En general, el uso de variables globales con subprogramas no es correcto. Sin em-
bargo, el uso de la variable global, en s, no tiene porqu ser perjudicial. As, si un dato
es inherentemente importante en un programa al que casi todo subprograma debe acce-
der al mismo, entonces ese dato ha de ser global por naturaleza.

1.8.3. Usar nombres significativos para identificadores


Los identificadores que representan los nombres de mdulos, subprogramas, funciones, ti-
pos, variables y otros elementos, deben ser elegidos apropiadamente para conseguir pro-
gramas legibles. El objetivo es usar interfaces significativas que ayuden al lector a recordar
el propsito de un identificador sin tener que hacer referencia continua a declaraciones o
listas externas de variables. Hay que evitar abreviaturas crpticas.
Identificadores largos se deben utilizar para la mayora de los objetos significativos
, de un programa, as como los objetos utilizados en muchas posiciones, tales como, por
I ejemplo, el nombre de un programa usado frecuentemente. Identificadores ms cortos se
utilizarn estrictamente para objetos locales: as, i, j, k, son tiles para ndices de arrays
en un bucle, variables contadores de bucle, etc., y son ms expresivos que 1 n die e,
VariableDeControl,e~.
Los identificadores deben utilizar letras maysculas y minsculas. Cuando un identifi-
cador consta de dos o ms palabras, cada palabra debe comenzar con una letra mayscula.
Una excepcin son los tipos de datos definidos por el usuario que suelen comenzar con
una letra minscula. As identificadores idneos son:

Sa l ar ioMes No mbreMensajeUsuario Mens a jesDatos Mal

Algunas reglas que se pueden seguir son:

Usar nombres para nombrar objetos de datos tales como variables, constantes y
tipos. Utilizar Salario mejor que APagar o Pagar.
Utilizar verbos para nombrar procedimientos. LeerCaracter, LeerSigCar
y CalcularSigMov son procedimientos que realizan estas acciones mejor que
SigCar o SigMov (siguiente movimiento).
Utilizar formas del verbo sen> o estar para funciones lgicas. SonIgua-
les, EsCero, EsListo y EsVacio se utilizan como variables o funciones l-

glcas.

if Son Igual es (A . B)

.".~ ...... ,.r'


Los nornhI'esde los objeto
al lector ,, '
, ., >,;
.'
"


..
Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 31

1.8.4. Definir constantes con nombres


Se deben evitar constantes explcitas siempre que sea posible. Por ejemplo, no utilizar 7
para el da de la semana o 3.141592 para representar el valor de la constante n. En su
lugar, es conveniente definir constantes con nombre que permiten Pascal C ... , tal como:

Const pi = 3.141592;
Const NurnDiasSernana = 7,
Const Longitud = 45;

Este sistema tiene la ventaja de la facilidad para cambiar un valor determinado bien
por necesidad o por cualquier error tipogrfico

Const Longitud = 200;


Const pi = 3.141592654;

1.8.5. Evitar el uso de goto


Uno de los factores que ms contribuyen a disear programas bien estructurados es un
flujo de control ordenado que implica los siguientes pasos:

1. El flujo general de un programa es adelante o directo.


2. La entrada a un mdulo slo se hace al principio y se sale slo al final.
3. La condicin para la terminacin de bucles ha de ser clara y uniforme.
4. Los casos alternativos de sentencias condicionales han de ser claros y uniformes.

El uso de una sentencia got o casi siempre viola al menos una de estas condiciones.
Adems es muy dificil verificar la exactitud de un programa que contenga una sentencia
goto. Por consiguiente, en general, se debe evitar el uso de got o. Hay, sin embargo,
raras situaciones en las que se necesita un flujo de control excepcional, tales casos in-
cluyen aquellos que requieren o bien que un programa termine la ejecucin cuando ocurre
un error, o bien que un subprograma devuelve el control a su mdulo llamador. La inclu-
sin en Turbo Borland Pascal de sentencias hal t y exi t hacen innecesario en cual-
quier caso el uso de goto.

1.8.6. Uso adecuado de parmetros valor/variable


Un programa interacta se comunica de un modo controlado con el resto del programa
mediante el uso de parmetros. Los parmetros valor, que son declarados por defecto cuan-
do no se especifica la palabra reservada var, pasa los valores al subprograma, pero
ningn cambio que el programa hace a estos parmetros se refleja en los parmetros
reales de retomo a la rutina llamadora. La comunicacin entre la rutina llamadora y
el subprograma es de un solo sentido; por esta causa en el caso de mdulos aislados se
deben utilizar parmetros valor siempre que sea posible.
32 Estructura de datos

Cundo es adecuado usar parmetros variable? La situacin ms evidente es cuan-


do un procedimiento necesita devolver valores a la rutina llamadora. Sin embargo, si el
procedimiento necesita devolver slo un nico valor, puede ser ms adecuado usar una
funcin. Si una funcin no es adecuada, entonces utilizar parmetros variables.
Es conveniente utilizar un parmetro variable para comunicar un valor de retorno del
subprograma a la rutina llamadora. Sin embargo, los parmetros variable cuyos valores
permanecen inalterables hacen el programa ms dificil de leer y ms propenso a errores
si se requieren modificaciones. La situacin es anloga a utilizar una constante en lugar de
una variable cuyo valor nunca cambia. Por consiguiente, se debe alcanzar un compromiso
entre legibilidad y modificabilidad por un lado y eficiencia por otro. A menos que exista
una diferencia significativa en eficiencia, se tomar generalmente el aspecto de la legibi-
lidad y modificabilidad.
,
,
,

,
,
1.8.7. Uso adecuado de funciones
,

,,
Pascal le proporciona un sistema para realizar tareas distintas a las funciones primitivas
, incorporadas al lenguaje. El mecanismo de llamada a un procedimiento o funcin defi-
nida por el usuario se puede activar desde cualquier punto de un programa en el que se
necesite ese subprograma.
En el caso de una funcin, sta se debe utilizar siempre que se necesite obtener un
nico valor. Este uso corresponde a la nocin matemtica de funcin. Por consiguiente, es
muy extrao que una funcin realice una tarea diferente de devolver un valor y no debe
hacerlo.

,' "
" ' "
,
.
'
'

Una funcin no ,.,.,'" ... " nct.dct., SIDO devolver el valor requ.erido. Es decir, una
'"' funcinnUrttll """,'kla'r:l. ,"- -. ' j 'j' :."i';: ':, .,.;':, !: . --,--" - - , _, ::,: ~ " , :', ';,' ", ':: , : r; ::T,' ',,:~,:,::: ", ',.--- - " -
,
. .. .. - . .
- - .
- -

Qu funciones tienen potencial para producir efectos laterales?

Funciones con variables globales. Si una funcin referencia a una variable glo-
bal, presenta el peligro de un posible efecto lateral. En general, las funciones no
deben asignar valores a variables globales.
Funciones con parmetros variables. Un parmetro variable es aquel en que su
valor cambiar dentro de la funcin. Este efecto es un efecto lateral. En general,
las funciones no deben utilizar parmetros variables. Si se necesitan parmetros
variables utilizar procedimientos.
Funciones que realizan entrada/salida (E/S). Las E/S son efectos laterales. Las
funciones no deben realizar E/S.

1.8.8. Tratamiento de errores


Un programa diseado ante fallos debe comprobar errores en las entradas y en su lgica
e intentar comportarse bien cuando los encuentra. El tratamiento de errores con frecuen-
Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 33

cia necesita acciones excepcionales que constituirn un mal estilo en la ejecucin normal
de un programa. Por ejemplo, el manejo de funciones puede implicar el uso de funciones
con efectos laterales.
Un subprograma debe comprobar ciertos tipos de errores, tal como entradas no vli-
das o parmetros valor. Qu accin debe hacer un subprograma cuando se encuentra un
error? Un sistema puede, en el caso de un procedimiento, presentar un mensaje de error
y devolver un indicador o bandera lgica a la rutina llamadora para indicarle que ha
encontrado una lnea de datos no vlida; en este caso, el procedimiento deja la responsa-
bilidad de realizar la accin apropiada a la rutina llamadora. En otras ocasiones, es ms
adecuado que el propio subprograma tome las acciones pertinentes por ejemplo,-
cuando la accin requerida no depende del punto en que fue llamado el subprograma.
Si una funcin maneja errores imprimiendo un mensaje o devolviendo un indicador,
viola las reglas contra efectos laterales dadas anteriormente.
Dependiendo del contexto, las acciones apropiadas pueden ir desde ignorar los datos
errneos hasta continuar la ejecucin para terminar el programa. En el caso de un error
fatal que invoque la terminacin, una ejecucin de hal t puede ser el mtodo ms lim-
pio para abortar. Otra situacin delicada se puede presentar cuando se encuentra un error
fatal en estructuras condicionales if - then-else o repetitivas while, repeat. La
primera accin puede ser llamar a un procedimiento de diagnstico que imprima la infor-
macin necesaria para ayudarle a determinar la causa del error; pero despus de que el
procedimiento ha presentado toda esta informacin, se ha de terminar el programa. Sin
embargo, si el procedimiento de diagnstico devuelve el control al punto en el que fue
llamado, debe salir de muchas capas de estructuras de control anidadas. En este caso la
solucin ms limpia es que la ltima sentencia del procedimiento de diagnstico sea
hal t.

1.8.9. Legibilidad
Para que un programa sea fcil de seguir su ejecucin (la traza) debe tener una buena
estructura y diseo, una buena eleccin de identificadores, buen sangrado y utilizar l-
neas en blanco en lugares adecuados y una buena documentacin.
Como ya se ha comentado anteriormente se han de elegir identificadores que describan
fielmente su propsito. Distinguir entre palabras reservadas, tales como f or o procedu-
re, identificadores estndar, tal como real o integer e identificadores definidos
por el usuario. Algunas reglas que hemos seguido en el libro son:

Las palabras reservadas se escriben en minsculas negritas (en letra courier, en el


libro ).
Los identificadores, funciones estndar y procedimientos estndar en minsculas
con la primera letra en maysculas (Wr i t eLn).
Los identificadores definidos por el usuario en letras maysculas y minsculas.
Cuando un identificador consta de dos o ms palabras, cada palabra comienza con
una letra mayscula (LeerVector, ListaNumeros).
34 Estructura de datos

Otra circunstancia importante a considerar en la escritura de un programa es el san-


grado o indentacin de las diferentes lneas del mismo. Algunas reglas importantes a
seguir para conseguir un buen estilo de escritura que facilite la legibilidad son:

Los bloques deben ser sangrados suficientemente para que se vean con claridad
(3 a 5 espacios en blanco puede ser una cifra aceptable).
En una sentencia compuesta, las palabras be g i n - en d deben estar alineadas:

begin
<sentencia1>
<sen tencia 2>

<s ent encian >


end

i
Sangrado consistente. Sangrar siempre el mismo tipo de construcciones de igual
manera. Algunas propuestas pueden ser:

bucles while/repeat/for

while <condi cin > while <condic i n> do


<sen t encia > begin
<s entencia>
end
,
while <condi cin> do
begin
<senten c ias>
end

Sentencias if-then-else
if <con d i cin > if <condicin > then
then <sen tenc i a1 > <senten cia1>
elee <sen t encia2 > elee
<sentencia2>

if <condicin >
then
<sentencias>
elee
<s entencias>

if <condicin> if <cond1 >


! then begin then <acc i n 1>
<sen t encias> elee if <cond2>
end then <acc i n2 >
elee begin elee <cond2> if

<sentenc ~ as >
end
Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 35

if <condl> tben inadecuada


<accinl>
else if <cond2> tben
<accin2>
else if <cond3> tben
<accin3>

1.9. LA DOCUMENTACiN

Un programa (un paquete de software) de computadora necesita siempre de una docu-


mentacin que permita a sus usuarios aprender a utilizarlo y mantenerlo. La documentacin
es una parte importante de cualquier paquete de software y, a su vez, su desarrollo es una
pieza clave en la ingeniera de software.
Existen tres grupos de personas que necesitan conocer la documentacin del progra-
ma: programadores, operadores y usuarios. Los requisitos necesarios para cada uno de
ellos suelen ser diferentes, en funcin de las misiones de cada grupo:

programadores manual de mantenimiento del programa


operadores manual del operador
operador: persona encargada de correr (ejecutar) el programa, in-
troducir datos y extraer resultados

usuariO manual del usuario
usuario: persona o seccin de una organizacin que explota el pro-
grama, conociendo su funcin, las entradas requeridas, el proceso a
ejecutar y la salida que produce

En entornos interactivos como el caso de Turbo Borland Pascal, las misiones del

usuario y operador suelen ser las mismas. As pues, la documentacin del programa se
puede concretar a:

manual del usuario,


manual de mantenimiento.

1.9.1. Manual del usuario


La documentacin de un paquete (programa) de software suele producirse con dos pro-
psitos: uno, explicar las funciones del software y describir el modo de utilizarlas (do-
cumentacin del usuario, que est diseada para ser leda por el usuario del programa);
dos, describir el software en s para poder mantener el sistema en una etapa posterior de
su ciclo de vida (documentacin del sistema o de mantenimiento)) 7.

7 Brookshear, Glen J.: Introduccin a las ciencias de la computacin, Addison-Wesley, 1995, pg. 272.
I

36 Estructura de datos

La documentacin de usuario es un instrumento comercial importante. Una buena


documentacin de usuario har al programa ms accesible y asequible. Hoy da es una
prctica habitual que muchos creadores de programas contratan escritores tcnicos para
elaborar esta parte del proceso de produccin de un programa. Esta documentacin adopta
la forma de un manual que presenta una introduccin a las funciones ms utilizadas del
software, una seccin que explica cmo instalar el programa y una seccin de referencia
que describe los detalles de cada funcin del software. Es frecuente que el manual se
edite en forma de libro, aunque cada vez es ms frecuente incluirlo adems, o en lugar,
del libro en el propio programa y suele denominarse manual de ayuda en lnea.
La documentacin del sistema o manual de mantenimiento es por naturaleza ms
tcnica que la del usuario. Antiguamente esta documentacin consista en los programas
fuente finales y algunas explicaciones sobre la construccin de los mismos. Hoy da esto
ya no es suficiente y es necesario estructurar y ampliar esta documentacin.
La documentacin del sistema abarca todo el ciclo de vida del desarrollo del software,
incluidas las especificaciones originales del sistema y aquellas con las que se verific el
sistema, los diagramas de flujo de datos (DFD), diagramas entidad-relacin (DER), diccio-
nario de datos y diagramas o cartas de estructura que representan la estructura modular
del sistema.
El problema ms grave que se plantea es la construccin prctica real de la docu-
mentacin y su continua actualizacin. Durante el ciclo de vida del software cambian
continuamente las especificaciones, los diagramas de flujo y de E/R (Entidad/Relacin)
o el diagrama de estructura; esto hace que la documentacin inicial se quede obsoleta o
incorrecta y por esta causa la documentacin requiere una actualizacin continua de
modo que la documentacin final sea lo ms exacta posible y se ajuste a la estructura
final del programa.
El manual de usuario debe cubrir al menos los siguientes puntos:

Ordenes necesarias para cargar el programa en memoria desde el almacenamiento
secundario (disco) y arrancar su funcionamiento.
Nombres de los archivos externos a los que accede el programa.
Formato de todos los mensajes de error o informes.
Opciones en el funcionamiento del programa.
Descripcin detallada de la funcin realizada por el programa.
Descripcin detallada, preferiblemente con ejemplos, de cualquier salida produ-
cida por el programa.

1.9.2. Manual de mantenimiento (documentacin


para programadores)
El manual de mantenimiento es la documentacin requerida para mantener un programa
durante su ciclo de vida. Se divide en dos categoras:

documentacin interna,
documentacin externa.
Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 37

1.9.3. Documentacin interna


Esta documentacin cubre los aspectos del programa relativos a la sintaxis del lengua-
je. Esta documentacin est contenida en los comentarios, encerrados entre llaves { } o
bien parntesis/asteriscos (* *). Algunos tpicos a considerar son:

Cabecera de programa (nombre del programador, fecha de la versin actual, breve


descripcin del programa).
Nombres significativos para describir identificadores.
Comentarios relativos a la funcin del programa como en todo, as como los m-
dulos que comprenden el programa.
Claridad de estilo y formato [una sentencia por lnea, indentacin (sangrado)],
lneas en blanco para separar mdulos (procedimientos, funciones, unidades, etc.).
Comentarios significativos.

Ejemplos
var
Radio ... ( entrada, rad i o de un c irc u lo )
( Calc u l ar Area)
Are a : = pi * radio * rad i o ;

1.9.4. Documentacin externa

Documentacin ajena al programa fuente, que se suele incluir en un manual que acom-
paa al programa. La documentacin externa debe incluir:

Listado actual del programa fuente, mapas de memoria, referencias cruzadas, etc.
Especificacin del programa: documento que define el propsito y modo de fun-
cionamiento del programa. I
Diagrama de estructura que representa la organizacin jerrquica de los mdulos
que comprende el programa.
Explicaciones de frmulas complejas.
Especificacin de los datos a procesar: archivos externos incluyendo el formato
de las estructuras de los registros, campos, etc.
Formatos de pantallas utilizados para interactuar con los usuarios.
Cualquier indicacin especial que pueda servir a los programadores que deben
mantener el programa.

1.9.5. Documentacin del programa


Un programa bien documentado es aquel que otras personas pueden leer, usar y modificar.
Existen muchos estilos aceptables de documentacin y, con frecuencia, los temas a in-
cluir dependern del programa especfico. No obstante, sealamos a continuacin algunas
caractersticas esenciales comunes a cualquier documentacin de un programa:

L,

38 Estructura de datos

1. Un comentario de cabecera para el programa que incluye:


a) Descripcin del programa: propsito.
b) Autor y fecha.
c) Descripcin de la entrada y salida del programa.
d) Descripcin de cmo utilizar el programa.
e) Hiptesis sobre tipos de datos esperados.
j) Breve descripcin de los algoritmos globales y estructuras de datos.
g) Descripcin de las variables importantes.
2. Comentarios breves en cada mdulo similares a la cabecera del programa y que
contenga informacin adecuada de ese mdulo, incluyendo en su caso precondi-
ciones y postcondiciones. Describir las entradas y cmo las salidas se relacio-
nan con las entradas.
3. Escribir comentarios inteligentes en el cuerpo de cada mdulo que expliquen
partes importantes y confusas del programa.
4. Describir claramente y con precisin los modelos de datos fundamentales y las
estructuras de datos seleccionadas para representarlas as como las operaciones
realizadas para cada procedimiento.

Aunque existe la tendencia entre los programadores y sobre todo entre los princi-
piantes a documentar los programas como ltima etapa, esto no es buena prctica, lo
idneo es documentar el programa a medida que se desarrolla. La tarea de escribir un
programa grande se puede extender por periodos de semanas o incluso meses. Esto le ha
de llevar a la consideracin de que lo que resulta evidente ahora puede no serlo de aqu
a dos meses; por esta causa, documentar a medida que se progresa en el programa es una
regla de oro para una programacin eficaz.

Regla

Asegrese de que siempre se corresponden los comentarios y el.cdigo. Si se .hace


un cambio importante en el cdigo, asegrese de .que se realiza un cambio similar
en el comentario ..

,
1.10. OEPU RACION

Una de las primeras cosas que se descubren al escribir programas es que un programa
raramente funciona correctamente la primera vez. La ley de Murphy si algo puede ser
incorrecto, lo ser parece estar escrita pensando en la programacin de computadoras.
Aunque un programa funcione sin mensajes de error y produzca resultados, puede
ser incorrecto. Un programa es correcto slo si se producen resultados correctos para
todas las entradas vlidas posibles. El proceso de eliminar errores bugs se denomi-
na depuracin (debugging) de un programa.
Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 39

Cuando el compilador detecta un error, la computadora visualiza un mensaje de error,


que indica se ha producido un error y cul puede ser la causa posible del error. Desgra-
ciadamente, los mensajes de error son, con frecuencia, difciles de interpretar y son, a
veces, engaosos. Los errores de programacin se pueden dividir en tres clases: errores
de compilacin (sintaxis), errores en tiempo de ejecucin y errores lgicos (vase
apartado 1.12).

1.10.1. Localizacin y reparacin de errores


Aunque se sigan todas las tcnicas de diseo dadas a lo largo del libro y en este captulo,
en particular, y cualquier otra que haya obtenido por cualquier otro medio (otros libros, ex-
periencias, cursos, etc.), es prcticamente imposible e inevitable que su programa carezca
de errores. Afortunadamente los programas modulares, claros y bien documentados son
ciertamente ms fciles de depurar que aquellos que no lo son. Es recomendable utilizar
tcnicas de seguridad contra fallos, que protejan contra ciertos errores e informen de
ellos cuando se encuentran.
Con frecuencia el programador, pero sobre todo el estudiante de programacin, est
convencido de la bondad de sus lneas de programa, sin pensar en las mltiples opciones
que pueden producir los errores: el estado incorrecto de una variable lgica, la entrada
de una clusula then o else, la salida imprevista de un bucle por un mal diseo de su
contador, etc. El enfoque adecuado debe ser seguir la traza de la ejecucin del programa
utilizando las facilidades de depuracin de Turbo Borland Pascal o aadir sentencias
Wr i t e que muestren cul fue la clusula ejecutada. En el caso de condiciones lgicas,
si la condicin es falsa cuando se espera que es verdadera como el mensaje de error
puede indicar , entonces el siguiente paso es determinar cmo se ha convertido en falsa.
Cmo se puede encontrar el punto de un programa en que algo se ha convertido en
una cosa distinta a lo que se haba previsto? En Turbo Borland Pascal se puede hacer el
seguimiento de la ejecucin de un programa o bien paso a paso a travs de las sentencias
del programa o bien estableciendo puntos de ruptura (breakpoint). Se puede examinar
tambin el contenido de una variable especfica, bien estableciendo inspecciones/obser-
vaciones (watches) o bien insertando sentencias Wri te temporales (vase el Apndi-
ce). La clave para una buena depuracin es sencillamente utilizar estas herramientas que
indiquen lo que est haciendo el programa.
La idea principal es localizar sistemticamente los puntos del programa que causan
el problema. La lgica de un programa implica que ciertas condiciones sean verdaderas
en puntos diferentes del programa (recuerde que estas condiciones se llaman invarian-
tes). Un error (bug) significa que una condicin que pensaba iba a ser verdadera no lo es.
Para corregir el error, se debe encontrar la primera posicin del programa en la que una
de estas condiciones difiera de sus expectativas. La insercin apropiada de puntos de
ruptura, y de observacin o inspeccin o sentencias Wr i t e en posiciones estratgicas
de un programa tal como entradas y salidas de bucles, estructuras selectivas y subpro-
gramas sirven para aislar sistemticamente el error.
Las herramientas de diagnstico han de informarles si las cosas son correctas o equi-
vocadas antes o despus de un punto dado del programa. Por consiguiente, despus de

40 Estructura de datos

ejecutar el programa con un conjunto inicial de diagnsticos se ha de poder seguir el


error entre dos puntos. Por ejemplo, si el programa ha funcionado bien hasta la llamada
al procedimiento o funcin P 1, pero algo falla cuando se llama al procedimiento P 2,
nos permite centrar el problema entre estos dos puntos, la llamada a P2 y el punto con-
creto donde se ha producido el error en P 2. Este mtodo es muy parecido al de aproxi-
maciones sucesivas, es decir, ir acotando la causa posible de error hasta limitarla a unas
pocas sentencias.
Naturalmente, la habilidad para situar los puntos de ruptura, de observacin o sen-
tencias Wr i t e, depender del dominio que se tenga del programa y de la experiencia
del programador. No obstante, le damos a continuacin algunas reglas prcticas que le

faciliten su tarea de depuracin .

1.10.1.1. Uso de sentencias Wr i t e


Las sentencias Wr i t e pueden ser muy adecuadas en numerosas ocasiones. Tales sen-
tencias sirven para informar sobre valores de variables importantes y la posicin en el
programa en que las variables toman esos valores. Es conveniente utilizar un comentario
para etiquetar la posicin.

(Posicin una)
WriteLn ('Est situado en posicin una del procedimiento Test');
WriteLn ('A=', a, lB = " b, le = " e);

1.10.1.2. Depuracin de sentencias if-then-else


Situar una parte de ruptura antes de una sentencia i f -then-else y examinar los
valores de las expresiones lgicas y de sus variables. Se pueden utilizar o bien puntos de
ruptura o sentencias Wr i t e para determinar qu alternativa de la sentencia i f se toma:

(Examinar valores de <condicin> y variables antes de if)


if <co ndicin >
then
begin
WriteLn ('Condicin verdadera: siga camino ' ) ;

end
elae
begin
WriteLn ('Condicin falsa: siga camino');

end;

1.10.1.3. Depuracin de bucles


Situar los puntos de ruptura al principio y al final del bucle y examinar los valores de las
variables importantes:
Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 41

{Examinar valores de m y n antes de entrar al bucle}


for i :~ m to n do
begin
{Examinar los valores de i y variables importantes final bucle}
end;
{Examinar los valores de m y n despus de salir del bucle}

1.10.1.4. Depuracin de subprogramas

Las dos posiciones clave para situar los puntos de ruptura son al principio y al final
de un subprograma. Se deben examinar los valores de los parmetros en estas dos
posiciones utilizando o bien sentencias Wr i t e o ventanas de inspeccin u observacin
(watches).

1.10.1.5. Lecturas de estructuras de datos completos

Las variables cuyos valores son arrays u otras estructuras puede ser interesante exami-
narlas. Para ello se recurre a escribir rutinas especficas de volcado (presentacin en
pantalla o papel) que ejecuten la tarea. Una vez diseada la rutina se llama a ella desde
puntos diferentes segn interesa a la secuencia de flujo de control del programa y los
datos que sean necesarios en cada caso.

1.10.2. Los equipos de programacin


En la actualidad es dificil y raro que un gran proyecto de software sea implementado
(realizado) por un solo programador. Normalmente, un proyecto grande se asigna a un
equipo de programadores, que por anticipado deben coordinar toda la organizacin glo-
bal del proyecto.
Cada miembro del equipo es responsable de un conjunto de procedimientos, algu-
nos de los cuales pueden ser utilizados por otros miembros del equipo. Cada uno de
estos miembros deber proporcionar a los otros las especificaciones de cada proce-
dimiento, condiciones pretest o postest y su lista de parmetros formales; es decir, la
informacin que un potencial usuario del procedimiento necesita conocer para poder
ser llamado.
Normalmente, un miembro del equipo acta como bibliotecario, de modo que a me-
dida que un nuevo procedimiento se termina y comprueba, su versin actualizada susti-
tuye la versin actualmente existente en la biblioteca. Una de las tareas del bibliotecario
es controlar la fecha en que cada nueva versin de un procedimiento se ha incorporado a
la librera, as como asegurarse de que todos los programadores utilizan la versin lti-
ma de cualquier procedimiento.
Es misin del equipo de programadores crear bibliotecas de procedimientos, que
posteriormente puedan ser utilizadas en otras aplicaciones. Una condicin importante
deben cumplir los procedimientos estar comprobados y ahorro de tiempo/memoria.
42 Estructura de datos

1.11.
-
DISENO DE ALGORITMOS

Tras la fase de anlisis, para poder solucionar problemas sobre una computadora, debe
conocerse cmo disear algoritmos. En la prctica sera deseable disponer de un mtodo
para escribir algoritmos, pero, en la realidad, no existe ningn algoritmo que sirva para
realizar dicha escritura. El diseo de algoritmos es un proceso creativo. Sin embargo,
existen una serie de pautas o lneas a seguir que ayudarn al diseo del algoritmo (Ta-
bla 1.1).

Tabla 1.1. Pautas a seguir en el diseo de algoritmos

1. FOllnular una solucin precisa del problema que debc solucionar el algoritmo.
2. Ver si existe ya algn algoritmo para resolver el problema o bien se puede adaptar uno ya existente
(algoritmos conocidos).
3. Buscar si existen tcnicasestn~r(luesePlWdaiuwlizar, para resolver el.problema.
4. Elegir una estructura de dato~adecuada.
. . " .. ..

5. Dividir el problelll!l 1:11 s\l:bP(Clbl!<lllas Yplic.arel mtodo a ca4a uno~ los subproblemas (di$eo .
. descendente).
. . , ....
. ", '" ~
....
",;:,; ,:'
:":: ". ,. :."., ,, ...

6. Si todo lo anterior falla, comIence de nuevo , .,.


en el paso 1.
.... _--- -- ---'-,,- -
- - , , ;, 1 J.~ .' -:::.,: _,o:: __ -._? __

De cualquier forma, antes de iniciar el diseo del algoritmo es preciso asegurarse


que el programa est bien definido:

Especificaciones precisas y completas de las entradas necesarias.


Especificaciones precisas y completas de la salida.
Cmo debe reaccionar el programa ante datos incorrectos?
Se emiten mensajes de error? Se detiene el proceso?, etc.
Conocer cundo y cmo debe terminar un programa.

1.12. PRUEBAS (TESTING)


Aunque muchos programadores utilizan indistintamente los trminos prueba o comproba-
cin (testing) y depuracin, son, sin embargo, diferentes. La comprobacin (pruebas)
se refiere a las acciones que detellninan si un programa funciona correctamente. La depu-
racin es la actividad posterior de encontrar y eliminar los errores (bugs) de un programa.
Las pruebas de ejecucin de programas normalmente muestran claramente que el
programa contiene errores, aunque el proceso de depuracin puede, en ocasiones, resul-
tar dificil de seguir y comprender.
Edgar Dijkstra ha escrito que mientras las pruebas muestran efectivamente la presen-
cia de errores, nunca pueden mostrar su ausencia. Una prueba (test) con xito significa
solamente que ningn error se descubri en las circunstancias particulares probadas,
pero no dice nada sobre otras circunstancias. En teora, el nico medio de comprobar
Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 43

que un programa es correcto es probar todos los casos posibles (realizar una prueba
exhaustiva), situacin tcnicamente imposible, incluso para los programas ms simples.
Consideremos un caso sencillo: calcular la media aritmtica de las temperaturas de un
mes dado; una prueba exhaustiva requerir todas las posibles combinaciones de tempe-
raturas y das de un mes: tarea ardua, laboriosa y lenta.
No obstante, el anlisis anterior no significa que la comprobacin sea imposible;
al contrario, existen diferentes metodologas formales para las comprobaciones de pro-
gramas. Una filosofa adecuada para pruebas de programas incluye las siguientes con-
sideraciones:

1. Suponer que su programa tiene errores hasta que sus pruebas muestren lo contrario.
2. Ningn test simple de ejec4cin puede probar que un programa est libre de
error.
3. Trate de someter al programa a pruebas duras. Un programa bien diseado mani-
pula entradas con elegancia. Por este trmino se entiende que el programa no
produce errores en tiempo de ejecucin ni produce resultados incorrectos; por el
contrario, el programa, en la mayora de los casos, visualizar un mensaje de error
claro y solicita de nuevo los datos de entrada.
4. Comenzar la comprobacin antes de terminar la codificacin.
5. Cambiar slo una cosa cada vez.

Cada vez que se ejecuta un programa con algunas entradas, se prueba a ver cmo
funciona el trabajo para esa entrada particular. Cada prueba ayuda a establecer que el
programa cumpla las especificaciones dadas.

Seleccin de datos de prueba


Cada prueba debe ayudar a establecer que el programa cumple las especificaciones dadas.
Parte de la ciencia de ingeniera de software es la construccin sistemtica de un conjunto
de entradas de prueba que es idneo a descubrir errores.
Para que un conjunto de datos puedan ser considerados como buenos datos de prue-
ba, sus entradas de prueba necesitan cumplir dos propiedades.

Propiedades de buenos "datos de prueba


,
" " "

1. Se debe conocer qu 'salida debep'rOdliClr un 'pr'grarriti:correcto para cada


" entrada de prueba.
2. ' Lasertrada.sde prUeba deben incluiraqueTls entradas que probablemente ori-
" ; -"., .__ .,- _"_,, ,-- 'o _- . ' __ .. - _: - . . , ,_._ ,
ginen ms errores. " '. ... .' . .
"".
., .... , ,',. , . .
.. ... . .
, " ,:.
.:: :.. '" .. :.' '..' ,,' .. ," :'" ::;'. '; ,,'
44 Estructura de datos

Se deben buscar numerosos mtodos para encontrar datos de prueba que produzcan
probablemente errores. El primer mtodo se basa en identificar y probar entradas deno-
minadas valores externos, que son especialmente idneos para causar errores. Un valor
externo o lmite de un problema en una entrada produce un tipo diferente de comporta-
miento. Por ejemplo, suponiendo que se tiene una funcin ver_hora que tiene un
parmetro hora y una precondicin:

P~con~cin: Hora est comprendido en el rango 0-23

Los dos valores lmites de ver_hora son hora igual a O (dado que un valor menor
de O es ilegal) y hora igual a 23 (dado que un valor superior a 23-24 ... es ilegal). Puede
ocurrir que la funcin se comporte de modo diferente para horario matutino (O a 11) o
nocturno (12 a 23), entonces 11 y 12 sern valores extremos. Si se espera un comporta-
miento diferente para hora igual a O, entonces 1 es un valor extremo. En general no
existe una definicin precisa de valor extremo, pero debe ser aquel que muestre un com-
portamiento lmite en el sistema.

Valores de prueba extremos

Si no se p\le.Qenprobar to.Qas las entra.Qas pQsibles, probar al meno; los valores


extremos. Por ejemplo, .si el rango .Qeentradas legales va de cero a un milln,
asegrese probar la entrada()y la entrada 1.000.000. Es buena idea considerar
tambin 0,.1 Y -1 cQmo yalore.;limitessiempre que sean entrada; legales.

Otra tcnica de prueba de datos es la denominada perfilador que bsicamente consi-


dera dos reglas:

l. Asegrese de que cada lnea de su cdigo se ejecuta al menos una vez para algu-
nos de sus datos de prueba. Por ejemplo, puede ser una porcin de su cdigo que
maneje alguna situacin rara.
2. Si existe alguna parte de su cdigo que a veces se salte totalmente, asegrese, en
ese caso, que existe al menos una entrada de prueba que salte realmente esta
parte de su cdigo. Por ejemplo, un bucle en el que el cuerpo se ejecute, a veces,
cero veces. Asegrese de que hay una entrada de prueba que produce que el
cuerpo del bucle se ejecute cero veces.

1.12.1. Errores de sintaxis (de compilacin)


Un error de sintaxis o en tiempo de compilacin se produce cuando existen errores en la
sintaxis del programa, tales como signos de puntuacin incorrectos, palabras mal escri-
tas, ausencia de separadores (signos de puntuacin), o de palabras reservadas (ausencia
Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 45

de un end). Si una sentencia tiene un error de sintaxis, no puede ser traducida y su pro-

. ,
,
grama no se ejecutara.
Cuando se detecta un error, Turbo Borland Pascal carga automticamente el archivo
fuente, sita el cursor en el error y visualiza un mensaje de error.

44 Field identifier expected

NOllnalmente, los mensajes de error son fciles de encontrar. El siguiente ejemplo pre-
senta dos errores de sintaxis: el punto y coma que falta al final de la primera lnea y la
palabra WritaLn mal escrita, debera ser WriteLn.

Suma := O

for 1 := O to 10 do

Suma := Suma + A[I];

~. WritaLn (Suma/lO);

I
1.12.2. Errores en tiempo de ejecucin

Los errores en tiempo de ejecucin o simplemente de ejecucin (runtime error)

suceden cuando el programa trata de hacer algo imposible o ilgico. Los errores de eje-

", cucin slo se detectan en la ejecucin. Errores tpicos son: la divisin por cero, intentar

utilizar un subndice fuera de los lmites definidos en un array, etc.

X := l/N produce un error si N - O

Los mensajes de error tpicos son del tipo:

Run - Time error nnn at xxxx:yyyy

nnn nmero de error en ejecucin


xxxx:yyyy direccin del error en ejecucin (segmento y desplazamiento)

Los errores de ejecucin se dividen en cuatro categoras:

errores DOS, 1-99 (nmeros de mensaje)


errores //0, 100-149
errores crticos, 150-199
errores fatales, 200-255

1.12.3. Errores lgicos


Los errores lgicos son errores del algoritmo o de la lgica del programa. Son dificiles de
encontrar porque el compilador no produce ningn mensaje de error. Se producen cuan-
do el programa es perfectamente vlido y produce una respuesta .


46 Estructura de datos

Calcular la media de todos los nmeros ledos del teclado


Suma := o;
for i := O to 10 do
begin
ReadLn (Num);
Suma := Suma + Num
end;
Media := Suma / 10;

La media est calculada mal ya que existen once nmeros (O a 10) y no diez como se ha
escrito.
Si se desea escribir la sentencia:

Salario := Horas * Tasa;

y se escribe:

Salario := Horas + Tasa;

Es un error lgico (+ por *) ya que a priori el programa funciona bien, y sera dificil,
por otra parte, a no ser que el resultado fuese obvio, detectar el error.

1.12.4. El depurador
Turbo Borland Pascal tiene un programa depurador disponible para ayudarle a depurar
un programa; el programa depurador le permite ejecutar su programa, una sentencia cada
vez, de modo que se pueda ver el efecto de la misma. El depurador imprime un diagns-
tico cuando ocurre un error de ejecucin, indica la sentencia que produce el error y
permite visualizar los valores de variables seleccionadas en el momento del error. Asi-
mismo, se puede seguir la pista de los valores de variables seleccionadas durante la eje-
cucin del programa (traza), de modo que se pueda observar cmo cambian estas varia-
bles mientras el programa se ejecuta. Por ltimo se puede pedir al depurador que detenga
la ejecucin en determinados puntos (breakpoints); en esos momentos se pueden inspec-
cionar los valores de las variables seleccionadas a fin de determinar si son correctas.
El depurador tiene la gran ventaja de posibilitar la observacin de los diferentes va-
lores que van tomando las variables dentro del programa.

1.13. EFICIENCIA
La eficiencia de un programa es una medida de cantidad de recursos consumidos por el
programa. Tradicionalmente, los recursos considerados han sido el tiempo de ejecucin
y/o el almacenamiento (ocupacin del programa en memoria). Mientras menos tiempo
se utilice y menor almacenamiento, el programa ser ms eficiente.
El tiempo y almacenamiento (memoria) de la computadora suelen ser costosos y por
ello su ahorro siempre ser importante. En algunos casos la eficiencia es crticamente
Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 47

importante: control de una unidad de vigilancia intensiva de un hospital un retardo de


fracciones de segundo puede ser vital en la vida de un enfermo , un programa de control
de roturas en una prensa hidrulica la no deteccin a tiempo podra producir grandes
inundaciones , etc. Por el contrario, existirn otros casos en los que el tiempo no ser
, factor importante: control de reservas de pasajeros en una agencia de viajes.
,
La mejora del tiempo de ejecucin y el ahorro en memoria se suelen conseguir con la
mejora de los algoritmos y sus programas respectivos. En ocasiones, un simple cambio
en un programa puede aumentar la velocidad de ejecucin considerablemente. Como
muestra de ello analicemos el problema siguiente desde el punto de vista de tiempo de
. .,
eJecuclOn

Buscar en un array o lista de enteros una clave dada (un entero)


ArrayL i sta : Lista[Primero .. Ultimo] of integer
ALGORITMO Buscar el em ento t
J Pr i me ro;
:=
while (T <> Lista [J] and (J < Ulti mo) do
J : = J + 1;
if T = Lista [J] then
Wri t e Ln ('el el ement o ', T, 'est en la li s t a ' )
elee
Writ eLn ('el element o ', T, 'no est en la lista')

El bucle va comprobando cada elemento de la lista hasta que encuentra el valor de T


o bien se alcanza el final de la lista sin encontrar T.
Supongamos ahora que la lista de enteros est ordenada.

45 73 81 1 20 1 60 321 450

En este caso el bucle puede ser ms eficiente si en lugar de la condicin

(T <> Lista[J]) and (J < Ultimo)

se utiliza

(T > Lista[J]) and (J < Ul tim o)

Ello se debe a que si T es igual a Lis t a [J 1 , se ha encontrado el elemento, y si T es


menor que Lis t a [J 1 , entonces sabemos que T ser ms pequeo que todos los elementos
que le siguen. Tan pronto como se pruebe un valor de T y resulte menor que su correspon-
diente Lis t a [J 1 , esta condicin ser falsa y el bucle se terminar. De este modo, y
como trmino medio, se puede ahorrar alrededor de la mitad del nmero de iteraciones.
En el caso de que T no existe en la lista, el nmero de iteraciones de ambos algoritmos
es igual, mientras que si T no existe en la lista, el algoritmo 2 con (T > Lis t a [J 1 )
reducir el nmero de iteraciones en la mitad y por consiguiente ser ms eficiente.
Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 49

Ejecucin
Intro d uzca 10 en t ero s en or de n asce nd ente :
2 5 8 12 23 37 45 89 1 12 234
I n tr o du c ir n m e r o a b uscar :
27
el e l e mento 27 n o es t en l a l ista
Bus q ueda1 te rm i n ada e n
10 i t e r ac i o n es
el ele mento 2 7 n o es t en l a lista
Bus qued a2 t ermi nada en
6 i t era cione s

1.13.1. Eficiencia versus leg ibilidad (claridad)


Las grandes velocidades de los microprocesadores (unidades centrales de proceso)
actuales, junto con el aumento considerable de las memorias centrales (cifras tpicas
usuales superan siempre los 32/64 MB), hacen que los recursos tpicos tiempo y almace-
namiento no sean hoy da parmetros fundamentales para la medida de la eficiencia de
un programa.
Por otra parte es preciso tener en cuenta que a veces los cambios para mejorar
un programa puede hacerlo ms dificil de comprender: poco legibles o claros. En pro-
gramas grandes la legibilidad suele ser ms importante que el ahorro en tiempo y en
almacenamiento en memoria. Como norma general, cuando la eleccin en un programa
se debe hacer entre claridad y eficiencia, generalmente se elegir la claridad o la legibi-
lidad del programa.

1.14. TRANSPORTABILIDAD (PORTABILIDAD)


Un programa es transportable o portable si se puede trasladar a otra computadora sin
cambios o con pocos cambios apreciables. La forma de hacer un programa transportable
es elegir como lenguaje de programacin la versin estndar del mismo, en el caso de
Pascal: ANSI/IEEE estndar e ISO estndar.
Turbo Borland Pascal no sigue todas las normas del estndar y adems rene un
conjunto de caractersticas no disponibles en Pascal estndar. Esto significa que si desea
transportar sus programas a Pascal estndar, deber evitar en los mismos todas las carac-
tersticas propias de Turbo.

RESUMEN
La ingeniera de software trata sobre la creacin y produccin de programas a gran escala. El ,
ciclo de vida del software consta de las fases:
Anlisis de requisitos y especificacin.

Diseo.
1
Implementacin (codificacin y depuracin).

If... ,
50 Estructura de datos

Prueba.
Evolucin.
Mantenimiento.
Si se desea crear buenos programas en Turbo Borland Pascal, los conceptos de unidades y progra-
macin modular sern vitales en el desarrollo de los mismos.

EJERCICIOS


1.1. Cul es el invariante del bucle siguiente?

! I nd i ce := 1 ;
Suma : = A [ 1 ] ;
while Ind ic e < N hacer
begin
Indice : = Succ ( In d i ce) ;
Sum a := Suma + A [ Indice ]
end;

1.2. Considere el programa siguiente que interactivamente lee y escribe el nmero de identifica-
cin, nombre, edad y salario (en millares de pesetas) de un grupo de empleados. Cmo se
puede mejorar el programa?
program Test ;
var xl, x 2, x3 , i : integ er ;
Nombre: array [ l .. 10 ] of ch ar;
begin
while not eo f do
begin
Re ad ( xl ) ;
for i : = 1 to 8 do
Read ( Nombre [ i] ) ;
Rea d Ln ( x 2 , x 3 ) ;
Wr it e Ln ( x 1 , Nombr e ,x 2 , x 3 )
end
end;

1.3. Cul es el error de la siguiente funcin? Cmo puede resolverse?


function Tang ent e ( x : r eal) :rea l ;
begin
Ta ng e n te : = si n (x) / cos(x)
end;

1.4. Escribir una [uncin que devuelve el total de dgitos (n) distintos de cero en un nmero
entero arbitrario (Nmero). La solucin debe incluir un bucle while con el siguiente inva-
riante de bucle vlido.
I {invarian t e :
O <= Tota l <= n y N me r o se h a div i d i d o po r 10 veces To ta l }

y sta ser la asercin vlida (postcondicin)

{po stcondicin : Total e s n }

,
.. -

Ingeniera de software: introduccin a la metodologa de construccin de grandes programas 51


1.5. Escribir un invariante de bucle para el siguiente segmento de cdigo

Produc t o : = 1 ;
Con ta d o r := 2 ;
while Cont ador < 10 do
begin
Producto : = Producto * Co ntador;
Co ntador : = Contador + 1
end;

PROBLEMAS
1.1. Escribir un programa que lea una lista de 100 o menos enteros y a continuacin realice las
siguientes tareas: visualizar la lista ordenada desde el mayor hasta el menor; visualizar lista
en orden inverso, calcular la media; calcular la mediana; listar las listas en orden creciente y
en orden decreciente, mostrando la diferencia de cada valor con la media y la mediana. Es
conveniente que cada tarea se realice con un mdulo y luego se integren todos en un pro-
grama.
1.2. A la entrada de un aparcamiento, un automovilista retira un ticket en el cual est indicado
su hora de llegada. Antes de abandonar el aparcamiento se introduce el ticket en una m-
quina que le indica la suma a pagar. El pago se realiza en una mquina automtica que
devuelve cambio.
Escribir un programa que simule el trabajo de la mquina. Se supone que:

La duracin del estacionamiento es siempre inferior a 24 horas.


La mquina no acepta ms que monedas de 200, 100, 50, 25, 5, 2 y l peseta.
Las tarifas de estacionamiento estn definidas por tramos semihorarios (1/2 hora).

1.3. Escribir un programa que contenga una serie de opciones para manipular un par de matri-
ces (suma, resta y multiplicacin). Cada procedimiento debe validar sus parmetros de en-
trada antes de ejecutar la manipulacin requerida de datos.
1.4. Un viajante de comercio debe visitar N ciudades. Parte de una de ellas y debe volver a su
- punto de partida. Conoce la distancia entre cada una de las ciudades y desea hacer un viaje

lo ms corto posible. El sistema elegido de viaje es el siguiente:

A partir de cada ciudad, elige como ciudad siguiente la ms prxima entre las ciudades
que no ha visitado.

Se suponen datos: la lista de ciudades, las distancias (en kilmetros) entre cada una de ellas
y el nombre de la ciudad de partida. Elegir un algoritmo que calcule el recorrido ms corto.
1.5. Se tiene la lista de una clase que contiene un nombre de estudiante y las notas de cinco

'. exmenes. Se desea escribir un programa que visualice la media de cada alumno, la nota
media ms alta y la nota media ms baja, junto con los nombres correspondientes.
1.6. Se desea disear un programa que permita adiestrar a un nio en clculos mentales. Para
ello el nio debe elegir entre las cuatro operaciones aritmticas bsicas; la computadora le
presentar la operacin correspondiente entre dos nmeros, y el nio debe introducir desde
el teclado el resultado. El nio dispone de tres tentativas. Caso de acertar, la computadora
debe visualizar Enhorabuena, y en caso de fallo Lo siento, intntalo otra vez.


52 Estructura de datos

1.7. Escribir un programa que construya un directorio telefnico interactivo que contiene una
coleccin de nombres y nmeros de telfonos. Las caractersticas del directorio han de
ser: 1) poder insertar una nueva entrada en el directorio; 2) recuperar una entrada del direc-
torio; 3) cambiar una entrada del directorio, y 4) borrar una entrada del directorio. Nota: El
directorio debe estar ordenado alfabticamente.

,
,

,
I
,
CAPITULO

.,
-,onstrucclon ran es ro ramas:
, .
mo u os versus unl a es
, , - - -- "- - ,- ~" -
--
-
-,
.

CONTENIDO

2.1. Concepto de unidad.


2.2. Estructura de una unidad.
2.3. Creacin de unidades.
2.4. Utilizacin de unidad estndar.
2.5. Situacin de las unidades en sus discos. Dnde busca Turbo Borland Pascal las uni-
dades?
2.6. Identificadores idnticos en diferentes unidades.
2.7. Sntesis de unidades.
2.8. Otros mtodos de estructurar programas: inclusin, solapamiento y encadenamiento.
RESUMEN.
EJERCICIOS.
REFERENCIAS BIBLIOGRFICAS.

,
;

,,}
Una de las caractersticas ms interesantes de Turbo Borland Pascal 5/
6/7 es la posibilidad de descomponer un programa grande en produc-
tos ms pequeos que se pueden compilar independientemente. Estos
mdulos se denominan unidades y eliminan el inconveniente de las
versiones anteriores a 4.0 de la limitacin de la memoria ocupada por 1
programas ejecutables a 64 K. Los lectores que hayan utilizado Modu-
la-2 encontrarn familiar el concepto unidad, ya que unidad (en Turbo
Borland Pascal) y mdulo (en Modula-2) representan el concepto de
compilacin separada y la posibilidad de construir grandes programas I
enlazando unidades compiladas separadamente para construir un pro-
grama ejecutable. Como resultado de ello, cuando se realiza un cam-
bio en el cdigo fuente, slo se tiene que compilar el segmento al que
afecta la modificacin.

53
r

54 Estructura de datos

2.1. CONCEPTO DE UNIDAD


Una unidad es un conjunto de constantes, tipos de datos variables, procedimientos y
,
funciones. Cada unidad es como un programa independiente Pascal o bien una bibliote-

ca de declaraciones que se pueden poner en un programa y que permiten que ste se


pueda dividir y compilar independientemente. Una unidad puede utilizar otras unidades
y contiene una parte que puede contener instrucciones de iniciacin.
Una unidad contiene uno o ms procedimientos, funciones constantes definidas (y a
veces otros elementos). Se puede compilar, probar y depurar una unidad independien-
temente de un programa principal. Una vez que una unidad ha sido compilada y depurada,
no necesita compilarse ms veces, Turbo Borland Pascal se encarga de enlazar la unidad
al programa que utiliza esa unidad, empleando siempre en esta tarea menor tiempo que
en la propia compilacin. Los procedimientos, funciones y constantes que se definen en
una unidad pueden ser utilizados por cualquier futuro programa que escriba sin tener
que ser declarados en el programa.
Las unidades tienen una estructura similar a los programas y en consecuencia requieren
un formato estricto, y es preciso declararlas por el usuario como si se tratara de un pro-
grama o subprograma.
Turbo Borland Pascal proporciona siete unidades estndar para el uso del programador:
System, Graph, DOS, ert, Printer, Turbo3 y Graph3. Las cinco primeras sirven para
escribir sus programas, y las dos ltimas para mantener compatibilidad con programas y
archivos de datos creados con la versin 3.0 de Turbo Borland Pascal. Las siete unidades
estn almacenadas en el archivo TURBO.TPL (biblioteca de programas residente propia
del programa Turbo Borland Pascal). La versin 7.0 introdujo dos nuevas unidades: WinDos
y Strings.

2.2. ESTRUCTURA DE UNA UNIDAD


Una unidad est constituida de cuatro partes: cabecera de la unidad, seccin de interface
1
(interfaz), seccin implementation (implementacin) y seccin initialization (iniciali-
zacin) 1.

Formato J

unit <identi ficado r>; ,


1
interface
1
uses <lista de unidades > ; {opciona l}
,
{decl ara cio ne s pblicas Obje t os exporta dos } ,
implementation
{declarac i o n es privadas}
ii
{defin i cin de proced i mientos y fu n c i ones pbl i cas} I1
begin
{cdigo de inicializ ac i n } {opcional} ,,
i,
end. ,
,

i
Aceptamos el tllnino inicializacin por su extensa difusin en la jerga infollntica, aun a sabiendas
I 1
que dicho trmino no es aceptado por el DRAE y su expresin correcta sera iniciacin. 1
1

<1,
j
;

,
1

Construccin de grandes programas: mdulos versus unidades 55

2.2.1. Cabecera de la unidad


La cabecera de la unidad comienza con la palabra reservada uni t, seguida por el nom-
bre de la unidad (identificador vlido)2. Es similar a una cabecera de programa, donde la
palabra reservada unit reemplaza a la palabra reservada programo Por ejemplo, para crear
una unidad denominada MiUnidad se ha de utilizar la cabecera de la unidad: unit
MiUnidad.
El nombre de la unidad es arbitrario pero debe coincidir con el nombre del archivo
que contiene. Por ejemplo, si la unidad se denomina Test.
Un it Test;

el archivo que contiene el programa fuente de la unidad se debe llamar Te s t . PAS.


Cuando Turbo Borland Pascal compila la unidad, le asigna la extensin TPU (Turbo
Borland Pascal Uni t). Si el nombre de la unidad es diferente del nombre del ar-
chivo, el programa principal no podr encontrar el archivo TPU.
Una unidad puede utilizar otras unidades siempre que se incluyan en la clusula uses
que aparece inmediatamente despus de la palabra interface, y separadas por comas.

2.2.2. Seccin de interfaz


La seccin de interface (interfaz) es la parte de la unidad que sirve para conectar dicha
unidad con otras unidades y programas. Esta seccin se conoce como la parte pblica
de la unidad, ya que todos los objetos que figuren en esta seccin son visibles desde el
exterior o exportables. Las restantes unidades y programas tienen acceso a la informa-
cin contenida en la seccin de interface.
En la interfaz de la unidad se pueden declarar constantes, tipos de datos, variables
y procedimientos. Los procedimientos y funciones visibles a cualquier programa que uti-
lice la unidad se declaran aqu, pero sus cuerpos reales implementaciones se en-
cuentran en la seccin de implementacin. La seccin de interfaz indica a un progra-
mador cules procedimientos y funciones se pueden utilizar en un programa. La seccin

de implementacin indica al compilador cmo implementarlos .


Los identificadores declarados en la seccin de interfaz pueden ser referenciados por
un cliente de la unidad, de modo que se consideran visibles.

Ejemplo de declaracin
unit Ray o ;
interface
uses DOS , Graph, Crt ; (se utilizan las un i dade s DO S, Gr aph y Crt )
var

a , b, e : int ege r
function Ex po n encia l (a, b : i n t eger) : rea l;
procedure Di v id ir (x, y : integ er ;var cocien t e : i nt eg er) ;


2 El identificador puede tener de uno a ocho caracteres ms un punto y una extensin tal como .PAS .

, 56 Estructura de datos

En la seccin de interface se pueden declarar variables y elementos globales y otras


unidades.

Observaciones
l. La unidad Ray o puede utilizar cualquier procedimiento o funcin presente en
las unidades estndar Dos, Gr aph o Cr t .
2. Se declaran tres variables globales; a, b, e (estn disponibles a otras unidades y
programas que utilicen la unidad Rayo ). Se debe extremar el cuidado a la hora
de declarar variables globales en la seccin de interfaz de la unidad.

2.2.3. Seccin de implementacin


La tercera parte de una unidad, denominada implementation (implementacin) , es
estrictamente privada; su contenido no es exportable. Slo los procedimientos o fun-
ciones que aparecen en la seccin interface pueden ser invocados desde el exterior
de la unidad.
Esta seccin contiene el cuerpo de los procedimientos y funciones declarados en la
seccin de interface.

unit Rayo ;

interface
function Expo n encia l (A, B : i n t eger ) : rea l;
procedure Di v i dir (X , Y : in t eger ; var Cocien t e : in t eger) ;

implementation
function Expon e n c i al (A, B : i nt eg er) : real ;
var
P, I : integer;
begin
P := 1;
for 1 := 1 to B do
P := P * A ;
Expone nc ial .' - P

end;

procedure Di vid i r (X , Y : integer ; var Coc i e n te : i n t e ger);


begin
Coc ie nte : = X d iv y
end;
o o o
endo

Ntese que la declaracin de una unidad est terminada por la palabra reservada
end y un punto.
Las variables globales pueden ser declaradas dentro de una seccin de implementacin,
pero estas variables sern globales a la unidad solamente y no accesibles a cualquier otra
unidad o programa.

I
Construccin de grandes programas: mdulos versus unidades 57

2.2.4. Seccin de iniciacin (inicializacin)


La cuarta parte de una unidad, llamada iniciacin, puede contener instrucciones
pero puede igualmente estar vaca. Estas instrucciones sirven, por ejemplo, para iniciali-
zar variables o abrir archivos. La ejecucin de estas instrucciones se efecta en el mo-
mento del lanzamiento o ejecucin de un programa que utiliza la unidad antes de la
ejecucin de la primera instruccin del cuerpo del programa.
En la seccin de iniciacin se inicializa cualquier estructura de datos (variables) que
utilice la unidad y las hace disponibles (a travs del interface) al programa que las utili-
za. Comienza con la palabra reservada beg in seguida por una secuencia de sentencias
y termina con end. (Al igual que en los programas ordinarios se requiere un punto a
continuacin de end).
Cuando un programa que utiliza esta unidad se ejecuta, la seccin de iniciacin se
llama antes que el cuerpo del programa se ejecute.

2.2.5. Ventajas de las unidades


La nocin de unidad acenta el carcter estructurado y modular de Turbo Borland Pascal
para el diseo de grandes programas. Las unidades que representan mdulos indepen-
dientes pueden ser compiladas aisladamente, con independencia de un programa. Estas
propiedades facilitan la creacin de libreras, estndar o personalizadas (por el usuario).
Turbo Borland Pascal dispone de varias unidades estndar predefinidas conectadas
a tareas especficas: grficos, gestin de pantalla, etc. Cualquier usuario puede, a su vez,

crear sus propias unidades, enriqueciendo as los recursos bsicos. En general una unidad
,,
, puede llamar a otras unidades.
!
,
,
2.3. CREACION DE UNIDADES

Una unidad tiene una estructura muy similar a la de un programa.


La clusula uses de la parte de interface slo es necesaria en el caso de que la
unidad actual llame a otras unidades. Todos los procedimientos y funciones en la sec-
cin de interfaz deben ser definidos en la seccin de implementacin.
El contenido de la parte de iniciacin es optativo; si figuran en ellas instrucciones, se
ejecutarn inmediatamente antes del principio de la ejecucin del programa que utiliza
esta unidad.
La cabecera de los procedimientos y funciones declaradas en la parte de interface
deben ser idnticos a la cabecera de las mismas funciones definidas en la parte de imple-
mentacin; sin embargo, es posible escribir la cabecera en forma abreviada en la seccin
de implementacin.
Una vez que se dispone el cdigo fuente de una unidad, se compila de igual forma
que un programa, pero el archivo obtenido no es ejecutable directamente. Se trata de un
archivo objeto con la extensin TPU (Turbo Borland Pascal Unit). As, por ejemplo, si la
unidad se graba con el nombre Demo . Pas, se guardar con el nombre Demo. TPU.
58 Estructura de datos

unit utilidad nombre de unidad


ha de corresponder Cabecera de la unidad
con nombre de archivo

interface
uses ert; ~ opcional Seccin de interfaz
procedure Frase(Texto : string);

implementation
uses Printer; ~ opcional

var
MiVar : Integer
procedure Frase;
begin Seccin de implementacin
ClrScr;
GotoXY ((80-Length (Texto)) div 2,1)
Write (texto);
end;

begin
Mi Var := o Seccin de iniciacin
end.

Figura 2.1. Estructura de una unidad.

Para utilizar una unidad en su programa, debe incluir una sentencia uses para indi-
car al compilador que est utilizando esa unidad.
program Prueba;
uses demo;

Turbo Borland Pascal espera que el nombre del archivo fuente tenga el mismo nom-
bre de la unidad. Por ejemplo, la unidad demo se encuentra en el archivo demo . tpu.
Si el nombre de la unidad fuera demostra. TPU, Turbo Borland Pascal tratar de en-
contrar un archivo demostra. TPU para evitar estas contrariedades se puede utilizar
una directiva del compilador ($ U) , que permite especificar el nombre del archivo en
que se encuentra la unidad. As, por ejemplo, si la unidad utilidad se encuentra en el
archivo VARIOS. PAS un programa puede llamar de la forma siguiente:
program Test;
uses
Crt, {SU VARIOS.PAS} utilidad;

Construccin de grandes programas: mdulos versus unidades 59

La directiva debe preceder inmediatamente al identificador de la unidad.


Cuando el compilador encuentra la clusula uses nombre-unidad, busca la unidad
nombre-unidad sucesivamente en:

Biblioteca de base TURBO. T PL .


El archivo n ombre-u ni dad . TPU en el directorio actual, despus en el direc-
torio reservado a las unidades y especifica en el men Op tion s del entorno
de trabajo.

Pasos de compilacin de una unidad


l. Edicin de la unidad.
2. Seleccionar la orden Co mpile / Comp il e (o pulse ALT-C) .

Una vez sin errores, conviene activar la opcin Comp i le a d i sk y volver a compilar.
Turbo Borland Pascal crea un archivo con extensin T PU. Este archivo se puede
dejar o mezclarlo con TURBO . TP L.

EJEMPLO 2.1
Escribir una unidad que conste a su vez de un procedimiento para intercambiar los
valores de dos variables, as como calcular su valor mximo.

unit Demol;
interface
procedure I nter cambio (var I , J : int eg er) ;
function Ma x imo (I , J : i ntege r) : i nt eger ;
implementation
procedure I n terca mbio;
var
Aux : integer ;
begin
Aux - I ,
-
1 - J ;
J - Aux
-
end;
function Maximo;
begin
i f I>J
then Ma x imo -- I
else Maximo -- J
end;
end.

Tras editar el programa, gurdelo en disco con el nombre Demo 1 . PAS , a continua-
cin compilar en disco. El cdigo objeto resultante ser Demo l . TPU. Un programa que
utiliza la unidad Demo 1 es:

60 Estructura de datos

program Prueba;
uses
Demo 1 ;
var
X, y : integer ;
begin
,
Write ('Introdu c i r dos num e r as enter os ' ) ;
ReadLn (X, Y);
In terca mbio (X , y); Wr it eLn (X , " , Y) ;
WriteLn ('e l valor mxi mo es ', Maxi mo( X, Y)) ;
end.

, El programa Prueba utiliza la unidad Demo 1 y, en consecuencia, puede disponer


del procedimiento In t ercambi o y la funcin Maximo.

EJEMPLO 2.2
Construccin de una unidad con un procedimiento Intercambio y una funcin Potencia
o Exponenciacin (xn; x: real, n: entero).

unit Ca l cu lo;

interface {sec cin de int erfaz}


procedure Inte rcamb io (var X, Y : integer) ;
{intercambia los va l o re s de X e Y}
function Potenc i a (X : real ; n : i nt eger) : real;
{d ev u e l ve X a l a potencia n -e si ma }

implementation {sec ci n de imp le me nt a cin}


procedure Inter ca mbio (var X, Y : in teger) ;
var
Aux : In teger;
begin
Aux := X;
X := Y;
Y := Aux
end; ( Intercambio )

function Pote ncia (X : real; n : i n te ger) : rea l ;


var
I : integer;
Pr od ucto: real;
begin (Po ten c i a)
Producto : = 1;
for I := 1 to n do
Producto : = Produ
, cto * X;
Potencia : = Pr oduc to
end; {Potencia}
end. {Clcul o}

El procedimiento Intercambio y la funcin Potencia de la seccin de imple-


mentacin pueden ser definidos de un modo abreviado.
Construccin de grandes programas: mdulos versus unidades 61

procedure I n te rcambio ;
function Po t~nc ia ;

Sin embargo, el mtodo abreviado para declarar no es un estilo muy recomendado.

Reglas de compilacin

Una unidad se compila tal como se compila un programa completo. La compilacin


se realiza en memoria. Sin embargo, antes que la unidad pueda ser utilizada por un , .
programa o por otra unidad, debe ser compilado en disco. Normalmente el archivo
que contiene una unidad debe tener el mismo nombre que la unidad.

2.3.1. Construccin de grandes programas


La caracterstica de compilacin independiente de las unidades facilita considerable-
mente la programacin modular. Un programa grande se divide en unidades que agrupan
procedimientos y funciones afines. As, un programa puede ser dividido en diferentes
mdulos o unidades: A, B, e y D, Y la estructura del programa podra ser sta:
program Prueba;
uses
Do s , Cr t , Pr in t er ,
A, B, e, D;
{declaraci o nes de procedimientos y funcione s de l progr ama}
begin {programa principa l}
end.

La compilacin independiente de las unidades permite tambin superar el tamao del


cdigo fuente de un programa de 64 K que viene limitado por el tamao de un segmento
del microprocesador 8086 (64 K); esta caracterstica significa que el programa principal
y cualquier segmento dado no pueden exceder un tamao de 64 K.
Turbo Borland Pascal manipula las unidades de forma que el lmite superior de alma-
cenamiento ocupado por un programa puede llegar al lmite mximo de memoria que puede
soportar la mquina y el sistema operativo: 640 K en la mayora de los Pe. Sin la
posibilidad de construccin de unidades , de Turbo Borland Pascal 4.0 y 5.0, los progra-
mas estn limitados a 64 K.

Turbo 80rtand diferencia unidades de programas por las palabras reservadas con
las que comienzan y acta de acuerdo con ellas.

2.3.2. Uso de unidades


Las unidades creadas por el usuario se almacenan con la extensin T PU, mientras que las
,

unidades estndar se almacenan en un archivo especial (TURBO . TPL) Y se cargan autom-


ticamente en memoria junto con el propio Turbo Borland Pascal.

62 Estructura de datos

El uso de una unidad o diferentes unidades aade muy poco tiempo (normalmente
menos de un segundo) al tiempo de compilacin de su programa. Si las unidades estn
cargadas en un archivo de disco independiente, se pueden necesitar unos segundos para
leerlas del disco.
Un programa puede utilizar ms de una unidad. En este caso todas las unidades se
listan en la sentencia uses, separadas por comas, como en el siguiente ejemplo:

program Prueba;
uses Ob j etos , Unidad2;

Slo las unidades realmente utilizadas en el programa necesitan ser listadas. Si Un i -


dad2 utiliza una unidad llamada ObViej os, pero el programa no incluye una llamada
a algo definido en ObV iej os, no es necesario listar ObV iej os en la sentencia uses .
Las unidades pueden ser listadas en cualquier orden. Aunque no exigible, una buena
regla a seguir es listar cada unidad antes de todas aquellas que la utilicen. As, por
ejemplo, si Unidad2 utiliza Obj etos, es buena prctica listar Obj etos antes que
Unidad2.
Si una unidad utiliza otra unidad, debe contener una clusula u s e s. Por ejemplo,
continuemos suponiendo que Unidad 2 utiliza las dos unidades Obj etos y ObViej os,
entonces Un i dad2 debe incluir una clusula u s e s que indique al compilador su uso.
La clusula uses (si se necesita) se incluye normalmente en la seccin de int er f ace.

unit Unida d2 ;
interface
uses ObViejos, Obje t os ;

2.3.3. Declaraciones/informacin pblica y privada


La seccin de interface no est limitada a contener slo procedimientos y cabeceras.
Puede contener declaraciones de tipos, constantes u otras clases.
Todos los objetos declarados en la seccin de interface es informacin pblica y
puede ser referenciada en cualquier programa (o unidad) que utilice la unidad. La infor-
macin que se desea ocultar del programa principal debe ser situada en la seccin de
implementacin.
Adems de los procedimientos y funciones cuyas cabeceras aparecen en la seccin
de interface de una unidad, sta puede tener tambin otros procedimientos, funciones,
constantes y/o otras declaraciones. Estas declaraciones se llaman, con frecuencia, decla-
raciones privadas. Son locales a la unidad y no se pueden ver referenciadas por cual-
quier programa (u otra unidad) que utilice la unidad. Por ejemplo, si un programa utiliza
la unidad Financa, puede utilizar el procedimiento Uno, el procedimiento Dos y la
constante Tasa. Sin embargo, no puede referenciar la constante Banda o la funcin
Conversin que aparece en la seccin de implementacin. Banda y Conversin
son locales a la unidad Finan c a. Pueden ser utilizadas en la unidad Financa, pero
no tienen significado fuera de esa unidad .


Construccin de grandes programas: mdulos versus unidades 63

unit Fi n anc a;
{dec la r a pro cedim ien to pa ra co n ve rt ir ca pit ales}

interface
const
Ta sa = 4. 25 ;
procedure Un o (Cap it al : r ea l) ;
procedure Dos(Cap it al : rea l ) ;
implementation
const
Banda = '*';

function Convers i o n (Cap i ta 1 : rea 1 ) : r ea 1 ;


var
Fa ctorCo nv ers i o n : in te ger;
Ca n tida dP agar : real ;
begin
FactorCo n vers i o n : = 65;
Ca n tida dP agar : = Capi t al * F ac torCon ve rs i on ;
Con vers ion : = Can tid adPag ar
end;

procedure Uno (Cap i ta l : r eal ) ;


begin
Writ e ( 'el in te r s es i gual a .. , ) ,.
WriteL n (Cap i ta l * 4. 2 5)
end;

procedure Do s (Ca pi tal : rea l) ;


begin
WriteLn (' e l inte r s es i gua l a :', Cap it a l * 6) ;
end;
end. {fin de Financ a}

La seccin de interface de una unidad es la seccin pblica y la seccin de imple-


mentacin es la seccin privada.
Un programa que utilice la unidad puede referenciar cualquier cosa de la parte pblica
(interface), pero no puede referenciar nada en la parte de implementacin. Este proceso
de ocultacin de la informacin es muy til en el diseo de grandes programas.

2.3.4. Clusula uses en la seccin de implementacin


En las versiones a partir de la 5.0 una clusula us es se puede situar en la seccin de
implementacin. Esta propiedad permite ocultacin adicional de la informacin. Por ejem-
plo, supngase que la unidad P utiliza la unidad Q. Esta clusula uses puede ser situa-
da en la seccin de interface o en la seccin de implementacin. Si la clusula uses se
utiliza en la seccin de implementacin, entonces las declaraciones dadas en la unidad Q
slo pueden situarse en la seccin de implementacin de la unidad P. Ellas no pueden
situarse en la seccin interface de la unidad P.
Cuando se utiliza una clusula uses en la seccin de imp.lementacin, se sita in-
mediatamente despus de la palabra reservada imp l e mentation.
64 Estructura de datos

unit P;
interface
uses A, B, C;
,

,
)

implementation
uses Q; 1

2.3.4.1. Uso circular de unidades

La versin 5.0 permite el uso circular de unidades. Es posible a la unidad P utilizar la


unidad Q y a la unidad Q utilizar la unidad P: se pueden construir unidades mutuamente
dependientes. En ambos casos la clusula uses se debe situar en la seccin de implemen-
.,
taclOn.
Si se escriben unidades con referencia circular, se debe utilizar la orden Make del
men Compile en lugar de la orden Compile.

La orden Ka.ke gestiona las unidades, compilando


unlWlUl;;S
!..1_..1_
nece".1;-
.....",,"

2.3

El programa circular utiliza una unidad denominada Visualiz, que incorpora un procedi-
miento denominado EscribirEnPosicionXY, que a su vez se llama a otro procedimiento
denominado VerError que pertenece a una unidad denominada Errores, que contiene
una llamada a la unidad Visualizar.

program Circular;
{visualizar texto utilizando EscribirEnPosicionXY}
uses
Crt, Visualiz;
begin
ClrScr; {limpieza de la pantalla}
EscribirEnPosicionXY (1, 1, 'Test');
EscribirEnPosicionXY (90, 90,' Fuera de pantalla');
EscribirEnPosicionXY (10, 2, 'Retorno a pantalla')
end.

El procedimiento EscribirEnPosicionXY tiene tres parmetros; x, y, men-


saj e. x, y, coordenadas del punto en la pantalla de texto (de 25 x 80); mensaje, frase
a visualizar en la posicin (x, y).
Si las coordenadas (x, y) son vlidas, es decir, 1 <= x <= 80, Y 1 <= Y < 25 se escribe
el mensaje en la pantalla; si x e y no son vlidos (la posicin queda fuera de la pantalla),
se visualiza un mensaje de error. .
Construccin de grandes programas: mdulos versus unidades 65

unit Vi suali z;

interface
procedure Escrib i r Enpos i cionXY (X,Y :in teger; Me n sa j e :string ) ;
implementation
uses Crt, Error ;
procedure Es crib irE nPo si cionXY (X ,Y:in teger ; Men saje: string);
begin
if (X in [ 1 .. 80 ] ) and (Y in [1 .. 2 5])
then
begin
GotoXY (X , Y, ) ;
Wr it e (Mensaje)
end
else
VerEr r or ( ' Coordenadas XY fue r a de rango ' )
end
end.

El procedimiento VerError visualiza el mensaje' Error Fatal' en la lnea


25 de la pantalla.

unit Error;
interface
procedure VerE r r o r (C adena : string)
implementation
uses Vis ual i z ;
procedure Ver Err or (Cade n a : str i ng)
begin
Esc ri b i rEnPosicionXY ( 1, 25 , cadena)
end;
end.

Como habr observado en la clusula uses de las secciones de implementacin,


existen referencias mutuas (llamadas recprocas) de las unidades posibles porque Turbo
Borland Pascal puede compilar ambas secciones de interface completas.

""
.y
' .,~
,"

L
la otra
1 ..

-.c_ .< __ ,.
', :'. .- - .. ..
, >"". . . , .. c
"! " ,

, ,
2.4. UTILlZACION DE UNIDAD ESTANDAR

El archivo T URBO. T PL, que contiene todas las unidades estndar, se carga en memoria
central a la vez que el propio compilador y est disponible en cualquier momento, con
la ayuda de la clusula uses.
Un programa debe contener la clusula uses , situada inmediatamente despus de la
cabecera, cuando utiliza objetos declarados en una unidad.
66 Estructura de datos

program Test ;
uses
Crt, Pro ceso;
const
Mayor = 1 00 ;
type
Pal abra - string [ 2] ;
var
Ex presion : rea l;

Recordemos que las unidades estndar son:

Syst em Ove rl ay Do s Crt Pr in ter Gr a p h Grap h3 Turbo3

En este captulo se har una breve introduccin a las diferentes unidades. Todas las
unidades contienen una serie de objetos que estn declarados en la seccin de interface
(constantes, variables, tipos, procedimientos y funciones) y que son exportables o visua-
lizables desde cualquier programa o unidad que utilice dichas unidades.

2.4.1. Unidad System


Esta unidad contiene todos los procedimientos y funciones estndar de Turbo Borland
Pascal relativas a entradas/salidas, cadena de caracteres, clculos en coma flotante, ges-
tin de memoria, etc.
La unidad S y s t em tiene una configuracin especial, se enlaza automticamente en
la compilacin de cada programa y no precisa ser referenciada por la clusula uses
system.


2.4.2. Unidad Crt
Esta unidad proporciona un conjunto especfico de declaraciones para entrada y salida:
constantes, variables, procedimientos y funciones, que permiten el acceso al control de
los modos de pantalla, al teclado, a los colores, al posicionamiento del cursor, etc.
La mayora de los programas Turbo Borland Pascal que hacen uso de la pantalla para
representaciones de salida recurren a la unidad Crt. Algunos procedimientos tpicos son:
ClrS c r Borra la pantalla.
KeyPressed Detecta la pulsacin de una tecla.
Sou n d Hace sonar el altavoz interno.
wi ndow Define una ventana de texto en la pantalla.

EJEMPLO 2.4
El siguiente programa permite comprobar la velocidad de presentacin de los caracte-
res en la pantalla, creando una ventana de JO. 000 caracteres aleatorios que se repiten
tres veces.


I
, ;
Construccin de grandes programas: mdulos versus unidades 69

Desplazamiento de objetos grficos.


Trazado de figuras geomtricas e histogramas.

2.5. SITUACiN DE LAS UNIDADES EN SUS DISCOS:


DNDE BUSCA TURBO BORLAND PASCAL
LAS UNIDADES?
Las unidades existen fisicamente en una de las dos formas siguientes: como archivo indepen-
diente con su nombre y una extensin TPU (Turbo Borland Pascal Uni t), o como
parte de un archivo llamado TURBO. TPL. Pueden existir muchos archivos con extensin
TPU, pero slo puede haber un archivo. TPL (Turbo Borland Pascal Library).
TURBO. TPL se carga en la memoria de la computadora siempre que se arranca el
programa TURBO Borland Pascal, de modo que todas las unidades predefinidas,
tales como Crt, Dos, etc., estn siempre disponibles. No importa cul sea la unidad de
disco activa o en qu directorio est situado, su programa puede utilizar cualquiera
de estas unidades y el programa TURBO encontrar la unidad. Si se conoce de antemano
que algunas de las unidades residentes en TURBO. TPL no se van a utilizar, se pueden
eliminar con la utilidad llamada TPUMOVER. EXE. Esta operacin har ms pequea
TURBO. TPL Y permitir que la memoria sea utilizada para otras cosas; es decir, se pue-
den aadir las unidades del usuario al archivo TURBO. TPL.
Las unidades que disea el programador, el sistema TURBO espera encontrarlas en el
directorio activo de la unidad de disco activa. Esto significa que si tiene una unidad con pro-
cedimientos que utiliza con frecuencia, deber transferir la unidad cada vez que cambia el
directorio, o en caso contrario perder el acceso a esa unidad cuando no est en el directorio
activo. Es preciso indicar entonces al sistema TURBO en qu directorio estn las unidades.
Desgraciadamente no se puede situar un especificador de unidad o de camino en la
sentencia uses. Las sentencias siguientes no son vlidas:

uses Crt, Dos, C:\UnidadesUsuario;


uses Crt, C:\Prueba\UnidadesUsuario;

Algunos mtodos para indicar al sistema TURBO en qu directorio estn las unida-
des son:

Si los archivos de su unidad estn en el directorio actual (por ejemplo, e: \ Prac-


ticas) y el compilador est en e: \TURBO, se puede invocar el compilador
desde e : \ P r a c tic a s, el compilador las encontrar.
Supongamos que estn todas las unidades del usuario en el directorio Pruebas en
la unidad de disco B y se desea indicar al sistema que busque siempre all para
encontrar las unidades. Las operaciones a realizar son:

1. Activar el men Options.


2. Elegir la orden Directories de ese men. Se produce una lista con los
tipos de directorios que se pueden especificar.
70 Estructura de datos

3. Elegir de esa lista Unit Directories y aparecer una ventana en la pan-


talla. Teclee B:\Pruebas y, tras pulsar RETURN, aparece:

, Unit Dir ector ies

B: \ Pruebas

El sistema ya est preparado para buscar en ese directorio las unidades que
haya escrito. Cuando se encuentra una clusula uses, el sistema busca la unidad
en TURBO. TPL, si no la encuentra, busca en el directorio activo de la unidad de
disco activa. Si no se encuentra en ninguna de esas posiciones, entonces busca en
el directorio que se referenci como Uni t Directories, es decir, en el ejemplo
Pruebas, en la unidad B. En caso negativo el sistema produce un error.
Se pueden utilizar directorios mltiples. En este caso se pueden listar todos los
directorios separados por puntos y comas:

unit directories:B: \ Pr a c ti c as; B : \ P rue bas; C : \ De moU no

En esta ocasin TURBO busca, como siempre, en TURBO. TPL Y a continuacin


en el directorio activo para encontrar una unidad. Si no tiene xito la bsqueda, se
busca en el directorio Practicas de la unidad B. Si no existe ninguna unidad,
entonces se busca en Pruebas de la unidad B. Si tampoco tiene xito en la bs-
queda, entonces se busca en el directorio DemoUno de la unidad c. Si tampoco
tiene xito la bsqueda, se producir un mensaje de error.
La directiva $U tie~e prioridad sobre unidades del directorio actual o de los
directorios especificados en el men Opt ions, de modo que si tiene una unidad
idntica en su directorio actual, $U permite seleccionar una unidad del mismo
nombre almacenada en cualquier parte de su disco.
TURBO supone que el nombre de la unidad y el nombre del archivo que con-
tiene a la unidad son idnticos (por ejemplo, unidad Demo y archivos Demo. Pas
y Demo . TPU).

Reglas de funcionamiento

, " < - ,-, .~ - :,-,,_ ,::_,_-~--"-, , :~ " , : ;- ' - .. '----:----. ::-.,-.--,:" _; '_ -- ;-.-.-----, , ~"- ' - . - -'- '-- .~ , ": , '- ,-'l-

, '" Cuando aparece "tiri qomnre' d undatt"'ell' uilll"directiva 'use~T~rbopusC .esta


unidad (ldll)' ~ucesi'vmerite 'en: <' j, , (. ' ' '< ;.; ',
'" , ., _ _ " - -,' _" _ '-l/, ~: _ ;~_,:;';,',,I,:,;,i,;:< .. . -.. -" _--.', .. ,,"' , ,,::" : ,,.,, :" ,- '._ .,' l' ," .. ' . ' ;',', ,,':' ,

1. ' Entre las unid.des residetlte~en la biblioteca TURBO. TPL.


2. En oel directorio actual; "o' 'c o , .o, L, , ; , i , '

3. Los,ditectoris'citads '~n -l menOpt iorts: !' " ",' ,


- --, ,
. ;

- . "'", """ _
, - V. ' ->_-:- .-,>
y ,
., .
"
---------------------------------------------------------------------------------------

Construccin de grandes programas: mdulos versus unidades 71

El programa TPUMOVER
Las unidades estndar residen en la biblioteca TURBO. TPL Y se cargan automtica-
mente cuando arranca Turbo Borland Pascal. Al objeto de ahorrar memoria se pueden
transferir unidades poco utilizadas, tales como Turbo3 y Graph, fuera del archivo
TURBO. TPL, mediante la utilidad TPUMOVER. En otras palabras, esta utilidad se pue-
de utilizar para aadir o borrar desde TURBO. TPL.

2.6. IDENTIFICADORES IDNTICOS EN DIFERENTES UNIDADES


Es vlido tener identificadores idnticos dentro de dos unidades y utilizar ambas unida-
des en el mismo programa. Es decir, es posible tener una unidad llamada Pan t a 1 1 a
que contenga un procedimiento denominado ClrScr, de igual nombre que el procedi-
miento, ya conocido, de borrado de la pantalla de la unidad estndar Crt.
uses DOS , Crt, Pant alla;

En este caso se dispondra de dos procedimientos ClrScr. Cul utilizar? Turbo


Borland Pascal utiliza el ltimo procedimiento ClrScr que se encuentra al explorar las
unidades en la sentencia uses. En este ejemplo explora primero Crt y luego Pantalla,
y por consiguiente, se emplea el procedimiento ClrScr escrito por el usuario. Si se
intercambian los nombres de las unidades
uses DOS , Pa n talla, Crt ;

el compilador utilizar ahora el procedimiento estndar ClrScr. ,i


,
Un sistema de diferenciar los identificadores idnticos es utilizar el identificador de
la unidad y un punto.
program Pruebas ;
uses
Dos , Crt, Pantall a ;
begin
Crt. ClrScr ; {l i mp ie za de l a pantalla de t exto)
ClrScr; { li mp ieza de c u a l q u ier otra pantall a de texto)

end.

Con este mtodo es posible referenciar y diferenciar identificadores idnticos en


unidades diferentes. En el caso de que ningn nombre de unidad preceda al identificador
o referencia, se asigna la ltima unidad encontrada en la exploracin de unidades en la
sentencia uses.
,
2.7. SINTESIS DE UNIDADES
Una vez visualizadas todas las caractersticas de las unidades, vamos a realizar una sn-
tesis de las mismas al objeto de que el lector pueda asimilar totalmente y comenzar a
modularizar sus programas con la mxima eficiencia a partir de ese momento.
72 Estructura de datos

, , "
" ._"
-,
-._~-
., - .
--,<----~-----
,',' -' - - , > ,
,
;:.

Un programapuede disponer d.econstantes, definiciones, de tiposy subprogr:amas


preCompillld()s,in~iu)'endo ,tma senteifdaUse~ despu~s dl 'fa ,cbecra de ul1 pro-
" ' _ : .::: ............ .... '.i ' ," ' _: . . . , -" .:' ; t ., -! . OA . . . . ,

grama . .. ,' ' " ':';'"':"' ':':--:'' . . ,'.


,,',,"",">'" . . . . . , ' "" ' ':, "' ,~
- " : . . . ':":",',"':',;:.':" ,': . .:< - <;;:'::; ': :;',:' '" ,:
':- 'f "::'~' r.: :,
.. ,

2.7.1. Estructura de una unidad


Una unidad es un mdulo. No es un programa ejecutable. Existen unidades estndar
(por ejemplo, Crt; si desea acceder a procedimientos de esa unidad como e l r S e r,
Wi nd ow, debe incluir mediante una clusula uses la unidad e r t: uses e r t) Y unidades
creadas por el usuario.
Una unidad tiene una estructura ya conocida que contiene una cabecera, una parte
interface, una parte implementation y, evidentemente, una parte de iniciacin.
Los identificadores que aparecen en la seccin de interface son visibles desde cual-
quier programa que utiliza la unidad, pero los detalles de su estructura interna slo se
pueden conocer en la seccin de implementacin.
Desde el punto de vista profesional, usted puede proteger su cdigo fuente, distribu-
yendo en la documentacin del programa slo la seccin de interface y reservndose los
algoritmos y el cdigo fuente de la seccin de implementacin.
La cabecera de los procedimientos y funciones declaradas en la seccin de interface
debe ser idntica a la cabecera de las mismas funciones definidas en la seccin de imple-
mentacin; sin embargo, es posible escribir la cabecera en forma abreviada en la seccin
de implementacin. Los dos modelos de la unidad Ba s e que siguen despus en los mo-
delos son correctos y equivalentes.

unit < ide nti f icador > ; {cabecera obli gator i a}


{e l identif i cado r se u t il i za como n ombre del archivo
de l a u n idad ya co mpi l ada; l a e x te n s i n es .T PU}

interface
uses <li s t a de u ni dades > {op cional}
{dec l a r aciones pb l icas o visibles son opc i o n a l es}
cons t .... .
type ..... .
var ..... .

procedure ... {s l o cabece ra}


function ... {slo cabecera}

implementation
{dec l a r acio n es priva d as : l ocales a l a u n i d a d }
uses <li s t a de unida des >
const ... .
type .... .
var .....

J
,
,
,J

I
I
Construccin de grandes programas: mdulos versus unidades 73

procedure . . . . {cabece r a y c u erpo de l proced im ie n to}


furiction . . . . {cabecera y cue r po de la func i n }
[begin {se l ecc i n de i ni c ia l izacin : opc i onal}


endo {obligatoria , fin de i mp l emen t aci n }

Modelo 1 ,,
,
unit Base ;
,,

interface :
,
uses
Crt ;
procedure Mens aje (Texto : string);
implementation
procedure Mensaj e ;
begin
ClrScr ;
GotoXY ((80 - Leng t h (Texto)) div 2 , 4 ) ;
Wr i te (T ext o )
end;
begin
o o o

endo

Modelo 2
unit Base ;
interface
uses
Crt ;
procedure Me n saje (Te xt o : string );
implementation
procedure Me n saje (T ext o: string ) ;;
begin
Cl rScr ;
GotoXY ((80 - Length (Texto)) div 2 , 4) ;
Write (T ext o)
end;
begin
. . ...
endo

2.7.2. Excepciones en la escritura de unidades


Al escribir unidades debe tener en cuenta estas limitaciones:

La declaracin forward de los subprogramas no est permitida (no es necesa-


ria) en una unidad . .
74 Estructura de datos

Si un subprograma se declara como inline, su definicin de cdigo debe apa-


recer en la seccin de interface y el identificador del subprograma no debe apare-
cer en la seccin implementacin.
Si un subprograma es declarado external, su identificador no debe aparecer
en la seccin implementation.

2.7.3. Compilacin de unidades


La compilacin de una unidad se efecta del mismo modo que la compilacin de un
programa, con la diferencia de que al compilar el programa se obtiene un archivo aut-
nomo ejecutable (. EXE) y al compilar una unidad se obtiene un archivo en cdigo obje-
to (no ejecutable) como resultado, con extensin .TPU (Turbo Borland Pascal
Uni t), aunque con el mismo nombre que el archivo de cdigo fuente. Este cdigo obje-
to de un archivo. TPU slo es enlazable (linkable) por el compilador de Turbo BorIand
Pascal y no es compatible con archivos OBJ creados por otros compiladores.
Para crear unidades que pueda automticamente recompilar con las opciones Make
y Bui ld de Turbo BorIand Pascal se deben seguir estas reglas:

El identificador de unidad (especificado) en la cabecera debe ser el mismo que el


nombre del archivo fuente (sin incluir la extensin . PAS).
El nombre del archivo fuente debe tener una extensin (. PAS).
El archivo. TPU debe estar en el directorio actual o en un directorio especificado
con las opciones Options/Directories/Unit directories. El cdigo del
programa fuente debe estar en el directorio actual.

2.8. OTROS MTODOS DE ESTRUCTURAR PROGRAMAS:


rNCLUSIN, SOLAPAMIENTOS y ENCADENAMIENTO

Adems de las unidades, existen dos mtodos para estructurar o construir grandes pro-
gramas a partir de Turbo Borland Pascal 5.0: los archivos de inclusin (inelude) y los
solapamientos (overlays). Aunque es necesario hacer constar que si bien en las versio-
nes 3.0 y anteriores eran imprescindibles, su utilidad ha decado en 5.0, 6.0 Y 7.0 en
beneficio de las unidades.

2.8.1. Los archivos de inclusin o incluidos (include)


Como ya conoce el lector, la directiva Incluir Archivos (include) ($I) permite incluir
cdigo fuente en el programa que est en memoria, a partir de archivos externos de dis-
cos. El cdigo del programa ejecutable acta como si el cdigo incluido estuviera fsica-
mente presente en el archivo que se est compilando.
La directiva $I<nombrearchivo > permite ,
incluir el archivo denominado
<nombrearchi vo > durante la compilacin. Este es un mtodo para dividir su cdi-
go fuente en segmentos ms pequeos. Cuando el compilador encuentra la directiva

l,
Construccin de grandes programas: mdulos versus unidades 75

$I<nombrearchi vo>, abre el archivo del disco <nombrearchi vo> y comienza


a compilarlo. El archivo <nombrearchi vo> no se lee realmente en memoria como
un todo; el compilador lee simplemente lnea a lnea, compila la lnea a cdigo mquina
y a continuacin lee la siguiente lnea .

Utilizar hIclusin, para bibliQtecas


.... ,.", '.
... ... .
de
,
... ..... .. . .. ,,,,,,' " . ,
...... .......... ,'"
..
i

El uso actual de ls archivos de inclusin se suele reducir a archivos que contienen I,


procedimientos o funciones sencillas; o incluso la definicin de uno o ms tipos de da- ,


tos; como ejemplos tpicos: procedimientos o funciones de bsqueda, ordenacin, etc.

2.8.2. Los solapamientos (overlays)


Si se desarrollan grandes aplicaciones que deban correr sobre sistemas con recursos de
memoria limitados (640 K o menos), la tcnica de solapamientos es indispensable.
Los solapamientos (overlays) son partes de un programa que comparten una zona
de memoria comn. Slo las partes del programa que se requieren para una funcin dada
residen en memoria al mismo tiempo; se cargan (sobreescriben) una sobre otra durante
la ejecucin. Los solapamientos pueden reducir significativamente los requisitos totales
de memoria de un programa en tiempo de ejecucin. De hecho, con solapamientos se
pueden ejecutar programas que son mucho ms grandes que la memoria total disponible,
r
ya que slo partes del programa residen en memoria en un instante dado. f

La idea bsica del solapamiento es sta: se divide un programa en partes y se prepara


de modo que diferentes partes compartan el mismo lugar en memoria. Cuando el progra-

ma principal comienza la ejecucin, un solapamiento (segmento de programa) se carga


en una zona libre (sial) de la memoria. Cuando se requiere el segundo solapamiento, se
carga en memoria en la misma zona que el primer solapamiento, superponiendo el pri-
mer solapamiento. Posteriormente, cuando un tercero, cuarto o quinto solapamiento se
requieren, simplemente se cargan en la parte superior de cualquier solapamiento que
hubiese ocupado anteriormente la zona del solapamiento. De este modo, se pueden ma-
nejar megabytes de cdigo que pueden correr sobre memorias de 640 K, 256 K o incluso
menos. Simplemente necesita dividir esos megabytes de cdigo en un nmero suficiente
de solapamientos.

2.8.2.1. Gestin de los solapamientos


El sistema de solapamientos de la versin 7.0 y anteriores est basado en unidades. La
gestin de los mismos se realiza a nivel de unidad; sta es la parte ms pequea de un
programa que se puede hacer en un solapamiento. Cualquier nmero de unidades puede
ser especificado como solapamiento, lo que significa que cada uno ocupar la misma
regin de memoria cuando se cargan.
Todas las unidades especificadas como solapamientos (overlays) se enlazan en un
archivo independiente, con el mismo nombre que el programa principal, pero con una
I
,

76 Estructura de datos

extensin .OVR. En otras palabras, si un programa con solapamientos MI PROG . PAS


se compila, Turbo Borland Pascal genera un archivo de solapamiento (MI PROG . OVR) y
un archivo ejecutable (MI PROG . EXE). El archivo . EXE contiene las partes estticas
(no recubiertas) del programa y el archivo. OVR contiene todas las unidades de solapa-
miento que se intercambiarn en la memoria durante la ejecucin del programa.
Existe una sola zona de memoria para solapamientos, se denomina memoria inter-
media de solapamiento (overlay buffer), que reside en memoria entre el segmento de la
pila (stack) y el segmento para variables dinmicas (heap). Inicialmente el tamao de la
memoria intermedia de solapamiento se hace tan grande como sea necesaria, de modo
que puede contener la unidad de solapamiento ms grande; posteriormente puede incre-
mentarse su tamao, si as se desea. Si no existe bastante memoria disponible cuando se
carga la unidad, se visualizarn mensajes de error:
Program too big to fit in memory
Not enough memory to rum program

El gestionador de solapamientos tiene la posibilidad de cargar el archivo recubierto


en memoria ampliada o expandida (EMS) cuando exista espacio disponible suficiente.
Si la librera en tiempo de ejecucin detecta memoria EMS (Expanded Memory Specifi-
cation) libre, el archivo de solapamiento se sita en la memoria EMS RAM.
La Figura 2.2. muestra el sistema de funcionamiento de los solapamientos.

2.8.3. La unidad Overlay (generacin de solapamientos)


Turbo Borland Pascal proporciona un gestionador de archivos que manipulan acceso a
solapamientos en una unidad llamada Overlay. Si se trata de utilizar solapamientos,
se debe incluir Overlay en su sentencia Uses, antes de todas las unidades a recubrir.
Para disear programas con solapamientos se deben seguir las siguientes reglas:
1. Una unidad especificada como solapamiento debe ser compilada con la directiva
$0. Esta directiva define una unidad como un solapamiento.
La directiva $0 tiene dos formatos: un formato de tipo conmutador y un
formato de parmetro .
formato conmutador {$O+}
{$O-}
formato parmetro {$Oparmetro}

$0+ situada en la unidad del archivo fuente, se activa su uso como


un solapamiento, pero no se requiere su uso como solapamien-
to; puede ser enlazada, todava, normalmente si se desea.
$0 Xmodem indica al programa principal que la unidad llamada Xmodem se
trate como un solapamiento.

Las. directivas
Construccin de grandes programas: mdulos versus unidades 77

program Mortim e r;
{$ F + }
uses overlay, Dos , Crt, Circu l os , Xmodem, Kermit, Parse r;
( SO Xmodem)
{SO Kermit}
{SO Parse r }

2. En el ejemplo anterior se observa la directiva $F+. La razn es que todas las


unidades utilizadas por el programa, as como el propio programa, deben ser
compiladas con la directiva Far Calla activada ({$F+}). Por esta causa,
$F+ se sita inmediatamente despus de la sentencia programo
3. Inicializar el gestionador (manipulador) de solapamientos. El cdigo de inicia-
cin se debe situar antes de la primera llamada a una rutina de solapamiento, y
en particular al principio de la parte de sentencias del programa. La llamada se
realiza con Ov r I n i t, cuyo formato es Ovr I ni t (nambrearchi va ).

MIPR OG . EXE MIPR OG . OVR

Unit Tee; Unit Tee;

Heap Unit Tie; Unit Tie;

Unit Toe; Unit Toe ;

Unit Tum; Unit Tum;

Unit Tea; Unit Tea;


fondo

overlay buffer (debe ser


tan grande como el Unit Tir; Unit Tir;
mayor solapamiento



cima

Unit Tas ; Unit Tas;

Stack
Memoria EMS Almacenamiento
(si existe) en disco (DOS)
Memoria principal
(DOS)

Figura 2.2. Archivos y memorias de solapamiento.

Ejemplo
begin
Ov rI n i t i ' MIP ROG . OVR' )
end;
o.. _

78 Estructura de datos

2.8.3.1. Constantes y variables de la unidad Overlay


const
Ov r Ok - o;
Ov rEr r o r -- - 1 ;
OvrN ot Found - -2;
Ovr No Me mory - -3;
Ovr lo Erro r - -4i
Ov rN o EM SDri ve r - - 5 ;
Ov rNoEMSMemo r y - - 6 ;
var
Ov r Res ult : integer;
,
,
,
2.8.3.2. Procedimientos y funciones de la unidad Overlay
Procedimientos Funciones
Ov r l n it Ovr Ge tBuf
OvrlnitEMS
Ov r Se t Buf
Ov r Cl e a r Buf

OvrClearBuf
Este procedimiento permite borrar temporalmente la memoria intellnedia de solapamiento;
esta operacin se debe realizar cuando se necesite utilizar la memoria que ocupa.

OvrClearBuf

OvrGetBuf
Devuelve el tamao actual de la memoria inte/media de solapamiento, en VarLonglnt.

VarLonglnt:= OvrGetBuf

Ovrlnit
Inicializa el gestionador de solapamientos y abre el archivo de solapamiento.

Ovrlnit (nombrearchivo)

OvrlnitEMS
Verifica que existe un controlador EMS y suficiente memoria EMS para contener el
archivo de solapamiento.

OvrlnitEMS
Construccin de grandes programas: mdulos versus unidades 79

OvrSetBuf
Establece el tamao de la memoria intermedia de solapamiento (o ver/ay buffer).

OvrSetBuf (VarLonglnt)

VarLonglnt variable de tipo /ongint

2.8.4. Encadenamiento de archivos compilados


Turbo Borland Pascal produce archivos. EXE en lugar de los archivos ms simples. COM
que producir la versin 3; por esta razn no puede soportar encadenamiento de progra-
mas con datos compartidos. Se puede utilizar el procedimiento Exec de Turbo Borland
Pascal 5, 6 Y 7 para transferir el control de un programa a otro, pero cada programa
tendr su propio segmento de datos.

RESUMEN
Una unidad es una coleccin de procedimientos y funciones de propsito general, guardadas en
disco de forma compilada. Las unidades se pueden utilizar para construir su propia librera de
procedimientos y funciones predefinidas. Esta librera puede ser utilizada en diferentes proyectos
y por diferentes equipos de programadores.
Las unidades refuerzan el concepto de abstraccin de datos. Esto se consigue situando los deta-
lles sobre procedimientos implementados en una unidad, y por consiguiente ocultando estos detalles.

Sintaxis de una unidad

unit <nombre>
interface
uses <lista de u nidades utilizadas por esta unidad >
{s e omite si no se uti liza ninguna unidad}
<cabeceras de procedimientos y f u n c i o nes >
<o tras declaraciones >
implementation
<declaraciones compl etas de pro ced imientos y fun cio nes >
begin {no se necesita si n o existen se ntencias de i nicializ ac i n}


end.

EJERCICIOS
2.1. Disear una unidad Lib 1 que defina las tres funciones siguientes, que puedan ser utilizadas
posteriormente por cualquier programa:

80 Estructura de datos

function Mn (Xl, X2 : integer) : integer;


{devuelve el elemento ms pequeo de Xl y X2}
function Mx (Xl,X2 : integer) : integer;
{devuelve el elemento mayor de Xl y X2}
function Media (Xl, X2 : integer): real;
{devuelve la media de Xl y X2}

Escribir un programa que haga uso de la unidad.


2.2. Construir una unidad que contenga las siguientes funciones estadsticas de un vector x de n
elementos.

n
Desviacin media (DM = ~L
i 1
=
x-x I

donde x =

I es el valor absoluto
n
Media cuadrtica (MC) = #. L xl
1= 1

Media armnica (MA) n-,----,--


= ___
n l
L
. 1
1=
x I

2.3. Escribir una unidad llamada Grados que incluya funciones para convertir grados sexagesi-
males y centesimales a radianes. Disear un programa que permita calcular los valores de
las funciones trigonomtricas seno, coseno y tangente de una tabla de valores angulares
dados en grados sexagesimales y centesimales (incremento del ngulo en la tabla, 1 grado).
2.4. Dadas dos matrices, A y B, donde

all a 12 al n b ll b 12 b lm
a 21 a22 a2n b21 b22 b 2m
A= y B=

ami a m2 a mn bml b m2 bmn

Disear una unidad que contenga los procedimientos o funciones: producto y suma de
A y B.
2.5. Disear una unidad que soporte las siguientes dos funciones de tiempo:

Fecha (convierte los parmetros numricos proporcionados por el procedimiento Ge t-


Date en una cadena con el formato DaSemana Da Mes Ao: ds DD MMAA).
Hora (convierte valores numricos proporcionados por el procedimiento Ge t Time en
una cadena de formato: 'hh mm ss').
Construccin de grandes programas: mdulos versus unidades 81

Nota

o. , ,
' .
.' '
Y
, .

, --.-

2.6. Escribir una unidad que manipule tipos de datos abstractos Enteros grandes (enteros de al
menos 2 dgitos). Debe proporcionar nmeros positivos y negativos, y las operaciones de
suma, resta, multiplicacin y divisin.
2.7. Escribir una unidad cuyos subprogramas bsicos deben ser:
Operacin traspuesta de una matriz.
Multiplicaciones de dos matrices cuadradas.
Suma de dos matrices cuadradas.
2.8. Crear una unidad que se componga de procedimientos y funciones que realicen las tareas
siguientes:
Hacer el cursor visible o invisible.
Emitir un sonido (pitido bip).
Borrar la parte de pantalla situada entre dos lneas.
Convertir las letras de una cadena de caracteres en maysculas.
Convertir un valor numrico en una cadena de caracteres.
Insertar caracteres.
2.9. Escribir una unidad que contenga los procedimientos de cambios de base de numeracin:
paso de base 2 a base 16, base 2 a base 1O Y base 10 a base 2.
2.10. Escribir una unidad que contenga procedimientos y funciones que efecten las tareas si-
guientes:

Desplazar una cadena de caracteres en la pantalla, de izquierda a derecha o viceversa


y de velocidad ajustable.
Visualizar una ventana.
Mover el cursor por la pantalla.

2. 11. Escribir la unidad Prueba que contenga dos funciones para asegurar divisiones correc-
tas y evitar la divisin por cero, que produce un error irrecuperable en la ejecucin del
programa. Aplicacin prctica: Escribir un programa Demo Prueba que utilice las fun-
ciones creadas en la unidad Prueba.
2.12. Crear una unidad Aleatori que contenga tres funciones que proporcionen valores ge-
nerados aleatoriamente de tres tipos diferentes: enteros, cadenas y lgicos. Las funciones
a definir se denominan EnterasA, cadenasA. LagicasA.

EnterasA Proporciona un entero comprendido en un intervalo de valores especfi-


cos Min y Max.
Enteros (Min y Max).
En t e ro sA ( 5 , 5 O) genera un entero aleatorio entre 5 y 50.
CadenaA Proporciona una cadena de letras maysculas arbitrarias.
CadenaA (n) n, nmero de letras.
LagicasA Proporciona un valor lgico aleatorio.
,

82 Estructura de datos

2. 13. Escribir un programa que visualice seis lneas que contengan cada una de ellas un entero
entre 300 y 400, una cadena de ocho letras y un valor true o false, todos ellos aleatorios.
325 MNRPQANT true
346 LOIVRSTN false
37l MSPBVTRL true
382 NZJMKSBC false
343 FGRILTRP true
Nota: Utilice la unidad Aleatori.
2.14. El programa siguiente lee un archivo de entrada (programa fuente en Pascal) y lo convier-
te en otro archivo de salida (programa fuente en Pascal) con las palabras reservadas de
Turbo Borland Pascal en negritas y maysculas.

,
REFERENCIAS BIBLlOGRAFICAS
1. Borland: Reference Guide. Turbo Borland Pascal 5.0. Captulo 13.
Si desea trabajar con solapamientos, este captulo le complementar las ideas expuestas en la
seccin 2.8.

2. Dunteman, Jeff: Complete Turbo Borland Pascal. Third Edition. Scott Foreman, 1989.
Es una excelente obra para profundizar en Turbo Borland Pascal. Recomendada para usuarios
expertos y como ampliacin de conocimientos tras la lectura de esta obra.

3. Joyanes, Luis: Turbo/Borland Pascal 7. Iniciacin y Referencia, Madrid, McGraw-Hilll, 1997.

,
CAPITULO

.,
stracclon e atos: ti os a stractos

atos o etos
., '.

CONTENIDO

3.1. El papel (el rol) de la abstraccin.

3.2. Un nuevo paradigma de programacin.


3.3. Modularidad.
3.4. Diseo de mdulos.
3.5. Tipos de datos.
3.6. Abstraccin en lenguajes de programacin.
3.7. Tipos abstractos de datos.
3.8. Tipos abstractos de datos en Turbo Borland Pascal.
3.9. Orientacin a objetos.
3.10. Reutilizacin de software.
3.11. Lenguajes de programacin orientados a objetos.
3.12. Desarrollo tradicional frente a orientado a objetos.
3.13. Beneficios de las tecnologas de objetos (TO).
RESUMEN.
EJERCICIOS.

En este captulo examinaremos los conceptos de modularidad y abs-


traccin de datos. La modularidad es la posibilidad de dividir una
aplicacin en piezas ms pequeas llamadas mdulos. Abstraccin de
datos es la tcnica de inventar nuevos tipos de datos que sean ms ade-
cuados a una aplicacin y, por consiguiente, facilitar la escritura del
programa. La tcnica de abstraccin de datos es una tcnica potente de
propsito general que cuando se utiliza adecuadamente, puede produ-
cir programas ms cortos, ms legibles y flexibles.
Los lenguajes de programacin soportan en sus compiladores tipos
de datos fundamentales o bsicos (predefinidos), tales como int, char
y float en e y C++, o bien integer, real o boolean en
Pascal. Algunos lenguajes de programacin tienen caractersticas que
permiten ampliar el lenguaje aadiendo sus propios tipos de datos.

83
84 Estructura de datos

Un tipo de dato definido por el programador se denomina tipo abs-


tracto de dato, TAD (abstract data type, ADT). El trmino abstracto se
refiere al medio en que un programador abstrae algunos conceptos de
programacin creando un nuevo tipo de dato.
La modularizacin de un programa utiliza la nocin de tipo abs-
tracto de dato (TAD) siempre que sea posible. Si el TAD soporta los
tipos que desea el usuario y el conjunto de operaciones sobre cada tipo,
se obtiene un nuevo tipo de dato denominado objeto .


3.1. EL PAPEL (EL ROL) DE LA ABSTRACCION

Los programadores han tenido que luchar con el problema de la complejidad durante
mucho tiempo desde el nacimiento de la informtica. Para comprender lo mejor posible
la importancia de las tcnicas orientadas a objetos, revisemos cules han sido los dife-
rentes mecanismos utilizados por los programadores para controlar la complejidad. En-
tre todos ellos se destaca la abstraccin. Como describe Wulft: Los humanos hemos
desarrollado una tcnica excepcionalmente potente para tratar la complejidad: abstraer-
nos de ella. Incapaces de dominar en su totalidad los objetos complejos, se ignora los
detalles no esenciales, tratando en su lugar con el modelo ideal del objeto y centrndo-
nos en el estudio de sus aspectos esenciales.
En esencia, la abstraccin es la capacidad para encapsular y aislar la informacin,
del diseo y ejecucin. En otro sentido, las tcnicas orientadas a objetos se ven como
resultado de una larga progresin histrica que comienza en los procedimientos y sigue
en los mdulos, tipos abstractos de datos y objetos.

3.1.1. La abstraccin como un proceso mental natural


Las personas normalmente comprenden el mundo construyendo modelos mentales de
partes del mismo, tratan de comprender cosas con las que pueden interactuar: un modelo
mental es una vista simplificada de cmo funciona de modo que se pueda interactuar
contra ella. En esencia, este proceso de construccin de modelos es lo mismo que el
diseo de software; aunque el desarrollo de software es nico, el diseo de software
produce el modelo que puede ser manipulado por una computadora.
Sin embargo, los modelos mentales deben ser ms sencillos que el sistema al cual
imitan, o en caso contrario sern intiles. Por ejemplo, consideremos un mapa como un
modelo de su territorio. A fin de ser til, el mapa debe ser ms sencillo que el territorio
que modela. Un mapa nos ayuda, ya que abstrae slo aquellas caractersticas del territo-
rio que deseamos modelar. Un mapa de carreteras modela cmo conducir mejor de una
posicin a otra. Un mapa topogrfico modela el contorno de un territorio, quizs para
planear un sistema de largos paseos o caminatas.
De igual forma que un mapa debe ser ms pequeo significativamente que su te-
rritorio e incluye slo informacin seleccionada cuidadosamente, as los modelos


Abstraccin de datos: tipos abstractos de datos y objetos 85

mentales abstraen esas caractersticas de un sistema requerido para nuestra compren-


sin, mientras ignoran caractersticas irrelevantes. Este proceso de abstraccin es psico-
lgicamente necesario y natural, la abstraccin es crucial para comprender este comple-
jo mundo.
La abstraccin es esencial para el funcionamiento de una mente humana normal, y es
una herramienta muy potente para tratar la complejidad. Considerar por ejemplo el ejer-
cicio mental de memorizar nmeros. Un total de nueve dgitos se puede memorizar con
ms o menos facilidad. Sin embargo, si se agrupan y se denominan nmeros de telfono,
los dgitos individuales se relegan en sus detalles de ms bajo nivel, crendose un nivel
abstracto y ms alto, en el que los nueve dgitos se organizan en una nica entidad (el
nmero de telfono). Utilizando este mecanismo, se pueden memorizar algunos nme-
ros de telfonos de modo que la agrupacin de diferentes entidades conceptuales es un

mecanismo potente al servicio de la abstraccin.

3.1.2. Historia de la abstraccin del software


La abstraccin es la clave para disear buen software. En los primeros das de la infor-
mtica, los programadores enviaban instrucciones binarias a una computadora, manipu-
lando directamente interrupciones en sus paneles frontales. Los nemotcnicos del len-
guaje ensamblador eran abstracciones diseadas para evitar que los programadores tuvieran
que recordar las secuencias de bits que componen las instrucciones de un programa. El
siguiente nivel de abstraccin se consigue agrupando instrucciones primitivas para for-
mar macroinstrucciones.
Por ejemplo, un conjunto se puede definir por abstraccin como una coleccin no
ordenada de elementos en el que no existen duplicados. Utilizando esta definicin, se
pueden especificar si sus elementos se almacenan en un array, una lista enlazada o cual-
quier otra estructura de datos. Un conjunto de instrucciones realizadas por un usuario se
pueden invocar por una macroinstruccin. Una macroinstruccin instruye a la mquina
para que realice muchas cosas. Tras los lenguajes de programacin ensambladores apa-
recieron los lenguajes de programacin de alto nivel, que supusieron un nuevo nivel de
abstraccin. Los lenguajes de programacin de alto nivel permitieron a los programado-
res distanciarse de las interioridades arquitectnicas especficas de una mquina dada.
Cada instruccin en un lenguaje de alto nivel puede invocar varias instrucciones mqui-

na, dependiendo de la mquina especfica donde se compila el programa. Esta abstrac-
cin permita a los programadores escribir software para propsito genrico, sin preocu-
parse sobre qu mquina corre el programa.
Secuencias de sentencias de lenguajes de alto nivel se pueden agrupar en procedi-
mientos y se invocan por una sentencia. La programacin estructurada alienta el uso de
abstracciones de control tales como bucles o sentencias if-then que se han incorporado
en lenguajes de alto nivel. Estas sentencias de control permitieron a los programadores
abstraer las condiciones comunes para cambiar la secuencia de ejecucin.
El proceso de abstraccin fue evolucionando desde la aparicin de los primeros len-
guajes de programacin. El mtodo ms idneo para controlar la complejidad fue au-
mentar los niveles de abstraccin. En esencia, la abstraccin supone la capacidad de
,
,
86 Estructura de datos


!
t
encapsular y aislar la informacin de diseo y ejecucin. En un determinado sentido, las r,
,
;
tcnicas orientadas a objetos pueden verse como un producto natural de una larga pro-
gresin histrica que va desde las estructuras de control, pasando por los procedimien- ,t
tos, los mdulos, los tipos abstractos de datos y los objetos. r
En las siguientes secciones describiremos los mecanismos de abstraccin que han
conducido al desarrollo profundo de los objetos: procedimientos, mdulos, tipos abs-
tractos de datos y objetos .

3.1.3. Procedimientos
Los procedimientos y funciones fueron uno de los primeros mecanismos de abstrac-
cin que se utilizaron ampliamente en lenguajes de programacin. Los procedimientos
permitan tareas que se ejecutaban rpidamente, o eran ejecutados slo con ligeras varia-
ciones, que se reunan en una entidad y se reutilizaban, en lugar de duplicar el cdigo
varias veces. Por otra parte, el procedimiento proporcion la primera posibilidad de ocul-
tacin de informacin. Un programador poda escribir un procedimiento o conjunto de
procedimientos, que se utilizaban por otros programadores. Estos otros programa-
dores no necesitaban conocer con exactitud los detalles de la implementacin, slo ne-
cesitaban el interfaz necesario. Sin embargo, los procedimientos no resolvan todos los
problemas. En particular, no era un mecanismo efectivo para ocultar la informacin y
para resolver el problema que se produca al trabajar mltiples programadores con nom-
bres idnticos.
Para ilustrar el problema, consideremos un programador que debe escribir un con-
junto de rutinas para implementar una pila. Siguiendo los criterios clsicos de diseo de
software, nuestro programador establece en primer lugar el interfaz visible a su trabajo,
es decir, cuatro rutinas: meter, sacar, pilavaca y pilallena. A continuacin implementa
los datos rutinas mediante arrays, listas enlazadas, etc. Naturalmente los datos conteni-
dos en la pila no se pueden hacer locales a cualquiera de las cuatro rutinas, ya que se
deben compartir por todos. Sin embargo, si las nicas elecciones posibles son variables
locales o globales, entonces la pila se debe mantener en variables globales; por el con-
trario, al ser las variables globales, no ,existe un mtodo para limitar la accesibilidad o
visibilidad de dichas variables. Por ejemplo, si la pila se representa en un array denomi-
nado datospila, este dato debe ser conocido por otros programadores, que puedan desear
crear variables utilizando el mismo nombre pero relativo a las referidas rutinas. De modo
similar las rutinas citadas estn reservadas y no se pueden utilizar en otras partes del
programa para otros propsitos. En Pascal existe el mbito local y global. Cualquier
mbito que permite acceso a los cuatro procedimientos debe permitir tambin el acceso
a sus datos comunes. Para resolver este problema, se ha desarrollado un mecanismo de
estructuracin diferente.

3.1.4. Mdulos
Un mdulo es una tcnica que proporciona la posibilidad de dividir sus datos y procedi-
mientos en una parte privada slo accesible dentro del mdulo y parte pblica


Abstraccin de datos: tipos abstractos de datos y objetos 87

-accesible fuera del mdulo . Los tipos, datos (variables) y procedimientos se pueden
definir en cualquier parte.
El criterio a seguir en la construccin de un mdulo es que si no se necesita algn
tipo de informacin, no se debe tener acceso a ella. Este criterio es la ocultacin de
informacin.
Los mdulos resuelven algunos problemas, pero no todos los problemas del desarro-
llo de software. Por ejemplo, los mdulos petmitirn a nuestros programadores ocultar
los detalles de la implementacin de su pila, pero qu sucede si otros usuarios desean
tener dos o ms pilas? Supongamos que un programador ha desarrollado un tipo de dato
e omp 1 e j o (representacin de un nmero complejo) y ha definido las operaciones arit-
mticas sobre nmeros 'complejos suma, resta, multiplicacin y divisin ; asimismo
ha definido rutinas para convertir nmeros convencionales a complejos. Se presenta un
problema: slo puede manipular un nmero complejo. El sistema de nmeros complejos
no ser til con esta restriccin, pero es la situacin en que se encuentra el programador
con mdulos simples.
Los mdulos proporcionan un mtodo efectivo de ocultacin de la informacin, pero
no permiten realizar instanciacin, que es la capacidad de hacer mltiples copias de las
zonas de datos.

3.1.5. Tipos abstractos de datos


Un tipo abstracto de datos (TAD) es un tipo de dato definido por el programador que se
puede manipular de un modo similar a los tipos de datos definidos por el sistema. Al
igual que los tipos definidos por el sistema, un tipo de dato abstracto corresponde a un
conjunto (puede ser de tamao indefinido) de valores legales de datos y un nmero de
operaciones primitivas que se pueden realizar sobre esos valores. Los usuarios pueden
crear variables con valores que estn en el rango de valores legales y pueden operar
sobre esos valores utilizando las operaciones definidas. Por ejemplo, en el caso de la
pila ya citada, se puede definir dicha pila como un tipo abstracto de datos y las operacio-
nes sobre la pila como las nicas operaciones legales que estn peIluitidas para ser rea-
. lizadas sobre instancias de la pila.
Los mdulos se utilizan frecuentemente como una tcnica de implementacin para
tipos abstractos de datos, y el tipo abstracto de datos es un concepto ms terico. Para
construir un tipo abstracto de datos se debe poder:
1. Exponer una definicin del tipo.
2. Hacer disponible un conjunto de operaciones que se pueden utilizar para mani-
pular instancias de ese tipo.
3. Proteger los datos asociados con el tipo de modo que slo se puede actuar sobre
ellas con las rutinas proporcionadas.
4. Hacer instancia mltiples del tipo.
Los mdulos son mecanismos de ocultacin de infoIlnacin y no cumplen bsica-
mente ms que los apartados 2 y 3. Los tipos abstractos de datos se implementan con
mdulos en Modula-2 y paquetes en CLU o Ada .

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ __ ~.~
_ _ o ..... " _ _ _ _
88 Estructura de datos

3.1.6. Objetos
Un objeto es sencillamente un tipo abstracto de datos al que se aaden importan-
tes innovaciones en comparticin de cdigo y reutilizacin. Los mecanismos bsicos de
orientacin a objetos son: objetos, mensajes y mtodos, clases e instancias y herencia.
Una idea fundamental es la comunicacin de los objetos a travs de paso de mensa-
jes. Adems de esta idea, se aaden los mecanismos de herencia y polimorfismo. La
herencia permite diferentes tipos de datos para compartir el mismo cdigo, permitiendo
una reduccin en el tamao del cdigo y un incremento en la funcionalidad. El polimor-
fismo permite que un mismo mensaje pueda actuar sobre objetos diferentes y comportar-
se de modo distinto.
La persistencia se refiere a la permanencia de un objeto, esto es, la cantidad de tiem-
po para el cual se asigna espacio y permanece accesible en la memoria del compu-
tador.

Conceptos
clave

Abstraccin Encapsulacin Persistencia

Herencia Polimorfismo Genericidad

Entidades bsicas

Mensajes Herencia
Objeto
Mtodos Jerarqua

Figura 3.1. Principios bsicos de la orientacin a objetos.

3.2. UN NUEVO PARADIGMA DE PROGRAMACiN

La programacin orientada a objetos (POO) I se suele conocer como un nuevo paradig-


ma de programacin. Otros paradigmas conocidos son: el paradigma de la progra-
macin imperativa (con lenguajes tales como Pascal o C), el paradigma de la progra-

I En ingls, OOP (Object Oriented Prograrnrning).


Abstraccin de datos: tipos abstractos de datos y objetos 89

macin lgica (PROLOG) y el paradigma de la programacin funcional (Lisp). El sig-


nificado de paradigma 2 (paradigma, en latn; paradigma, en griego) en su origen signi-
ficaba un ejemplo ilustrativo, en particular enunciado modelo que mostraba todas las
inflexiones de una palabra. En el libro The Structure ofScientific Revolutions el historia-
dor Thomas Kuhn 3 [Kuhn 70] describa un paradigma como un conjunto de teoras,
estndar y mtodos que juntos representan un medio de organizacin del conocimiento:
es decir, un medio de visualizar el mundo. En este sentido la programacin orientada a
objetos es un nuevo paradigma. La orientacin a objetos fuerza a reconsiderar nuestro
pensamiento sobre la computacin, sobre lo que significa realizar computacin y sobre
cmo se estructura la informacin dentro del computador.
Jenkins y Glasgow observan que la mayora de los programadores trabajan en un
lenguaje y utilizan slo un estilo de programacin. Ellos programan en un paradigma
forzado por el lenguaje que utilizan. Con frecuencia, no se enfrentan a mtodos alterna-
tivos de resolucin de un problema, y por consiguiente tienen dificultad en ver la ventaja
de elegir un estilo ms apropiado al problema a manejar. Bobrow y Stefik definen un
estilo de programacin como un medio de organizacin de programas sobre la base
de algn modelo conceptual de programacin y un lenguaje apropiado para hacer
programas en un estilo claro. Sugiere que existen cuatro clases de estilos de progra-
.,
maClOn:

Orientados a procedimientos Algoritmos


Orientados a objetos Clases y objetos
Orientados a lgica Expresado en clculo de predicados
Orientados a reglas Reglas if-then

No existe ningn estilo de programacin idneo para todas las clases de pro-
gramacin. La orientacin a objetos se acopla a la simulacin de situaciones del mun-
do real.
En POO, las entidades centrales son los objetos, que son tipos de datos que encapsu-
lan con el mismo nombre estructuras de datos y las operaciones o algoritmos que mani-
pulan esos datos.

3.3. MODULARIDAD

La programacin modular trata de descomponer un programa en un pequeo nmero de


abstracciones coherentes que pertenecen al dominio del problema y cuya complejidad
interna es susceptible de ser enmascarada por la descripcin de un interfaz.

2 Un ejemplo que sirve como modelo o patrn: Dictionary of Science and Techn%gy, Academic
Press, 1992.
3 Kuhn, Thomas S.: The Structure of Scientific Revo/ution, 2." ed.~ University of Chicago Press, Chi-
cago, 1970.
90 Estructura de datos

Si las abstracciones que se desean representar pueden, en ciertos casos, correspon-


der a una nica accin abstracta y se implementan en general con la nocin de objeto
abstracto (o tipo abstracto) caracterizado en todo instante por:

Un estado actual, definido por un cierto nmero de atributos.


Un conjunto de acciones posibles.

En consecuencia, la modularidad es la posibilidad de subdividir una aplicacin


en piezas ms pequeas (denominadas mdulos) cada una de las cuales debe ser tan
independiente como sea posible, considerando la aplicacin como un todo, as como de
las otras piezas de las cuales es una parte. Este principio bsico desemboca en el princi-
pio bsico de construir programas modulares. Esto significa que, aproximadamente, ha
de subdividir un programa en piezas ms pequeas, o mdulos, que son generalmente
independientes de cada una de las restantes y se pueden ensamblar fcilmente para
construir la aplicacin completa. En esencia, las abstracciones se implementan en mdu-
los, conocidos en la terminologa de Booch como objetos, que agrupan en una sola
entidad:

Un conjunto de datos. .
Un conjunto de operaciones que actan sobre los datos.

Liskov define la modularizacin como el proceso de dividir un programa en mdu-


los que se pueden compilar separadamente, pero que tienen conexiones con otros m-
dulos. Pamas va ms lejos y dice que las conexiones entre mdulos deben seguir el
criterio de ocultacin de la informacin: un sistema se debe descomponer de acuerdo al
criterio general, de que cada mdulo oculta alguna decisin de diseo del resto del siste-
ma; en otras palabras, cada mdulo oculta un secreto.
Si un programa se descompone (o subdivide en mdulos) de modo consistente con el
criterio de Pamas es decir, aplicando el principio de ocultacin de la informacin se

reduce la complejidad de cada mdulo que compone la solucin. Estos se constituyen,
en cierto modo, independientes de los restantes y, por consiguiente, se reduce la necesi-
dad de tomar decisiones globales, operaciones y datos.

3.3.1. La estructura de un mdulo


Un mdulo se caracteriza fundamentalmente por su interfaz y por su implementacin.
Pamas define el mdulo como un conjunto de acciones denominadas, funciones o sub-
mdulos que corresponden a una abstraccin coherente, que compartan un conjunto de
datos comunes implantadas estticamente llamadas atributos, eventualmente asociadas
a definiciones lgicas de tipos. Las acciones o funciones de un mdulo que son suscep-
tibles de ser llamadas desde el exterior se denominan primitivas o puntos de entrada del
mdulo. Los tipos lgicos eventualmente definidos en la interfaz permiten representar
los parmetros de estas primitivas.
Abstraccin de datos: tipos abstractos de datos y objetos 91

Interfaz Primitivas de acceso


Descripcin de propiedades de los datos

Atributos Algoritmos
Seccin
privada
Representacin Parmetros actuales

Figura 3.2. Estructura de un mdulo.

3.3.2. Reglas de modularizacin


En primer lugar, un mtodo de diseo debe ayudar al programador a resolver un proble,.
ma dividiendo el problema en subproblemas ms pequeos, que se puedan resolver in-
dependientemente unos de otros. Debe, tambin, ser fcil conectar los diferentes mdu-
los a los restantes, dentro del programa que est escribiendo.
Cada mdulo tiene un significado especfico propio y se debe asegurar que cualquier
cambio a su implementacin no afecte a su exterior (o al menos, lo mnimo). De igual
modo los errores posibles, condiciones de lmites o frontera, comportamientos errticos
no se propaguen ms all del mdulo (o como mximo, a los mdulos que estn directa-
mente en contacto con el afectado).
Para obtener mdulos con las caractersticas anteriores, se deben seguir las siguien-
tes reglas:

Unidades modulares
El lenguaje debe proporcionar estructuras modulares con las cuales se puedan des-
cribir las diferentes unidades. De este modo, el lenguaje (y el compilador) puede reco-
nocer un mdulo y debe ser capaz de manipular y gobernar su uso, adems de las ven-
tajas evidentes relativas a la legibilidad del cdigo resultante. Estas construcciones
modulares pueden, como en el caso de los lenguajes orientados a objetos, mostrar carac-
tersticas que facilitan la estructura del programa, as como la escritura de programas.
En otras palabras, nos referimos a las unidades modulares lingsticas que en el caso de
C++ se conocen como clases y en Turbo Borland Pascal, los mdulos se denominan
unidades. La sintaxis de las unidades diferencia entre el interfaz y la implementacin
del mdulo. Las dependencias entre unidades se pueden declarar slo en un interfaz del
mdulo. Ada va ms lejos y define el paquete en dos partes: la especificacin del paque-
te y el cuerpo del paquete. Al contrario que Object Pascal, Ada permite que la conexin
entre mdulos se declaren independientemente en la especificacin y en el cuerpo de un
paquete.
92 Estructura de datos

Interfaces adecuados
En la estructuracin de un programa en unidades es beneficioso que existan pocos inter-
faces y que estos sean pequeos. Es conveniente que existan pocos enlaces entre los
diferentes mdulos en que se descompone un programa. El interfaz de un mdulo es la
parte del mdulo (datos, procedimientos, etc.) que es visible fuera del mdulo.
Los interfaces deben ser tambin pequeos (esto es, su tamao debe ser pequeo con
respecto al tamao de los mdulos implicados). De este modo, los mdulos estn aco-
plados dbilmente; se enlazarn por un nmero pequeo de llamadas (Figura 3.3).

Pocos Muchos
interfaces interfaces

Figura 3.3. Interfaces adecuados (pocos-muchos).

Parte
Interfaces visible
grandes

Parte
visible

Interfaces
pequeos

Figura 3.4. Interfaces adecuados (grandes-pequeos).


Abstraccin de datos: tipos abstractos de datos y objetos 93

Interfaces explcitos
La interfaz o parte visible externamente de un mdulo se debe declarar y describir expl-
citamente; el programa debe especificar cules son los datos y procedimientos que un
mdulo trata de exportar y cules deben permanecer ocultos del exterior. La interfaz
debe ser fcilmente legible, tanto para el programador como para el compilador. Es de-
cir, el programador debe comprender cmo funciona el programa y el compilador ha de
poder comprobar si el cdigo que accede al mdulo se ha escrito correctamente.

Ocultacin de la informacin
Todos los mdulos deben seguir el principio de ocultacin de la informacin; cada m-
dulo debe representarse al menos un elemento de diseo (por ejemplo, la estructura de
un registro, un algoritmo, una abstraccin, etc.).
Otro criterio a tener en cuenta es la subdivisin de un sistema en mdulos, es el
principio denominado abierto-cerrado 4, formulado por Meyer. Este principio entiende
que cada mdulo se considerar cerrado (esto es, terminado y, por consiguiente, til o
activo desde dentro de otros mdulos) y, al mismo tiempo, debe ser abierto (esto es,
sometido a cambios y modificaciones). El principio abierto-cerrado debe producirse
sin tener que reescribir todos los mdulos que ya utilizan el mdulo que se est modifi-
cando.
, ',' , " "


. ~., 1, -",;,<: '
----.,-_. - " o _-c
. :,
- __'-_._
-._. . - -'-:'-,:',,'" :.,.

En diseo estructurado, la modularizacin como ya se ha comentado se centra


en el agrupamiento significativo de subprogramas, utilizando el criterio de acoplamiento
y cohesin.
En diseo orientado a objetos, el problema es sutilmente diferente: la tarea consiste
en decidir dnde se empaquetan flsicamente las clases y objetos de la estructura lgica
del diseo, que son claramente diferentes de los subprogramas.

Sobre el principio abierto-cerrado y su implementacin en C++ y Eiffel, se puede consultar la biblio-


4

grafia de Miguel Katrib. Algunos ttulos destacados sobre orientacin a objetos son: Programacin Orien-
tada a Objetos a travs de C++ y Eiffel. V Escuela Internacional en Temas Selectos de Computacin.
Zacatecas, Mxico, 1994 (esta Escuela est organizada por la UN AM. Mxico); Programacin Orientada a
Objetos en C++. Infosys, Mxico, 1994; Collections and Iterators in Eiffel, Joop, vol. 6, nm. 7, noviem-
bre-diciembre 1993.
94 Estructura de datos

3.4.
- .
DISENO DE MODULOS

Aunque el diseo modular persigue la divisin de un sistema grande en mdulos ms


pequeos y a la vez manejables, no siempre esta divisin es garanta de un sistema bien
organizado. Los mdulos deben disearse con los criterios de acoplamiento y cohesin.
El primer criterio exige independencia de mdulos y el segundo criterio se corresponde
con la idea de que cada mdulo debe realizarse con una sola funcin relacionada con el
problema.
Desde esta perspectiva Booch s define la modularidad como la propiedad de un siste-
ma que ha sido descompuesto en un conjunto de mdulos cohesivos y dbilmente aco-
plados.

3.4.1. Acoplamiento de mdulos

El acoplamiento es una medida del grado de interdependencia entre mdulos, es decir,


el modo en que un mdulo est siendo afectado por la estructura interna de otro mdu-
lo. El grado de acoplamiento se puede utilizar para evaluar la calidad de un diseo de
sistema. El objetivo es minimizar el acoplamiento entre mdulos, es decir, minimizar su
interdependencia, de modo que un mdulo sea afectado 10 menos posible por la estruc-
tura de otro mdulo. El acoplamiento entre mdulos vara en un amplio rango. Por un
lado, el diseo de un sistema puede tener una jerarqua de mdulos totalmente desaco-
plados. Sin embargo, dado que un sistema debe realizar un conjunto de funciones o ta-
reas de un modo organizado, no puede constar de un conjunto de mdulos totalmente
desacoplados. En el otro extremo, se tendr una jerarqua de mdulos estrechamente
acoplados; es decir, hay un alto grado de dependencia entre cada pareja de mdulos del
diseo.
Tal como define Booch, un sistema modular dbilmente acoplado facilita:

l. La sustitucin de un mdulo por otro, de modo que slo unos pocos mdulos
sern afectados por el cambio.
2. El seguimiento de un error y el aislamiento del mdulo defectuoso que produce
ese error.

Existen varias clases de. acoplamiento entre dos mdulos (Tabla 3.1). Examina-
remos los cinco tipos de acoplamiento, desde el menos deseable (esto es, acoplamiento
estrecho o impermeable) al ms deseable (esto es, acoplamiento ms dbil). La fuerza
de acoplamiento entre dos mdulos est influenciada por el tipo de conexin, el tipo de
comunicacin entre ellos y la complejidad global de su interfaz .

5 Booch, Grady: Object-Oriented Design with applications, Benjamin Cummings, 1991, pg. 52.
Abstraccin de datos: tipos abstractos de datos y objetos 95

Tabla 3.1. Clasificacin del acoplamiento del mdulo

l'ipCl d~ aC:j)pJ i t o...


ap~.. ..
. .
. . . .'. .rad. 0. de
G ..'
C)p ro
ac:. 1."pe",..
i


': : . .. G.,.lIo. d,. ptanteDibilid.d
Por contenido Alto (Fuerte) Bajo
Comn
De control
Por sellado (estampado)
Datos
Sin acoplamiento
Bajo (Dbil) Alto

3.4.2. Cohesin de mdulos


La cohesin es una extensin del concepto de ocultamiento de la informacin. Dicho de
otro modo, la cohesin describe la naturaleza de las interacciones dentro de un mdulo
software. Este criterio sugiere que un sistema bien modularizado es aquel en el cual los
interfaces de los mdulos son claros y simples. Un mdulo cohesivo ejecuta una tarea
sencilla de un procedimiento de software y requiere poca interaccin con procedimien-
tos que ejecutan otras partes de un programa. En otras palabras, un mdulo cohesivo
slo hace (idealmente) una cosa.
La cohesin y el acoplamiento se miden como un espectro que muestra las escalas
que siguen los mdulos. La Tabla 3.1 muestra la clasificacin de acoplamientos de m-
dulos y su grado de acoplamiento. La Tabla 3.2 muestra los grados de cohesin: baja
cohesin (no deseable) y alta cohesin (deseable), as como los diferentes tipos de cohe-
.,
SlOn.
Idealmente se buscan mdulos altamente cohesivos y dbilmente acoplados.

Tabla 3.2. Clasificacin de cohesin de mdulos


, :. :.:.:.: . .. " .. . . :.
,
. . .

.... G...dode mantenimiento


l'ipC)$ de cohesin.
..... :::: ":.: ,. :.;".:<::.::: .... :.. ::. ... ". ."... . .":.: ..... :.::. :. :...
.: .. .
.. Gra"
. dec:o'hesin '

Por coincidencia Bajo Bajo


Lgica
Temporal
Por procedimientos
,
Por comUnIcaCIOnes
Secuencial
Funcional
Informacional . Alto Alto
96 Estructura de datos

3.5. TIPOS DE DATOS

Todos los lenguajes de programacin soportan algn tipo de dato. Por ejemplo, el len-
guaje de programacin convencional Pascal soporta tipos base tales como enteros, rea-
les y caracteres, as como tipos compuestos tales como arrays (vectores y matrices) y
registros. Los tipos abstractos de datos extienden la funcin de un tipo de datos; ocul-
tan la implementacin de las operaciones definidas por el usuario asociadas con el
tipo de datos. Esta capacidad de ocultar la infonnacin permite el desarrollo de compo-
nentesde software reutilizables y extensibles.

Un tipo de dato es ",n conjunto de va/ores, y un conjunto de operaciones definidas


por esos valores.

Un valor depende de su representacin y de la interpretacin de la representacin,


por lo que una definicin informal de un tipo de dato es: Representacin + Operaciones.
Un tipo de dato describe un conjunto de objetos con la misma representacin. Exis-
ten un nmero de operaciones asociadas con cada tipo. Es posible realizar aritmtica
sobre tipos de datos enteros y reales, concat~nar cadenas o recuperar o modificar el va-
lor de un elemento. -
La mayora de los lenguajes tratan las variables y constantes de un programa como
instancias de un tipo de dato. Un tipo de dato proporciona una descripcin de sus ins-
tancias que indican al compilador cosas como cunta memoria se debe asignar para una
instancia, cmo interpretar los datos en memoria y qu operaciones son permisibles so-
bre esos datos. Por ejemplo, cuando se escribe una declaracin tal como f 1 oa t z en C
o C++, se est declarando una instancia denominada z del tipo de dato f loa t. El
tipo de datos float indica al compilador que reserve, por ejemplo, 32 bits de memo-
ria, y qu operaciones tales como sumar y multiplicar estn permitidas, mientras
que operaciones tales como el el resto (mdulo) y desplazamiento de bits no lo son.
Sin embargo, no se necesita escribir la declaracin del tipo float el autor de compila-
dor lo hizo por nosotros y se construyen en el compilador . Los tipos de datos que se
construyen en un compilador de este modo, se conocen como tipos de datos fundamen-
tales (predefinidos), y por ejemplo en C y C++ son entre otros: int, char y float.
Cada lenguaje de programacin incorpora una coleccin de tipos de datos funda-
mentales, que incluyen normalmente enteros, reales, carcter, etc. Los lenguajes de pro-
gramacin soportan tambin un nmero de constructores de tipos incorporados que per-
miten generar tipos ms complejos. Por ejemplo, Pascal soporta registros y arrays.
En lenguajes convencionales tales como C, Pascal, etc., las operaciones sobre un
tipo de dato son composiciones de constructores de tipo y operaciones de tipos bases.
-,-.--',--'
-- ,-,.,
-- -"."

Operaciones .:=:. Operacioqes constructor + Operaciones base . .


,-,

Algunos tipos de constructores incluyen registros, arrays, listas, conjuntos, etc.


Abstraccin de datos: tipos abstractos de datos y objetos 97

3.6. ABSTRACCiN EN LENGUAJES DE PROGRAMACiN

Los lenguajes de programacin son las herramientas mediante las cuales los diseadores
de lenguajes pueden implementar los modelos abstractos. La abstraccin ofrecida por
los lenguajes de programacin se puede dividir en dos categoras: abstraccin de datos
(perteneciente a los datos) y abstraccin de control (perteneciente a las estructuras de
control).
Desde comienzos del decenio de los sesenta, en que se desarrollaron los prime-
ros lenguajes de programacin de alto nivel, ha sido posible utilizar las abstracciones
ms primitivas de ambas categoras (variables, tipos de datos, procedimientos, control
de bucles, etc.). Ambas categoras de abstracciones han producido una gran cantidad de
lenguajes de programacin no siempre bien definidos.

3.6.1, . Abstracciones de control

Los microprocesadores ofrecen directamente slo dos mecanismos para controlar el flu-
jo y ejecucin de las instrucciones: secuencia y salto. Los primeros lenguajes de progra-
macin de alto nivel introdujeron las estructuras de control: sentencias de bifurcacin
( i f) y bucles (for, while, do-l oop, etc.).
Las estructuras de control describen el orden en que se ejecutan las sentencias o
grupos de sentencia (unidades de programa). Las unidades de programa se utilizan como
bloques bsicos de la clsica descomposicin descendente. En todos los casos, los
subprogramas constituyen una herramienta potente de abstraccin ya que durante su
implementacin, el programador describe en detalle cmo funcionan los subprogramas.
Cuando el subprograma se llama, basta con conocer lo que hace y no cmo 10 hace. De
este modo, los subprogramas se convierten en cajas negras que amplan el lenguaje de
programacin a utilizar. En general, los subprogramas son los mecanismos ms amplia-
mente utilizados para reutilizar cdigo, a travs de colecciones de subprogramas en bi-
bliotecas.

Las abstracciones y estructuras de control se clasifican en estructuras de control a


nivel de sentencia y a nivel de unidades. Las abstracciones de control a nivel de unidad
se conoce como abstraccin procedimental.

Abstraccin procedimental (por procedimientos)

Es esencial para disear software modular y fiable. La abstraccin procedimental se


basa en la utilizacin de procedimientos o funciones sin preocuparse de cmo se imple-
mentan. Esto es posible slo si conocemos qu hace el procedimiento; esto es; conoce-
mos la sintaxis y semntica que utiliza el procedimiento o funcin. El nico mecanismo
en Pascal estndar para establecer abstraccin procedimental es el subprograma (proce-
dimientos y funciones). La abstraccin aparece en los subprogramas debido a las si-
guientes causas:
98 Estructura de datos

Con el nombre de los subprogramas, un programador puede asignar una des-


cripcin abstracta que captura el significado global del subprograma. Utili-
zando el nombre en lugar de escribir el cdigo permite al programador aplicar la
accin en tIlninos de su descripcin de alto nivel en lugar de sus detalles de bajo
nivel.
Los subprogramas en Pascal proporcionan ocultacin de la informacin. Las va-
riables locales y cualquier otra definicin local se encapsulan en el subprograma,
ocultndolos realmente de forma que no se pueden utilizar fuera del subprogra-
ma. Por consiguiente, el programador no tiene que preocuparse sobre las defini-
ciones locales; sin embargo, pueden utilizarse los componentes sin conocer nada
sobre sus detalles.
Los parmetros de los subprogramas, junto con la ocultacin de la informacin
anterior, permiten crear subprogramas que constituyen entidades de software pro-
pias. Los detalles locales de la implementacin pueden estar ocultos mientras que
los parmetros se pueden utilizar para establecer el interfaz pblico.

Otros mecanismos de abstraccin de control


La evolucin de los lenguajes de programacin ha permitido la aparicin de otros meca-
nismos para la abstraccin de control, tales como manejo de excepciones, corrutinas,
unidades concurrentes, plantillas (<<templates). Estas construcciones son soportadas por
los lenguajes de programacin basados y orientados a objetos, tales como Modula-2,

Ada, C++, Smalltalk o Eiffel.

3.6.2. Abstraccin de datos


Los primeros pasos hacia la abstraccin de datos se crearon con lenguajes tales como
FORTRAN, COBOL Y ALGOL 60, con la introduccin de tipos de variables diferentes,
que manipulan enteros, nmeros reales, caracteres, valores lgicos, etc. Sin embargo,
estos tipos de datos no podan ser modificados y no siempre se ajustaban al tipo de uno
para el que se necesitaban. Por ejemplo, el tratamiento de cadenas es una deficiencia en
FORTRAN, mientras que la precisin y fiabilidad para clculos matemticos es muy
alta.
La siguiente generacin de lenguajes, incluyendo Pascal, SIMULA-67 y AL-
GOL 68, ofreci una amplia seleccin de tipos de datos y permiti al programador mo-
dificar y ampliar los tipos de datos existentes mediante construcciones especficas (por
ejemplo, arrays y registros). Adems, SIMULA-67 fue el primer lenguaje que mezcl
datos y procedimientos mediante la construccin de clases, que eventualmente se con-
virti en la base del desarrollo de programacin orientada a objetos.
La abstraccin de datos es la tcnica de programacin que permite inventar o definir
nuevos tipos de datos (tipos de datos definidos por el usuario) adecuados a la aplicacin
que se desea realizar. La abstraccin de datos es una tcnica muy potente que permite
disear programas ms cortos, legibles y flexibles. La esencia de la abstraccin es simi-
Abstraccin de datos: tipos abstractos de datos y objetos 99

lar a la utilizacin de un tipo de dato, cuyo uso se realiza sin tener en cuenta cmo est
representado o implementado.
Los tipos de datos son abstracciones y el proceso de construir nuevos tipos se llaman
abstracciones de datos. Los nuevos tipos de datos definidos por el usuario se llaman
tipos abstractos de datos.
El concepto de tipo, tal como se defini en Pascal y ALGOL 68, ha constituido un
hito importante hacia la realizacin de un lenguaje capaz de soportar programacin es-
tructurada. Sin embargo, estos lenguajes no soportan totalmente una metodologa. La
abstraccin de datos til para este propsito, no slo clasifica objetos de acuerdo a su
estructura de representacin; sino que se clasifican de acuerdo al comportamiento espe-
rado. Tal comportamiento es expresable en trminos de operaciones que son significati-

vas sobre esos datos, y las operaciones son el nico medio para crear, modificar y acce-
der a los objetos.
En trminos ms precisos, Ghezzi indica que un tipo de dato definible por el usuario
se denomina tipo abstracto de dato (TAD) si:

Existe una construccin del lenguaje que le permite asociar la representacin de


los datos con las operaciones que lo manipulan.
La representacin del nuevo tipo de dato est oculta de las unidades de programa
que lo utilizan [Ghezzi 87].

Las clases en SIMULA slo cumplan la primera de las dos condiciones, mientras
que otros lenguajes actuales cumplen las dos condiciones: Ada, Modula-2 y C++.
Los tipos abstractos de datos proporcionan un mecanismo adicional mediante el cual
se realiza una separacin clara entre la interfaz y la implementacin del tipo de dato. La
implementacin de un tipo abstracto de dato consta de:

l. La representacin: eleccin de las estructuras de datos.


2. Las operaciones: eleccin de los algoritmos.

La interfaz del tipo abstracto de dato se asocia con las operaciones y datos visibles al
exterior del TAD.

3.7. TIPOS ABSTRACTOS DE DATOS (TAO)

Algunos lenguajes de programacin tienen caractersticas que nos permiten ampliar el


lenguaje aadiendo sus propios tipos de datos. Un tipo de dato definido por el programa-
dor se denomina tipo abstracto de datos (TAD) para diferenciarlo del tipo fundamental
(predefinido) de datos. Por ejemplo, en Turbo Borland Pascal un tipo Punto, que repre-
senta a las coordenadas x e y de un sistema de coordenadas rectangulares, no existe. Sin
embargo, es posible implementar el tipo abstracto de datos, considerando los valores
que se almacenan en las variables y qu operaciones estn disponibles para manipular
estas variables. En esencia un tipo abstracto de datos es un tipo de datos que consta de
100 Estructura de datos

datos (estructuras de datos propias) y operaciones que se pueden realizar sobre esos
datos. Un TAD se compone de estructuras de datos y los procedimientos o funciones
que manipulan esas estructuras de datos.

TAD = Representacin (datos) + Operaciones (funciones y procedimientos)

Las operaciones desde un enfoque orientado a objetos se suelen denominar mtodos.


La estructura de un tipo abstracto de dato (clase), desde un punto de vista global, se
compone del interfaz y de la implementacin (Figura 3.5).
Las estructuras de datos reales elegidas para almacenar la representacin de un tipo
abstracto de datos son invisibles a los usuarios o clientes. Los algoritmos utilizados para
implementar cada una de las operaciones de los TAO estn encapsuladas dentro de los
propios TAO. La caracterstica de ocultamiento de la informacin del TAO significa que
los objetos tienen interfaces pblicos. Sin embargo, las representaciones e implementa-
ciones de esos interfaces son privados.

Mtodo 1 Mtodo 1

Mtodo 3 Mtodo 3
...

Interfaz pblico

Representacin:
estructura de datos
(variables de instancia)

Implementacin de mtodos:

Cdigo del mtodo 1


Cdigo del mtodo 2
Cdigo del mtodo 3
Cdigo del mtodo 4
...

Implementacin privada

Figura 3.5. Estructura de un tipo abstracto de datos (TAO).


Abstraccin de datos: tipos abstractos de datos y objetos 101

3.7.1. Ventajas de los tipos abstractos de datos


Un tipo abstracto de datos es un modelo (estructura) con un nmero de operaciones que
afectan a ese modelo. Es similar a la definicin que daremos en el captulo siguiente de
objeto y, de hecho, estn unidos ntimamente. Los tipos abstractos de datos proporcio-
nan numerosos beneficios al programador, que se pueden resumir en los siguientes:

l. Permite una mejor conceptualizacin y modelado del mundo real. Mejora la re-
presentacin y la comprensibilidad. Clarifica los objetos basados en estructuras
y comportamientos comunes.
2. Mejora la robustez del sistema. Si hay caractersticas subyacentes en los lengua-
jes permiten la especificacin del tipo de cada variable, los tipos abstractos
de datos permiten la comprobacin de tipos para evitar errores de tipo en tiem-
po de ejecucin.
3. Mejora el rendimiento (prestaciones). Para sistemas tipeados, el conocimiento
de los objetos permite la optimizacin de tiempo de compilacin.
4. Separa la implementacin de la especificacin. Permite la modificacin y mejo-
ra de la implementacin sin afectar al interfaz pblico del tipo abstracto de dato.
5. Permite la extensibilidad del sistema. Los componentes de software reutiliza-
bles son ms fciles de crear y mantener.
6. Recoge mejor la semntica del tipo. Los tipos abstractos de datos agrupan o
localizan las operaciones y la representacin de atributos.

3.7.2. Implementacin de los TAO


Los lenguajes convencionales, tales como Pascal, permiten la definicin de nuevos tipos
y la declaracin de procedimientos y funciones para realizar operaciones sobre objetos
de los tipos. Sin embargo, tales lenguajes no permiten que los datos y las operaciones
asociadas sean declaradas juntos como una unidad y con un solo nombre. En los lengua-
jes en el que los mdulos (TAD) se pueden implementar como una unidad, stos reciben
nombres distintos:

Turbo Borland Pascal unidad, objeto


Modula-2 mdulo
Ada paquete
C++ clase
Java clase

En estos lenguajes se definen la especificacin del TAD, que declara las operaciones
y los datos ocultos al exterior, y la implementacin, que muestra el cdigo fuente de las
operaciones y que permanece oculto al exterior del mdulo.
Las ventajas de los TAD se pueden manifestar en toda su potencia, debido a que las
dos partes de los mdulos (especificacin e implementacin) se pueden compilar por
separado mediante la tcnica de compilacin separada (<<separate compilation).
102 Estructura de datos

3.8. TIPOS ABSTRACTOS DE DATOS EN TURBO BORLAND


PASCAL

Una pila es una de las estructuras de datos ms utilizadas en el mundo de la compila-


cin. Una pila es un tipo de dato clsico utilizado frecuentemente para introducir al
concepto de tipo abstracto de datos; es una lista lineal de elementos en la que los ele-
mentos se aaden o se quitan por un solo extremo de la lista.
,
La pila almacena elemen-
tos del mismo tipo y actan sobre ella las operaciones clsicas de Meter y Sacar elemen-
tos en dicha pila, teniendo presente la estructura lgica LIFO (ltimo en entrar, primero
en salir).
En Turbo Borland Pascal, los TAD se implementan mediante estructuras tipo uni-
dad. Recordemos que una unidad es una biblioteca de func.iones y procedimientos que
pueden ser utilizados por cualquier programa con la condicin de incluir el nombre de la
unidad en la clusula uses de su sintaxis.

unit <nombre unidad > ;


interface
<c lausula uses >
<co nstantes, tipos y variables publicas >
<cabecer as de procedimientos y funciones publicas>
implementation
<clausula uses >
<co nstante s , tipos y variables privadas >
<proced imientos / funciones privadas y cu erpos de
procedimientos / f u n c i o nes publicas>
begin
<se cuencia de sen t e n c ias para inicializacion >
end.

Pila

Estructura de datos
Almacena una serie de elementos del tipo elemento. La pila est inicialmente vaca y los elementos
se meten o sacan en la pila por el mismo extremo.
Operaciones (Procedimientos que actan sobre la estructura de datos).
Meter
Sacar
Crear
Destruir
Pilavacia Sacar Meter

Cim a

- , -
Fondo vi C\. CA ,.

Figura 3.6. Estructura de datos Pila.


Abstraccin de datos: tipos abstractos de datos y objetos 103

La implementacin de una pila con capacidad para 1.000 elementos del tipo en-
tero es:

unit Pila;
interface .
const
MaxPila = 1000;
type

TipoElemento = int eger;

ListaElementos = array (l .. MaxPilal of TipoElemento;
tipo = record
Elems : ListaElementos; ,
Cima: integer;
end;

procedure Crear (var S:tipo);


(* S s e inic ializa y se limpia o vaca * )

procedure Destruir (var S:tipo);


(* Se libera memoria asignada a S * )
(* S no est inicializada *)
.
procedure Meter (var S:tipo; Item: t ipo El eme nt o);
(* Se aade u n elemento a la cima de la pila *)

procedure Sacar (var S:tipo;var Item:tipoElemento);


(*quitar un elemento de la pila *)

function PilaVacia (S:tipo) :boole~n;


(*devuelve true si S es vaca; false en caso contra rio *)

implementation

procedure Crear (var S:tipo);


begin
S.Cima := O;
end;

procedure Destruir (var S:tipo);


begin
(*no ha c e nada *)
end;

procedure Meter ( var S:tipo; Item:TipoElemento);


begin

S.Cima := S.Cima + 1;
S .Elems(S.Cimal := Item;
end;
.
procedure Sacar (var S:tipo; var Item:TipoElemento);
begin
Item := S.Elems(S.Cimal;
S.Cima := S.Cima-l
end;
104 Estructura de datos

function p il aVacia (S :ti po) :boo l ea n;


begin
PilaVa cia : = ( S . Cima =O) ;
end;
end.

Una vez que se ha implementado el tipo de dato p i 1 a , ste puede ser utilizado en
cualquier programa con tal de invocar en la clusula uses a dicho tipo de dato P il a .

3.8.1. Aplicacin del tipo abstracto de dato pila


El siguiente programa lee una secuencia de enteros, uno por lnea, tales como stos:

100
4567
- 20
25 0

y genera la misma secuencia de nmeros en orden inverso (los saca de la pila).

250
-20
4567

10 0

Esta tarea se consigue metiendo nmeros en la pila y a continuacin vaciando dicha


pila.

program Numer o s ;
uses
Pi l a ;
var
S : Pila .Ti po ;

procedure LeeryA lmacenar Num e ros( var Num Pi la : Pil a.T ip o } ;


var
Aux : p il a.TipoE l emento ;
begin
while not eof do
begin
readln (Aux) ;
Pi l a . Meter(NumPi l a , Aux} ;
end;
end;

procedure VerN um eros( var Nu mP i l a : p il a.T i po} ;


var
Aux : pi la.Ti po Eleme nto;
begin
while not P i l a . Pil avacia(NumP il a} do
Abstraccin de datos: tipos abstractos de datos y objetos 105

begin
Pi l a . Sacar( Nu mP i l a . Au x ) ;
Wr i te Ln( Aux ) ;
end; ( * whi le *)
end; ( * Ve rN umer os * )

begin (* pro gram a pr inc ipal * )


Pil a . Cre ar(S)
LeeryAl mace nar Num e r os( S ) ;
Ve rNum er os(S) ;
Pil a . Des tr u i r (S) ;
end. (* fi n de p r inci p a l * )

Al igual que se ha definido el tipo pi 1 a con estructuras estticas tipo array, se


poda haber realizado con estructuras dinmicas tales como listas enlazadas. De igual
modo se pueden implementar otros tipos de datos abstractos tales como, por ejemplo, las
colas que se utilizan en muchas aplicaciones: sistemas operativos, sistemas de comuni-
caciones, etc.

3.9. ORIENTACiN A OBJETOS


La orientacin a objetos puede describirse como el conjunto de disciplinas (ingeniera)
que desarrollan y modelan software que facilitan la construccin de sistemas complejos
a partir de componentes.
El atractivo intuitivo de la orientacin a objetos es que proporciona conceptos y he-
rramientas con las cuales se modela y representa el mundo real tan fielmente como sea
posible. Las ventajas de la orientacin a objetos son muchas en programacin y modela-
cin de datos. Como apuntaban Ledbetter y Cox (1985):

La programacin orientada a objetos pellnite una representacin ms directa del modelo


de mundo real en el cdigo. El resultado es que la transformacin radical nOllnal de los
requisitos del sistema (definido en tllninos de usuario) a la especificacin del sistema
(definido en trminos de computador) se reduce considerablemente.

La Figura 3.7 ilustra el problema. Utilizando tcnicas convencionales, el cdigo ge-


nerado para un problema de mundo real consta de una primera codificacin del proble-
ma y a continuacin la transformacin del problema en trminos de un lenguaje de com-
putador Von Newmann. Las disciplinas y tcnicas orientadas a objetos manipulan la
transformacin automticamente, de modo que el volumen de cdigo que codifica el
problema y la transformacin se minimiza. De hecho, cuando se compara con estilos de
programacin convencionales (procedimentales por procedimientos), las reducciones
de cdigo van desde un 40 por 100 hasta un orden de magnitud elevado cuando se adop-
ta un estilo de programacin orientado a objetos.
Los conceptos y herramientas orientadas a objetos son tecnologas que permiten que
los problemas del mundo real sean expresados de modo fcil y natural. Las tcnicas
orientadas a objetos proporcionan mejoras metodolgicas para construir sistemas de soft-
ware complejos a partir de unidades de software modularizado y reutilizable .

106 Estructura de datos

Problema del
mundo real

Transformacin de Von Newman

Programa

Codificacin del programa

Figura 3.7. Construccin de software.

Se necesita un nuevo enfoque para construir software en la actualidad. Este nuevo


enfoque debe ser capaz de manipular, tanto sistemas grandes como pequeos, y debe
crear sistemas fiables que sean flexibles, mantenibles y capaces de evolucionar, para
cumplir las necesidades de cambio.
La tecnologa orieritada a objetos puede cubrir estos cambios y algunos otros ms en
el futuro. La orientacin a objetos trata de cumplir las necesidades de los usuarios fina-
les, as como las propias de los desarrolladores de productos software.
Estas tareas se realizan mediante la modelizacin del mundo real. El soporte funda-
mental es el modelo objeto. Los cuatro elementos (propiedades) ms importantes de este
modelo 6 son:

Abstraccin.
Encapsulacin.

Modularidad .
Jerarqua.

Como sugiere Booch, si alguno de estos elementos no existe, se dice que el modelo
no es orientado a objetos.

6 Booch, Grady: Object-Oriented Ana/ysis and Design with App/ications, Benjamin/Cummings,


1994.
Abstraccin de datos: tipos abstractos de datos y objetos 107

3.9.1. Abstraccin
La abstraccin es uno de los medios ms importante mediante el cual nos enfrentamos
con la complejidad inherente al software. La abstraccin es la propiedad que permite
representar las caractersticas esenciales de un objeto, sin preocuparse de las restantes
caractersticas (no esenciales).
Una abstraccin se centra en la vista externa de un objeto, de modo que sirva para
separar el comportamiento esencial de un objeto, de su implementacin. Definir una
abstraccin significa describir una entidad del mundo real, no importa lo compleja que
pueda ser, y a continuacin utilizar esta descripcin en un programa.
El elemento clave de la programacin orientada a objetos es la clase. Una clase se
puede definir como una descripcin abstracta de un grupo de objetos, cada uno de los
cuales se diferencia por su estado especfico y por la posibilidad de realizar una serie de
operaciones. Por ejemplo, una pluma estilogrfica es un objeto que tiene un estado (lle-
na de tinta o vaca) y sobre la cual se pueden realizar algunas operaciones (por ejemplo,
escribir, poner/quitar el capuchn, llenar de tinta si est vaca).
La idea de escribir programas definiendo una serie de abstracciones no es nueva,
pero el uso de clases para gestionar dichas abstracciones en lenguajes de programacin
ha facilitado considerablemente su aplicacin.

3.9.2. Encapsulacin
.
La encapsulacin o encapsulamiento es la propiedad que permite asegurar que el conte-
nido de la informacin de un objeto est oculta al mundo exterior: el objeto A no conoce
lo que hace el objeto B, y viceversa. La encapsulacin (tambin se conoce como oculta-
cin de la informacin), en esencia, es el proceso de ocultar todos los secretos de un
objeto que no contribuyen a sus caractersticas esenciales.
La encapsulacin permite la divisin de un programa en mdulos. Estos mdulos se
implementan mediante clases, de forma que una clase representa la encapsulacin de
una abstraccin. En la prctica, esto significa que cada clase debe tener dos partes: un
interfaz y una implementacin. La interfaz de una clase captura slo su vista externa y la
implementacin contiene la representacin de la abstraccin, as como los mecanismos
que realizan el comportamiento deseado.


3.9.3. Modularidad
La modularidad es la propiedad que permite subdividir una aplicacin en partes ms
pequeas (llamadas mdulos), cada una las cuales debe ser tan independiente como sea
posible de la aplicacin en s y de las restantes partes.
La modularizacin, como
indica Liskov, consiste en dividir un programa

en mdulos
que se pueden compilar por separado, pero que tienen conexiones con otros mdulos. Al
igual que la encapsulacin, los lenguajes soportan la modularidad de diversas formas.
Por ejemplo, en C++ los mdulos son archivos compilados por separado. La prctica
usual es situar las interfaces de los mdulos en archivos con nombres con extensin .h
108 Estructura de datos

(archivos de cabecera) y las implementaciones de los mdulos se sitan en archivos con


nombres con extensin . cpp.
En Ada, el mdulo se define como paquete (package). Un paquete tiene dos partes:
la especificacin del paquete y el cuerpo del paquete, tambin se pueden compilar por
separado.
La modularidad es la propiedad de un sistema que permite su descomposicin en un
conjunto de mdulos cohesivos y dbilmente acoplados .

3.9.4. Jerarqua

La jerarqua es una propiedad que permite una ordenacin de las abstracciones. Las dos
jerarquas ms importantes de un sistema complejo son: estructura de clases [jerarqua
es-un (is-a): generalizacin/especializacin] y estructura de objetos [jerarqua par-
te-de (part-o.!): agregacin].

,
No.sedebe
,-'.- ' .. ,' -- "" .c..

. . azul.no .
atrlbut6df .. . .
_.
... ,----
,-- -

Las jerarquas de generalizacin/especializacin se conocen como herencia. Bsica-


mente, la herencia define una relacin entre clases, en donde una clase comparte la es-
tructura o comportamiento definido en una o ms clases (herencia simple y herencia
mltiple, respectivamente).
La agregacin es el concepto que permite el agrupamiento fisieo de estructuras rela-
cionadas lgicamente. As, un camin se compone de ruedas, motor, sistema de transmi-
sin y chasis; en consecuencia, camin es una agregacin y ruedas, motor, transmisin y
chasis son agregados de camin.

3.9.5. Polimorfismo
La quinta propiedad significativa de los lenguajes de programacin orientados a objetos
es el polimorfismo. Esta propiedad no suele ser considerada como fundamental en los
diferentes modelos de objetos propuestos, pero dada su importancia, no tiene sentido
considerar un objeto modelo que no soporte esta propiedad.
Polimorfismo es la propiedad, que indica, literalmente, la posibilidad de que una
entidad tome muchas formas. En trminos prcticos, el polimorfismo permite referirse
a objetos de clases diferentes mediante el mismo elemento de programa y realizar
la misma operacin de diferentes formas, segn sea el objeto que se referencia en ese
momento.
Por ejemplo, cuando se qescribe la clase mamferos, se puede observar que la opera-
cin comer es una operacin fundamental en la vida de los mamferos, de modo que
cada tipo de mamfero debe poder realizar la operacin o funcin comer. Por otra parte,
una vaca o una cabra que pastan en un campo, un nio que se come un bombn o cara-
Abstraccin de datos: tipos abstractos de datos y objetos 109

me lo y un len que devora a otro animal, son diferentes formas que utilizan los distintos
mamferos, para realizar la misma funcin (comer).
El polimorfismo implica la posibilidad de tomar un objeto de un tipo (mamfero, por
ejemplo) e indicarle que ejecute comer; esta accin se ejecutar de diferente forma se-
gn sea el objeto mamfero sobre el que se aplica.
Clases, herencia y polimorfismo son aspectos claves en la programacin orientada a
objetos y se reconocen a estos elementos como esenciales en la orientacin a objetos. El
polimorfismo adquiere su mxima expresin en la derivacin o extensin de clases; es
decir, cuando se obtiene una clase a partir de una clase ya existente, mediante la propie-
dad de derivacin de clases o herencia. As, por ejemplo, si se dispone de una figura que
represente figuras genricas, se puede enviar cualquier mensaje tanto a un tipo derivado
(elipse, crculo, cuadrado, etc.) como al tipo base. Por ejemplo, una clase figura , pueden
aceptar los mensajes dibujar, borrar y mover. Cualquier tipo derivado de una figura es
un tipo de figura y puede recibir el mismo mensaje. Cuando se enva un mensaje, por
ejemplo dibujar, esta tarea ser distinta segn que la clase sea un tringulo, un cuadrado
o una elipse. Esta propiedad es el polimorfismo, que permite que una misma funcin se
comporte de diferente forma segn sea la clase sobre la que se aplica. La funcin dibujar
se aplica igualmente a un crculo, un cuadrado o un tringulo y el objeto ejecutar el
cdigo apropiado dependiendo del tipo especfico.
El polimorfismo requiere ligadura tarda o postergada (tambin llamada dinmica),
y esto slo se puede producir en lenguajes de programacin orientados a objetos. Los
lenguajes no orientados a objetos soportan ligadura temprana o anterior; esto significa
que el compilador genera una llamada a un nombre especfico de funcin y el enlazador
(linker) resuelve la llamada a la direccin absoluta del cdigo que se ha de ejecutar. En
POO, el programa no puede determinar la direccin del cdigo hasta el momento de la
ejecucin; para resolver este concepto, los lenguajes orientados a objetos utilizan el con-
cepto de ligadura tarda. Cuando se enva un mensaje a un objeto, el cdigo que se
llama no se determina hasta el momento de la ejecucin. El compilador asegura que la
funcin existe y realiza verificacin de tipos de los argumentos y del valor de retomo,
pero no conoce el cdigo exacto a ejecutar.
Para realizar la ligadura tarda, el compilador inserta un segmento especial de cdigo
en lugar de la llamada absoluta. Este cdigo calcula la direccin del cuerpo de la funcin
para ejecutar en tiempo de ejecucin utilizando informacin almacenada en el propio
objeto. Por consiguiente, cada objeto se puede comportar de modo diferente de acuerdo
al contenido de ese puntero. Cuando se enva un mensaje a un objeto, ste realmente
sabe qu ha de hacer con ese mensaje.

3.9.6. Otras propiedades


El modelo objeto ideal no slo tiene las propiedades anteriollllente citadas al principio
del apartado, sino que es conveniente soporte, adems, estas otras propiedades:

Concurrencia (multitarea).
Persistencia.
110 Estructura de datos

Genericidad.
Manejo de excepciones.

Muchos lenguajes soportan todas estas propiedades y otros slo algunas de ellas.
As, por ejemplo, Ada soporta concurrencia y Ada y C++ soportan genericidad y manejo
de excepciones. La persistencia o propiedad de que las variables y por extensin, a los
objetos existan entre las invocaciones de un programa, es posiblemente la propiedad
menos implantada en los LPOO, aunque ya es posible considerar la persistencia en len-
guaje tales como Smalltalk y C+, lo que facilitar el advenimiento de las bases de datos
orientadas a objetos como as est sucediendo en esta segunda mitad de la dcada de los
noventa.

3.10. REUTILIZACiN DE SOFTWARE

Cuando se construye un automvil, un edificio o un dispositivo electrnico, se ensam-


blan una serie de piezas independientes de modo que estos componentes se reutilizan en
vez de fabricarlos cada vez que se necesita construir un automvil o un edificio. En la
construccin de software, esta pregunta es continua: Por qu no se utilizan programas
ya construidos para formar programas ms grandes? Es decir, si en electrnica, los com-
putadores y sus perifricos se fonuan esencialmente con el ensamblado de circuitos in-
tegrados, existe algn mtodo que permite realizar grandes programas a partir de la
utilizacin de otros programas ya realizados? Es posible reutilizar estos componentes
de software?
Las tcnicas orientadas u objetos proporcionan un mecanismo para construir compo-
nentes de software reutilizables que posteriormente puedan ser interconectados entre s
y formar grandes proyectos de software 7.
En los sistemas de programacin tradicionales y en particular en los basados en
lenguajes de programacin estructurados (tales como FORTRAN, C, etc.) exis-
ten las bibliotecas de funciones, que contienen funciones (o procedimientos, segn
el lenguaje) que pueden ser incorporados en diferentes programas. En sistemas orien-
tados a objetos se pueden construir componentes de software reutilizables, al estilo
de las bibliotecas de funciones, normalmente denominados bibliotecas de software o
paquetes de software reutilizables. Ejemplos de componentes reutilizables comer-
cialmente disponibles son: Turbo Visin de Turbo Borland Pascal, OLE 2.0 de C++,
jerarqua de clases Smalltalk, clases MacApp para desarrollo de interfaces grficos
de usuario en Object Pascal, disponibles en Apple, la coleccin de clases de Objec-
tive-C, etc.

7 Brad COX, en su ya clsico libro Object-Oriented Programming An Evolutionary Approach [Cox,


Novobilski, 91] , acu el tllllino chip de software (Software-IC), o componentes de software, para definir
las clases de objetos como componentes de software reutilizables. Existe versin en espaol de Addison-
Wesley/Daz de Santos, 1993, con el ttulo Programacin orientada a objetos. Un enfoque evolutivo.


Abstraccin de datos: tipos abstractos de datos y objetos 111

En el futuro inmediato, los ingenieros de software dispondrn de catlogos de pa-


quetes de software reutilizable, al igual que sucede con los catlogos de circuitos inte-
grados electrnicos como les ocurre a los ingenieros de hardware.
Las tcnicas orientadas a objetos ofrecen una alternativa de escribir el mismo pro-
grama una y otra vez. El programador orientado a objetos modifica una funcionalidad
del programa sustituyendo elementos antiguos u objetos por nuevos objetos, o bien co-
nectando simplemente nuevos objetos en la aplicacin.
La reutilizacin de cdigo en programacin tradicional se puede realizar copiando y
editando mientras que en programacin orientada a objetos se puede reutilizar el cdigo,
creando automticamente una subclase y anulando alguno de sus mtodos.
Muchos lenguajes orientados a objetos fomentan la reutilizacin mediante el uso de
bibliotecas robustas de clases preconstruidas, as como otras herramientas como hojea-
dores o navegadores (<<browser), para localizar clases de inters y depuradores interac-
tivos para ayudar al programador.

3.11. LENGUAJES DE PROGRAMACiN ORIENTADOS


A OBJETOS

El primer lenguaje de programacin que introdujo el concepto de clase fue Simula-67,


como entidad que contena datos y las operaciones que manipulaban los datos. Asimis-
mo, introdujo tambin el concepto de herencia.
El siguiente lenguaje orientado a objetos, y seguramente el ms popular desde un
enfoque conceptual exclusivamente de objetos, es Smalltalk, cuya primera versin co-
mercial se desarroll en 1976, y en 1980 se populariz con la aparicin de Smalltalk-80.
Posteriormente, se ha popularizado gracias al desarrollo de SmalltalklV de la casa Digi-
tal, que recientemente se ha implementado bajo entorno Windows. El lenguaje se carac-
teriza por soportar todas las propiedades fundamentales de la orientacin a objetos, den-
tro de un entorno integrado de desarrollo, con interfaz interactivo de usuario basado en

menus.
Entre los lenguajes orientados a objetos que se han desarrollado a partir de los
ochenta, destacan extensiones de lenguajes tradicionales tales como C++ y Objective-C
(extensiones de C), Modula-2 y Object Pascal (extensin de Pascal) y reciente-
mente Object Cobol, que a lo largo de 1994 han aparecido sus primeras versiones co-
merciales.
Otro lenguaje orientado a objetos puros es Eiffel, creado por Bertrand Meyer y que
soporta todas las propiedades fundamentales de objetos. Hasta ahora no ha adquirido
popularidad ms que en ambientes universitarios y de investigacin. Sin embargo, la
aparicin en el ao 1995 de la versin 3, que corre bajo Windows, seguramente aumen-
tar su difusin.

I
Ada ha sido, tambin, un lenguaje en este caso basado en objetos que soporta la

mayora de las propiedades orientadas a objetos. Sin embargo, la nueva versin Ada-95
ya soporta herencia y polimorfismo.

112 Estructura de datos

Algol

Simula

Pascal Smalltalk C BASIC


CLU

~ 4
Object Pascal

Ada Objective-C C++ Visual BASIC 3


Actor

Ada-9S Visual BASIC 4


Borland Pascal

. Java
Delphi

Figura 3.8. Evolucin de los lenguajes orientados a objetos.

En los ltimos aos han aparecido lenguajes con soporte de objetos que cada vez se
estn popularizando ms: Clipper 5.2 (ya en claro desuso), Visual BASIC, etc.
De cualquier forma, existe un rE)' actual en los lenguajes orientados a objetos: C++.
La normalizacin por ANSI y AT &T de la versin 3.0 y las numerosas versiones de
diferentes fabricantes, tales como Borland C++ 4.0/4.5/5, Turbo C++ 3.0/3.1 y 4.5, Vi-
sual C++ 4.114.2/5, Symantec 6.0/7.0, etc., hacen que en la segunda mitad de los noven-
ta, c++ ser el lenguaje orientado a objetos ms popular y utilizado en el mundo de la
programacin. A C++ se le ha unido recientemente Java, un lenguaje evolucin de C++,
creado especficamente para programar en Internet pero que puede ser utilizado tambin
en aplicaciones de propsito general.
La evolucin de los lenguajes orientados a objetos se muestra en la Figura 3.8, en
la que se aprecia el tronco comn a todos los lenguajes modernos Algol y las tres
lneas fundamentales: enfoque en Pascal (Ada, Object Pascal), enfoque puro de orien-
tacin a objetos (Simula/Smalltalk) y enfoque en e (Objective-C, C++, Java y Ada-95).

3.11.1. Clasificacin de los lenguajes orientados a objetos


Existen varias clasificaciones de lenguajes de programacin orientados a objetos, aten-
diendo a criterios de construccin o caractersticas especficas de los mismos. Una clasi-
ficacin ampliamente aceptada y difundida es la dada por Wegner y que se ilustra en la
Figura 3.10 8.

8 Wegner, Peter [1987]: Dimensions ofObject-Based Languajes Design. Nmero especial de SIGPLAN
Notices, 1987.


Abstraccin de datos: tipos abstractos de datos y objetos 113

FORTRAN I
1957 ALGOL 58
FORTRAN 11 COMTRAN
1958
1959 LlSP LGOL60 COBOL
1960 LlSP
1961

1962 BASIC // CPL
1963
1964 SIMULA I
1965
1966 ALGOL-W
1967 SIMULA 67 ALGOL I

1968
1969
Pascal B
1970
1971 Prolog
1972
1973
1974
1975
1976
1977 FORTRAN 77

1978
1979
Smalltalk 80
1980
1981

1982
1983
1984
1985
1986
1987
1988 Common
Object-P LlSP
1989
Oberon ANSIC++
1990
1991
Ada-90
Modula-3
Quick
90
EiHel
Basic
1992
1993 Prolog++

1994 Object-COBOl
Visual BASle
1995 (00 COBOL)
Ada-9S - - - _;-______
Delphi

Java

Figura 3.9. Genealoga de los lenguajes de objetos segn Sebesta 9.

9Esta tecnologa ha sido extrada y modificada ligeramente con lenguajes de los noventa de Robert
W. Sebesta: Concepts o/ Programming Languages , Addison-Wesley, 2." ed., 1993.
114 Estructura de datos

Basados
en objetos

Basados
en clases
+herencia

Orientados
a objetos

Figura 3.10. Clasificacin de lenguajes 00 de Wegner.

La clasificacin de Wegner divide los lenguajes en tres categoras:

l. Lenguajes basados en objetos que soportan objetos. Es decir, disponen de com-


ponentes caracterizados por un conjunto de operaciones (comportamiento) y un
estado.
2. Lenguajes basados en clases que implican objetos y clases. Es decir, disponen
de componentes tipo clase con operaciones y estado comn. Una clase de un
objeto se construye con una interfaz que especifica las operaciones posibles y
un cuerpo que implementa dichas operaciones.
3. Lenguajes orientados a objetos que adems de objetos y clases ofrecen meca-
nismos de herencia entre clases. Esto es, la posibilidad de derivar operaciones y
atributos de una clase (superclase) a sus subclases.

La definicin anterior, pese a su antigedad sigue teniendo vigencia. Existen otras


clasificaciones similares, pero con la inclusin de la propiedad de polimorfismo en la
categora 3, como requisito para ser lenguaje orientado a objetos.
De cualquier forma, hoy da es posible ampliar esa clasificacin de acuerdo a crite-
rios puramente tcnicos y hacer una nueva clasificacin de la categora 3:

3.1. Lenguajes orientados a objetos puros. Soportan en su totalidad el paradigma


de orientacin a objetos:
Smalltalk Eiffel Simula
Abstraccin de datos: tipos abstractos de datos y objetos 115

3.2. Lenguajes orientados a objetos hbridos. Soportan en su totalidad el paradig-


ma de orientacin a objetos sobre un ncleo de lenguaje hbrido:

C++ (extensin de C: Borland C++, Microsoft C++, Turbo C++, Visual C++,
Symantec, Watcom ... ).
Objective-C (extensin de C).
Object COBOL (extensin de COBOL).
Object Pascal (extensin de Pascal: Turbo Borland Pascal).
Visual Object (extensin de Clipper).
Delphi (extensin de Turbo Borland Pascal 7.0).
Java (extensin mejorada de C++).
Ada-95 (extensin de Ada-83).

De cualquier forma, Meyer, creador del lenguaje Eiffel, proporciona unos criterios
para considerar la bondad 10 de un lenguaje orientado a objetos, cuyos complementos
configuran, de hecho, una nueva clasificacin. En este sentido, los criterios recogidos en
[Meyer 88] son los siguientes:

1. La modularizacin de los sistemas ha de realizarse mediante estructuras de da-


tos apropiadas.
2. Los objetos se describen como la implementacin de tipos abstractos de datos.
3. La memoria se gestiona (administra) automticamente.
4. Existe una correspondencia entre tipos de datos no elementales y clases.
5. Las clases se pueden definir como extensiones o restricciones de otras clases ya
existentes mediante herencia.
6. Soportan polimorfismo y ligadura dinmica.
7. Existe herencia mltiple y repetida.

De acuerdo con los criterios de Meyer recogemos en la Tabla 3.3 el cumplimiento de


dichos criterios en los lenguajes 00 y basados en objetos ms populares.

Tabla 3.3. Criterios de Meyer en lenguajes 00 y basados en objetos

1. Modularizacin S S S S S
2. Tipos abstractos de datos S S S S S
3. Gestin automtica de memoria S S En parte S S
4. Slo clases S S En parte S S
5. Herencia No S S S S
6. Polimorfismo (ligadura dinmica) No S S S S
7. Herencia mltiple y repetida No No S S No

10 Meyer, Bertrand: Object Oriented Software Construction, Englewood Cliffs NJ, Prentice-Hall, 1988.


I
116 Estructura de datos

3.12. DESARROLLO TRADICIONAL FRENTE A DESARROLLO


ORIENTADO A OBJETOS

El sistema tradicional del desarrollo del software para un determinado sistema, es la


subdivisin del mismo en mdulos, a la cual deben aplicarse criterios especficos de
descomposicin, los cuales se incluyen en metodologas de diseo. Estos mdulos se
refieren a la fase de construccin de un programa, que en el modelo clsico sigue a la
definicin de los requisitos (fase de anlisis).
El modelo clsico del ciclo de vida del software no es el nico modelo posible,
dado que es posible desarrollar cdigo de un modo evolutivo, por refinamiento y proto-
tipos sucesivos. Existen numerosos lenguajes de programacin y metodologas que se
han desarrollado en paralelo a los mismos, aunque, normalmente, con independencia
de ellos.
En esta seccin nos centraremos en la metodologa ms utilizada denominada desa-
rrollo estructurado, que se apoya esencialmente en el diseo descendente y en la pro-
gramacin estructurada.
La programacin estructurada es un estilo disciplinado de programacin que se si-
gue en los lenguajes procedimentales (por procedimientos) tales como FORTRAN, BA-
SIC, COBOL, C y C++.
Las metodologas diseo descendente (o descomposicin funcional) se centran en
operaciones y tienden a descuidar la importancia de las estructuras de datos. Se basan
en la clebre ecuacin de Wirth:

Datos + Algoritmos = Programas

La idea clave del diseo descendente es romper un programa grande en tareas ms


pequeas, ms manejables. Si una de estas tareas es demasiado grande, se divide en
tareas ms pequeas. Se contina con este proceso hasta que el programa se comparti-
mentaliza en mdulos ms pequeos y que se programan fcilmente. Los subprogramas
facilitan el enfoque estructurado, y en el caso de lenguajes como C, estas unidades de
programas, llamadas funciones, representan las citadas tareas o mdulos individuales.
Las tcnicas de programacin estructuradas reflejan, en esencia, un modo de resolver un
programa en trminos de las acciones que realiza.
Para comprender mejor las relaciones entre los algoritmos (funciones) y los datos,
consideremos una comparacin con el lenguaje natural (por ejemplo Espaolo Ingls),
que se compone de muchos elementos, pero que reflejar poca expresividad si slo se
utilizan nombres y verbos. Una metodologa que se basa slo en datos o slo en proce-
dimientos es similar a un lenguaje (idnea) en el que slo se utilizan nombres o verbos.
Slo enlazando nombres o verbos correctos (siguiendo las reglas semnticas), las expre-
siones tomarn formas inteligibles y su proceso ser ms fcil.
Las metodologas tradicionales se vuelven poco prcticas cuando han de aplicarse a
proyectos de gran tamao. El diseo orientado a objetos se apoya en lenguajes orienta-
dos a objetos, que se sustentan fundamentalmente en los tipos de datos y operaciones
Abstraccin de datos: tipos abstractos de datos y objetos 117

que se pueden realizar sobre los tipos de datos. Los datos no fluyen abiertamente en un
sistema, como ocurre en las tcnicas estructuradas, sino que estn protegidos de modifi-
caciones accidentales. En programacin orientada a objetos, los mensajes (en vez
de los datos) se mueven por el sistema. En lugar del enfoque funcional (invocar una
funcin con unos datos), en un lenguaje orientado a objetos, se enva un mensaje a un
objeto.
De acuerdo con Meyer, el diseo orientado a objetos es el mtodo que con-
duce a arquitecturas de software basadas en objetos que cada sistema o subsistema
evala.
Recordemos, qu son los objetos? Un objeto es una entidad cuyo comportamiento
se caracteriza por las acciones que realiza. Con ms precisin, un objeto se define como
una entidad caracterizada por un estado; su comportamiento se define por las operacio-
nes que puede realizar; es una instancia de una clase; se identifica por un nombre; tiene
una visibilidad limitada para otros objetos; se define el objeto mediante su especifica-
cin y su implementacin.
Una definicin muy elaborada se debe a Meyer: Diseo orientado a objetos, es la
construccin de sistemas de software como colecciones estructuradas de implementa-
ciones de tipos de datos abstractos.
La construccin de un sistema se suele realizar mediante el ensamblado ascen-
dente (abajo-arriba) de clases preexistentes. Las clases de un sistema pueden tener entre
s relaciones de uso (cliente), relaciones de derivacin (herencia) o relaciones de agre-
gacin (composicin) o, incluso, slo relaciones de asociacin. As, por ejemplo, con
una relacin de cliente, una clase puede utilizar los objetos de otra clase; con una rela-
cin de herencia, una clase puede heredar o derivar sus propiedades definidas en otra
clase.
El hardware se ensambla a partir de componentes electrnicos, tales como circuitos
integrados (chips), que se pueden utilizar repetidamente para disear y construir conjun-
tos mucho ms grandes, que son totalmente reutilizables. La calidad de cada nivel de
diseo se asegura mediante componentes del sistema que han sido probados previamen-
te a su utilizacin. El ensamblado de componentes electrnicos se garantiza mediante
interfaces adecuados.
Estos conceptos se aplican tambin con tecnologas de objetos. Las clases (tipos de
objetos) son como los chips de hardware, Cox les llam chips de software, que no slo
se pueden enlazar (ensamblar) entre s, sino que tambin se pueden reutilizar (volver a
utilizar). Las clases se agruparn, normalmente, en bibliotecas de clases, que son com-
ponentes reutilizables, fcilmente legibles.
En la actualidad, existen gran cantidad de software convencional, en su mayora es-
crito normalmente para resolver problemas especficos; por esta razn, a veces es ms
fcil escribir nuevos sistemas que convertir los existentes.
Los objetos al reflejar entidades del mundo real permiten desarrollar aplicaciones
creando nuevas clases y ensamblndolas con otras ya existentes. Normalmente, los de-
sarrolladores experimentados gastan un porcentaje alto de su tiempo (20 al 40 por 100)
en crear nuevas clases y el tiempo restante en ensamblar componentes probados de siste-
mas, construyendo sistemas potentes y fiables.
118 Estructura de datos

3.13. BENEFICIOS DE LAS TECNOLOGAS DE OBJETOS


Una pregunta que hoy da se hacen muchos informticos es: Cul es la razn para
introducir mtodos de ro en los procesos de desarrollo? La principal razn, sin lugar a
dudas, son los beneficios de dichas TO: aumento de la fiabilidad y productividad del
desarrollador. La fiabilidad se puede mejorar debido a que cada objeto es simplemente
una caja negra con respecto a objetos externos con los que debe comunicarse. Las
estructuras de datos internos y mtodos se pueden refinar sin afectar a otras partes de un
sistema (Figura 3.11).
Los sistemas tradicionales, por otra parte, presentan, con frecuencia, efectos latera-
les no deseados. Las tecnologas de objetos ayudan a los desarrolladores a tratar la com-
plejidad en el desarrollo del sistema.
La productividad del desarrollador se puede mejorar debido a que las clases de obje-
tos se pueden hacer reutilizables de modo que en cada subclase o instancia de un objeto
se puede utilizar el mismo cdigo de programa para la clase. Por otra parte, esta produc-
tividad tambin aumenta debido a que existe una asociacin ms natural entre objetos
del sistema y objetos del mundo real.

Objeto

Mtodos

Datos

Figura 3.11. El objeto como caja negra.

Programa Programa

Datos

Figura 3.12. Proceso tradicional de datos.


Abstraccin de datos: tipos abstractos de datos y objetos 119

Taylor" considera que los beneficios del modelado y desarrollo de objetos son:

l. Desarrollo ms rpido.
2. Calidad ms alta.
3. Mantenimiento ms fcil.
4. Coste reducido.
5. Incremento en escalabilidad.
6. Mejores estructuras de informacin.
7. Incremento de adaptabilidad.

Sin embargo, Taylor '2 tambin considera algunos inconvenientes, aunque algunos de
ellos ya han sido superados o al menos reducido su impacto.

l. Inmadurez de la tecnologa (hoy da ya no se puede considerar as).


2. Necesidades de estndares (el grupo OMG es una realidad).
3. Necesidad de mejores herramientas.
4. Velocidad de ejecucin.
5. Disponibilidad de personal cualificado.
6. Coste de conversin.
7. Soporte para modularidad a gran escala.

La Figura 3.13 muestra los beneficios genricos de las tecnologas de objetos.

Reutilizacin. Las clases se construyen a partir de otras clases.


Sistemas ms fiables.
Proceso de desarrollo ms rpido.
Desarrollo ms flexible.
Modelos que reflejan mejor la realidad.
Mejor independencia e interoperatividad de la tecnologa.
Mejor informtica distribuida y cliente-servidor.
Bibliotecas de clases comerciales disponibles.
Mejor relacin con los clientes .
Mejora la calidad del producto software terminado.

Figura 3.13. Beneficios de las tecnologas de objetos.

11 Taylor, David A. : Object-Ori ented Technology Reading, MA: Addison-Wesley , 1992, pgi-
nas 103-107.
12 [bd., pgs. 108-113.
120 Estructura de datos

RESUMEN

Este captulo examina el concepto fundamental de la orientacin a objetos, el tipo abstracto de


datos. Los tipos abstractos de datos (TAD) describen un conjunto de objetos con la misma repre-
sentacin y comportamiento. Los tipos abstractos de datos representan una separacin clara entre
la interfaz externa de un tipo de datos y su implementacin interna. La implementacin de un tipo
abstracto de datos est oculta. Por consiguiente, se pueden utilizar implementaciones alternativas
para el mismo tipo abstracto de dato sin cambiar su interfaz.
En la mayora de los lenguajes de programacin orientados a objetos, los tipos abstractos de
datos se implementan mediante clases (unidades en Pascal, mdulos en Modula-2, paquetes en
Ada).
En este captulo se considera tambin una introduccin a los mtodos de desarrollo orien-
tados a objetos. Se comienza con una breve revisin de los problemas encontrados en el desa-
rrollo tradicional de software, que condujeron a la crisis del software y que se han mantenido
hasta los aos actuales. El nuevo modelo de programacin se apoya esencialmente en el concepto
de objetos.
La orientacin a objetos modela el mundo real de un modo ms fcil a la perspectiva del
usuario que el modelo tradicional. La orientacin a objetos proporciona mejores tcnicas y para-
digmas para construir componentes de software reutilizables y bibliotecas ampliables de mdulos
de software. Esta caracterstica mejora la extensibilidad de los programas desarrollados a travs
de metodologas de orientacin a objetos. Los usuarios finales, programadores de sistemas y de-
sarrolladores de aplicaciones, se benefician de las tecnologas de modelado y programacin orien-
tadas a objetos.
Los conceptos fundamentales de orientacin a objetos son tipos abstractos de datos, herencia
e identidad de los objetos. Un tipo abstracto de datos describe una coleccin con la misma estruc-
tura y comportamiento. Los tipos abstractos de datos extienden la nocin de tipos de datos ocul-
tando la implementacin de operaciones definidas por el usuario (mensajes) asociados con los
tipos de datos. Los tipos abstractos de datos se implementan a travs de clases. Las clases pueden
heredar unas de otras. Mediante la herencia, se pueden construir nuevos mdulos de software
(tales como clases) en la parte superior de una jerarqua existente de mdulos. La herencia permi-
te la comparticin de cdigo (y por consiguiente reutilizacin) entre mdulos de software. La
identidad es la propiedad de un objeto que diferencia cada objeto de los restantes. Con la identi-
dad de un objeto, los objetos pueden contener o referirse a otros objetos. La identidad del objeto
organiza los objetos del espacio del objeto manipulado por un programa orientado a objetos.
Este captulo examina el impacto de las tecnologas orientadas a objetos en lenguajes de pro-
gramacin, as como los beneficios que producen en el desarrollo de software.
Los conceptos de la programacin orientada a objetos se examinan en el captulo; si no ha
ledo hasta ahora nada sobre tecnologas de objetos, deber examinar con detenimiento todos los
elementos conceptuales del captulo.

EJERCICIOS

3.1. Construir un tipo abstracto lista enlazada de nodos que contienen enteros.
3.2. Disear un tipo abstracto de datos pila de nmeros enteros y que al menos soporte las si-
guientes operaciones:
Abstraccin de datos: tipos abstractos de datos y objetos 121

Borrar: Eliminar todos los nmeros de la pila.


Copiar: Hace una copia de la pila actual.
Meter: Aadir un nuevo elemento en la cima de la pila.
Sacar: Quitar un elemento de la pila.
Longitud: Devuelve un nmero natural igual al nmero de objetos de la pila.
Llena: Devuelve verdadero si la pila est llena (no existe espacio libre en la pila).
Vaca: Devuelve verdadero si la pila est vaca y falso en caso contrario.
Igual: Devuelve verdadero si existen dos pilas que tienen la misma profundidad y las
dos secuencias de nmeros son iguales cuando se comparan elemento a ele-
mento desde sus respectivas cimas de la pila; falso en caso contrario.
3.3. Crear un tipo abstracto Cola que sirva para implementar una estructura de datos cola.
3.4. Crear un TAD para representar:
Un vector (representacin grfica y operaciones).
Una matriz y sus diferentes operaciones.
Un nmero complejo y sus diferentes operaciones.
3.5. Crear un TAD que represente un dato tipo cadena (string) y sus diversas operaciones:
clculo, longitud, buscar posicin de un carcter dado, concatenar cadenas, extraer una sub-
cadena, etc.


PARTE

,
CAPITULO

. , .
structuras e atos lnamlcas:
, un teros
[,'., :", . . '0
" ' ,
, .,- .:.-._;_, .'_ _ _
-- - -- f
_M
J
_ ~ _
, "
1. 'F:i-., '. ,. - -,":.--

CONTENIDO

4.1. Estructuras de datos dinmicas.


4.2. Punteros (apuntadores).
4.3. Operaciones con variables puntero: los procedimientos new y dispose.
4.4. El tipo genrico puntero (pointer).
4.5. La asignacin de memoria en Turbo Pascal.
RESUMEN.
EJERCICIOS.
PROBLEMAS.

Los punteros son el ltimo de los tipos de datos incorporados a Pascal.


Un puntero es un tipo de dato simple que contiene la direccin de una
variable o estructura en vez de un valor de dato. Los punteros tienen
dos propsitos principales: hacer los programas ms eficientes y cons-
truir estructuras muy complejas. En el captulo se examina tambin la
gestin dinmica de memoria y el modo en que se puede manipular. Se
ver cmo utilizar variables dinmicas para construir estructuras de
datos que pueden crecer y disminuir conforme se ejecuta el programa.
Las estructuras de datos dinmicas son una coleccin de elemen-
tos (denominados nodos) que son nodos, en contraste a un array que
siempre contiene almacenamiento para un nmero fijo de elementos.

4.1. ESTRUCTURAS DE DATOS DINMICAS


Todas las variables y estructuras de datos que se han considerado hasta este momento
han sido estticas. Con una variable esttica, la cantidad de memoria (espacio) ocupada
debe ser declarado por anticipado y no puede ser incrementado durante la ejecucin del
programa si se necesitara ms espacio de memoria.

125
126 Estructura de datos

Un array de requisitos es esttico dado que la cantidad exacta de memoria se fija por
la declaracin del tamao del array. Esta falta de flexibilidad puede ser una desventaja
notable. As, por ejemplo, si en un array de registros se declara para un tamao mximo
de 1.000 registros, el programa no funcionar si se deben almacenar ms de 1.000 regis-
tros en ese array. Por otra parte, si el tamao mximo declarado para un array es mucho
mayor que el total de espacio de memoria requerido, el programa utilizar ineficiente-
mente la memoria, dado que la cantidad de memoria especificada en la declaracin se
reservar, incluso aunque slo se utilice una pequea parte.
Los punteros (apuntadores) 1 permiten la creacin de estructuras de datos dinmi-
cas: estructuras de datos que tienen capacidad de variar en tamao y ocupar tanta
memoria como utilicen realmente. Las variables que se crean y se destruyen durante la
ejecucin se llaman variables dinmicas (tambin annimas). As, durante la ejecu-
cin de un programa, puede haber una posicin de memoria especfica asociada con
una variable dinmica y posteriormente puede no existir ninguna posicin de memoria

asociada con ella.


Pascal proporciona los mtodos para asignar y liberar espacio de memoria utilizando
punteros y los procedimientos predefinidos new y dispose.
Al contrario que las estructuras de datos estticas, tales como arrays cuyos tamaos
y posiciones de memoria asociados se fijan en tiempo de compilacin, las estructuras
dinmicas de datos se amplan (expanden) o reducen (contraen) a medida que se requie-
ra durante la ejecucin y cambia sus posiciones de memoria asociada.
Una estructura de datos dinmica es una coleccin de elementos llamados nodos de
la estructura normalmente de tipo registro que se enlazan o encadenan juntos. Este .
enlace se establece asociando con cada nodo un puntero que apunta al nodo siguiente de
la estructura.
Existen diferentes tipos de estructuras dinmicas de datos, siendo las ms notables y
significativas las listas enlazadas, los rboles y los grafos.
Las estructuras de datos dinmicas son tiles especialmente para almacenar y proce-
sar conjuntos de datos cuyos tamaos cambian durante la ejecucin del programa, por
ejemplo, el conjunto de trabajos que se han introducido en una computadora y estn
esperando su ejecucin o el conjunto de nombres de pasajeros y asignacin respectiva
de asientos de un vuelo de avin determinado. En este captulo se estudiarn los punte-
ros y los procedimientos new y dispose, as como el mtodo que se puede utilizar

Siguiente Siguiente Siguiente Siguiente

Datos Datos Datos Datos

Nodo1 Nodo2 Nodo3 Nodo4 ...

Figura 4.1. Representacin de una lista enlazada.

I En Latinoamrica, el trmino utilizado para definir este concepto es apuntador.


Estructuras de datos dinmicas: punteros 127

para construir y procesar estructuras dinmicas de datos, junto con la estructura dinmi-
ca de datos, por excelencia, la lista enlazada.

4.2. PUNTEROS (APUNTADORES)


En una computadora cada posicin de memoria tiene una direccin y un valor especfico
almacenado en esa posicin. Se han utilizado nombres de variables en lugar de direccio-
nes porque los nombres son ms fciles de recordar. Para almacenar un nuevo valor en
memoria se asigna a una variable, y la computadora enva una direccin a la memoria
seguida por el valor a almacenar en esa posicin.
El tipo puntero es un tipo de datos simple en Pascal; es simple debido a que no se
puede romper en otros componentes pequeos como es el caso de un array o un registro.
Los punteros en esencia son un tipo especial de variable (esttica) que se utiliza para
almacenar la direccin de memoria de otra variable, o 10 que es igual, su valor es una
direccin de una posicin de memoria donde est almacenada otra variable. Las varia-
bles utilizadas para almacenar direcciones en vez de valores convencionales se denomi-
nan variables puntero o simplemente puntero (apuntador).

1747 (direccin) 2014 (direccin)

2014 (valor) 2587 (valor)


un puntero una var dinmica


p pl\

Al definir un tipo puntero se debe indicar el tipo de valores que se almacenarn en


las posiciones designadas por los punteros. La razn es que los diferentes tipos de datos
requieren diferentes cantidades de memoria para almacenar sus constantes, una variable
puntero puede contener una direccin de una posicin de memoria adecuada slo para
un tipo dado. Por esta razn se dice que un puntero apunta a una variable particular, es
decir, a otra posicin de memoria.
, ,.,..

.. .. .. .. conti~~ela
...

Una
--~-~",----- .. ..
,"," -'"""'

4.2.1. Declaracin de punteros


Un puntero es una variable que se utiliza para almacenar la direccin de otra variable.
Sin embargo, el puntero en s no es normalmente lo que le interesa ms; sino que el
inters reside en la celda (direccin de memoria) apuntada por l. Es decir, es preciso
diferenciar entre las dos entidades implicadas en el apuntamiento: la variable puntero
(quin hace el apuntamiento) y la variable apuntada (a quin se apunta).
128 Estructura de datos

Un tipo de dato puntero se especifica utilizando el smbolo de circunflejo (") seguido


por un identificador de tipo. Su formato es:
Ai dent if icador- t i po

Se puede declarar un puntero a una variable carcter, un puntero a un array de ente-


ros, un puntero a un registro o un puntero a cualquier otro tipo. En general, se pueden
declarar variables puntero que apunten a cualquier tipo de dato, incluso otros punteros.
La declaracin de una variable a un puntero se realiza con el formato siguiente:

var
Nombre-var i able : Aidentific ad or -tip o

var
Ptr: ATip oElement o

La variable Ptr apunta a un tipo de dato TipoElemento

EJEMPLO 4.1
var
P : Al n teger;

Los punteros se pueden representar mediante diagramas grficos:

Por ejemplo, la variable P contiene 0591 64 que es la direccin de memoria donde est
la variable entera apuntada 345.

059164 345

P est en la variable entera en la


direccin 034405 direccin 059164 pA

Un puntero apunta hacia (a) otra variable cuando contiene la direccin de esa va-
riable.
Estructuras de datos dinmicas: punteros 129

variable entera a la que


apunta el puntero P

... 345

Es muy til crear un identificador de tipo para los tipos de datos puntero. Se puede crear
dicho identificador y utilizar ese identificador para crear variables punteros .
,'JO - _. .-. ,. .:
.'. - ' ''-''"':
' - " .,_
..
. ,.
tyPe .... .

..-.' .
nbmbr e :" tipo: Aidentificdor-t i po ;,
,"var . .---_ . ,
. -..
. n oinbre-v?r-pt:r : nombf:e-'tipo; ' ",> ", ;

EJEMPLO 4.2

Supongamos que se desean almacenar nmeros reales utilizando aplicacin de memo-


ria dinmica. Las variables A y B son variables punteros que apuntan a datos reales.

type real
Pu n t er o Real = AR e a l;
A
var
A, B : Punte r oRea l ; B

1. type
--- ."
real

Tipo_Pu n tero = Ai n teger ;


var
P: Tipo_Pun t ero ;

2. var
P : Al nteg e r;

3. type cad4 0 = s tr ing [ 40 1; declara tres variables puntero:


var ptr : Aca d40 ; p t r apunta a valores cadena
ql , q2: Ar ea l; ql, q2 apuntan a valores reales
4. type
Punt e r oRe a l = ARe a l ; puntero a reales
var
P: Pun teroReal ; Pes una variable puntero de tipo
R : Real; Punter o Real
type
PunteroEn t = Ai nt ege r ;
130 Estructura de datos

5. var
Pr imero : ~ Rea l;
S i g o Pun tero En t ;

4.3. OPERACIONES CON VARIABLES PUNTERO:


LOS PROCEDIMIENTOS NEW Y DISPOSE

Los punteros se crean con las declaraciones citadas:

type
Punter o Rea l = ~ Rea l ;
var
P : Pun t eroRea l ;

P es una variable puntero de tipo PunteroReal que apunta a posiciones que contie-
nen reales. La posicin de memoria designada por el valor de la variable puntero P se
representa por v'. La Figura 4.2 representa la relacin entre P y P".
Como P" designa una posicin de memoria, se puede utilizar como cualquier otra
variable Pascal. Se pueden asignar valores a P " y utilizar valores de P " en expresiones
tal como cualquier otra variable. Si P apunta a posiciones que contienen reales, P " es
una variable real. As, en la Figura 4.2 el valor de P " es 3.500.
Sin embargo, estas operaciones no se pueden realizar directamente tras la declaracin,
debido a que el objeto o direccin apuntada p A no tiene existencia. Antes de que un
programa utilice un puntero, se requiere primero espacio para el tipo de datos objeto de
la direccin del puntero. En otras palabras, un programa debe inicializar sus punteros
-su declaracin no basta ; para iniciar un puntero se debe utilizar el procedimiento
New.

4.3.1. Procedimiento New


La declaracin de una variable puntero P no crea una celda de memoria para apuntar a
ella. El procedimiento (sentencia) N e w se utiliza para crear tal celda de memoria P; es
decir el procedimiento New crea una nueva variable dinmica y establece que una varia-
ble puntero apunte a ella.

P~ : = 1 000 el valor de p ~ es 1000


P~ : = 3 * P ~ + 500 toma el valor 3500

3500

Figura 4.2. Diferencia entre P y P".


Estructuras de datos dinmicas: punteros 131

Formato

New (P)

p variable puntero

La sentencia N ew ( P ) ; llama al procedimiento N ew que asigna almacenamiento para


un valor del tipo determinado y sita la direccin de esta celda de memoria en la variable
puntero P. Una vez que se asigna almacenamiento para un valor de tipo determinado al
que est apuntando P, se puede almacenar un valor en esa celda de memoria y manipu-
larlo. La posicin exacta de la memoria de esta celda particular es indiferente.
La nueva variable creada es la ya conocida con el smbolo P La llamada a N ew A.

exige que exista suficiente espacio de memoria libre en el montculo la pila de varia-
bles dinmicas (heap) para asignar a la nueva variable. En caso contrario se producir
un error en tiempo de ejecucin.
Se puede representar el valor de una variable puntero por una flecha dirigida a una
celda de memoria. El diagrama

p

?

muestra que la variable puntero P apunta a una celda de memoria cuyo contenido se
desconoce. Esta es la sentencia que existe inmediatamente despus de que se ejecuta
New (P) .
El smbolo P se utiliza para referenciar a la celda de memoria apuntada por la va-
A

riable puntero P. El smbolo (circunflejo) se denomina operador de indireccin o de


A

desreferencia.
La sentencia de asignacin

almacena el valor real 25.0 en la posicin (celda) de memoria apuntada por P.

25.0

Como P A se considera una variable, podr ser visualizado su valor


Wr i t e (PA : 10 : 2 ) ; visualiza el valor 25.0
132 Estructura de datos

Atencin
P:= 25 .0; asignacin no vlida
Write (P : I0 : 2) ; sentencia no vlida

Ambas sentencias son no vlidas debido a que no se puede almacenar un valor de


tipo Real en una variable puntero P, ni se puede visualizar el valor (una direccin)
de una variable puntero.

Funcionamiento de New (P)

..
,e ,--,_:','-_--, , ___ ~ ~:;
-
'i",- ,.~,..~:; -,., . . '<':,-. ,<-.':__ -- __
.;_: _-,: .-,--~-.~ . __.J', . ;', .'-' -::
-
__, --, __ '_, <
-
' ,_'.' ,

l.
,:' ' ,,' < :':' ' '' 1<, ;\ ' f ' i':t "' , , ':' : ' ', ,: . : ' ,,1 ' ,, ' , l . . . ' "

., ' ,f .," , L~direc.cip~ ,~~~ IW~lpj,qp: de memoria ~e;lllpla~eNt . cm~; se crea una luira-
" "'b'l:'='d" ... :."." . .. . ':' . . -::''':' ,:' 1)/'\""""':' "" ",:"':< ..,'::' ',' '_,",- ',' .. . . , ,,I""":f;!- ,.", ';' :, .,. , ... . <

. e . lnanuca J: ,....." ..<,',.:".,-...,',.ij;';>."


<.

,. > ,, ,' ,' ," ." , , .. '" ,' , '


',," , ;' !.'. . '"'..>i: . .?:.';::::',::. ' - , _ , " ' ;, ,- , . " \ '<':"1..', ,' ,':
,,:: _" ,,' '~ "

'r i'.!;.- ;'",:"if: : : ' , \ - " :' - :r'~'n:,',i ' ; ' :~ l~<:;:::' '>,';:"">!: : "- '(-' . ,~.. j"~; :; " ~' , j'-:, "f> , , . ".
.
"r-----.. . . -- :. .::~'1::~"". ". ,
'
"

i, ':!,~':';_
.- ! , ~, ..
,"
.
'- ,
! ,

,
't' - . .'
...
, "
" .. " -_: - ---

P , ."... ,<,
,,.' ,1
-l;: ~ \ .;h.'
. -
"'!'iiw.;......, <.~ ",,",,,-, ' ''',,+__ . -f' ,,-,_."' _ -- , -_ . _------
< -~

EJEMPLO 4.3

A la posicin o celda de memoria a que apunta un puntero se puede acceder situando un


smbolo despus del nombre de la variable puntero. Por ejemplo,
A

new (Ptr) ;
Ptr ~ : = 'M ckenna ';

La sentencia new (pt r) crea una celda de memoria vaca (o con basura) a la que apun-
ta Ptr. La segunda sentencia sita el valor Mckenna en esa celda de memoria. Un I I

diagrama grfico sera:

Ptr

Mc Kenna

Implementacin interna
Internamente, los punteros se implementan teniendo en cuenta las direcciones de memo-
ria a las que se apunta. Por ejemplo, supongamos que la direccin de p tres 1015 Y
que la celda de memoria que crea new (ptr) est en la direccin 1256. Por consigUien-
te, el efecto de

__ _ _ o

- __ o
Estructuras de datos dinmicas: punteros 133

new (ptr) ;
pt rA := ' McK e n na ';

se puede dibujar a nivel de direcciones de memoria, como se muestra a la izquierda,


con el diagrama ms sencillo de la derecha.

Dir ec c i n 10 1 5 Direccin 1256

1 2 56 McK enna Mc Ke nn a

Pt r Ptr

Atencin
Observe que en la declaracin de un puntero, el circunflejo est situado a la izquierda de
su tipo, mientras que en una sentencia en que se accede a la celda de memoria a que se
est apuntando, el circunflejo aparece a la derecha.

LO 4.4
Realizar el seguimiento del segmento de programa.
var
1. P t r1 : Ac ha r;
2. Pt r2 : Ain t eger ;
begin
3. Ne w (Ptr 1) ;
4. P tr l " : = ' B';
5. Ne w (Ptr 2);
6. P t r 2A := 86 ;

LO 4.5
Deducir la salida del siguiente programa.
program Pun te r o ;
type
Ptrin t = Ai nt e ger;
var
l , J : Pt rint ;
N : in t e g er ;
begin
Ne w ( l) ;
N ew (J) ;
N: = 5;
l A .-
. - N ,'
Wri t e Ln ( l A) ;
. - l ',
J .-
J A .. -
- - 7 ,'
Wri teLn
end.
134 Estructura de datos

EJEMPLO 4.6
Qu se imprime tras ejecutar el siguiente programa?

program Prueba S i mp l e ;
var p, q : Ainteger;
x, y : int ege r;
begin
ne w (P );
P A.. _ - 5 ,.
X: ::::: p '" + 1;

Y . -- pA ,.
new (q) ;
qA: = y + 3;
WriteLn (x, " , y, " , pA, " , qA)
end.

Solucin
6 5 5 8

La distribucin grfica es:


P

x 6 5

y 5 8

4.3.2. Variables de puntero con registros


Las variables de puntero pueden contener la direccin de tipos de datos simples o datos
de tipo compuesto. En las estructuras dinmicas de datos es frecuente el uso de registros
como elementos. Se suelen conocer con el nombre de nodos, aunque en realidad el tr-
mino se extiende tanto a datos simples como compuestos. Por su importancia, y aunque
la manipulacin es idntica a la ya estudiada, consideraremos un ejemplo con variables
dinmicas tipo registro.

EJEMPLO 4.7
Cul es la salida de este programa?
program Test ;
type
Estudiante = record
Letr a : char;
Edad: int eger
end;
Estructuras de datos dinmicas: punteros 135

Pu n tEstu = A Estud i a nt e;
var
P I , P2 : PuntEs t u ;
begin
N ew (P 1 ) ;
P l A. Eda d -- l ',
A
P I .L etr a .-
- 'A" ,
WriteLn (PlA.Edad , Pl A. Letra) ;
New (P2) ;
A
P2 .E dad = 2,
P2 A . Letra : = 'B ';
Wr i teLn (P2 A .Edad, P2 A.Letra);
PI := P2 ;
A
P2 .Edad - 3 , -

P2 A . Letra := 'C' ;
Wr it eLn (PlA . Edad, P I A. Letra , P2 A. Edad , P2 A .L etra)
end.

Ejecucin
lA
28
3C3C

4.3.3. Iniciacin y asignacin de punteros


Antes de intentar referirse a valores de variables es preciso, como siempre, inicializar
las variables. Los pasos a dar se muestran en las siguientes sentencias:

var
P : Ain teger;

New (P) ;

. -- 17 ,'

En un puntero (P) se deben considerar dos valores:

P untero (P) Su valor es la posicin (direccin) de una variable integer.


P" El valor de la variable integer propiamente dicho.
P (flecha que apunta a la posicin de una
---".
variable de memoria)
P" (contenido de esa memoria)

El procedimiento new inicializa el puntero con la direccin de una variable integer.


La variable integer, P", a la que P apunta debe tambin ser inicializada (P " : = 1 7 ) .
136 Estructura de datos

Recuerde
Write (P A) sen t enci a vl i da
Wr i te (P) sentenc i a no v l ida (error)

Asignacin
Las variables dinmicas pueden tener ms de un puntero que est apuntando a ellas.
Tambin los punteros pueden ser modificados de modo que apunten a variables dinmi-
cas diferentes en momentos diferentes.
Estos cambios se pueden realizar con el operador de asignacin (:=). Estudiemos las
asignaciones posibles.

(1) p := q (2)

(1) Los punteros p y q apuntan a la misma posicin; por consiguiente, p Y q A A

designan la misma posicin y tienen el mismo valor.


(2) El valor de q A se asigna a p A; despus de la asignacin, p A Y q A tienen el
mismo valor, sin embargo, p Y q permanecen en distintas posiciones de
A A

memona..

\.,,~,~ ~-,-
~; . .'."""
.
::', _-- ' :--i.".

No se .
:,;
.. -, -

diferente . . . . ,'. .
"

, . "
, ,
i:
.' ",:. " " ,.......
" ."
.
" , '"
' .
,- ,

4.8
Pl Y P2 son punteros de tipo entero. Qu se imprimir tras la ejecucin del siguiente
segmento de programa? y cmo ser la distribucin en memoria?
new ( p I ) ;
new ( p 2) ;
P IA := 86 ; No se puede acceder a este valor-----
P2 A := 50 ;
P I:: P 2 ;
Writ e Ln (PIA, " , P2A) ;

Solucin
50 50 PI

86

P2

50
Estructuras de datos dinmicas: punteros 137

4.3.4. Procedimiento oispose


El procedimiento dispose libera la posicin de memoria ocupada por una variable
dinmica.

Formato

dispose (p)

p variable puntero

Dispose destruye la variable referenciada por P y devuelve su zona de memoria a la


pila dinmica (heap). Despus de una llamada a dispose, el valor de P se vuelve indefi-
nido y cualquier intento de referenciar a P/\ producir un error.
En resumen, Dispo se produce las siguientes acciones:

l. La posicin de memoria cuya direccin se almacena en P se libera de la memo-


ria montculo (heap). En otras palabras, P deja de existir.
A

2. P se vuelve indefinido.

La representacin grfica es:


I
p

situacin inicial

?
situacin despus de di spose (p)
p

EJEMPLO 4.9

1. var
p, Q: Ainteger;
begin
2. New ( p) ;
3. pA - 8;
-
4. Q -
- P;
5. QA -- 5;
6. Dispos e ( P)
end
138 Estructura de datos

4.3.5. Constante ni 1
Pascal proporciona una constante predefinida, nil (nulo). La constante nil se utiliza para
dar un valor a una variable puntero que no apunta a ninguna posicin, nil puede ser
asignada a un puntero de cualquier tipo.

p: = nil

Como ni 1 no apunta a ninguna posicin de memoria, una referencia a p " es ilegal


si el valor de p es nil.

p : = ni 1;
p '" : = 5; es ilegal ya que se instruye a la computadora a almacenar 5 en la
posicin apuntada por p, pero debido a la primera sentencia (p: =nil),
p no apunta a ninguna direccin

EJEMPLO 4.10
El segmento de programa

var
p : Ac h a r;
begin
p := nil;
i f p = nil
then
WriteLn ( ' e l punte ro P n o apun ta a n ad a')
else
Wr i t e Ln ( ' P se qu eda i n def in i d o apunta ' ) ;

proporciona la salida

el p unt e r o P no apunta a nada

..
,.- ,. . ,_o
,
.~;

............... ij. JC
.',.- .. -. ~r,i "l"--_

4.3.6. Naturaleza dinmica de los punteros


,
Las variables a las que se apuntan no estn declaradas. Unicamente las variables a las
que se apunta se declaran. As, una sentencia como:
New (P) ;

se puede ejecutar muchas veces dentro de un programa simple; cada vez que se ejecuta,
crea una nueva celda de memoria. En consecuencia no existe lmite declarado para saber
cuntas celdas de memoria se pueden crear utilizando unos pocos punteros.
Estructuras de datos dinmicas: punteros 139

Los arrays se dice que son estticos debido a que la cantidad mxima de espacio de
memoria que se puede utilizar debe ser declarado por anticipado. Los punteros son din-
micos ya que no hay tal lmite previo, el espacio de memoria se crea durante la ejecucin
del programa.

4.3.7. Comparacin de punteros


Los punteros pueden ser comparados slo en expresiones de igualdad. As, en el caso de

var
Pu nt eroA , Pun tero B: Aintege r;

las comparaciones:

if ( PunteroA = Punte r oB)


then < se nten c i a >;
if ( Pu nteroA <> Punt er o B )
then < se nt e n cia > ;

No se puede comparar la ordenacin de punteros con los operadores de relacin


<, >, <= y >=.
No existe ningn problema para comparar los objetos direccionados por los punte-
ros. La lnea siguiente es vlida.

if ( Pun teroA A <= Punt ero B A)


then < sentenc i a >

Si dos punteros PI y P2 son del mismo tipo, el efecto de

Pl : = P 2 ;

redirige PIde modo que apunta a la celda de memoria apuntada por P 2. Despus de la
ejecucin de PI: = P2, ambos punteros apuntan a la misma celda.
Se dice que dos punteros son iguales si ambos apuntan precisamente al mismo ele-
mento de datos. En un diagrama ambos apuntan a la misma caja.

Pl

25

P2

Estructuras de datos dinmicas: punteros 141

La traza de memoria es

p p

Carpe Concha
,

q q

Dien Dien

La salida ser

Concha
Concha

4.3.8. Paso de punteros como parmetros


El paso de parmetros es, como conoce el lector, una tcnica poderossima para proce-
sar informacin. El paso de punteros se realiza como cualquier otro tipo de dato, con
la salvedad de que cuando se pasa un puntero como un parmetro, se est pasando el
puntero, no el objeto al que apunta. En el caso de una lista enlazada, el paso de la
cabeza o cabecera de la lista no pasa la lista en s, slo el puntero a su primer ele-
mento.
El caso ms sencillo es cuando se pasa el puntero como un parmetro varo Al igual
que en otros casos similares, todos los cambios realizados a los parmetros formales se
harn tambin al parmetro real. Normalmente se utiliza un parmetro var cuando se
espera que el procedimiento cambie el puntero.
Ms complejo es el caso en el que un puntero se pasa por valor. En este caso, la
computadora hace una copia legal del parmetro real de modo que cualquier cambio
hecho al parmetro formal no se reflejar de nuevo. Por ejemplo, supongamos que en el
procedimiento de escritura VerNumeros (imprime los nmeros almacenados en una
pila) en lugar de utilizar un puntero temporal para moverse a travs de la lista, se utiliza
el propio parmetro.

procedure VerNumeros (Cabeza: PtrLista);


begin
while Cabeza < > nil do
begin
WriteLn (CabezaA.Datos);
Cabeza:= CabezaA.Siguiente;
end;
end;

El procedimiento funciona, pero se destruye la lista cuando se cambia e abe z a?


La respuesta es no ya que el parmetro valor protege el parmetro real del cambio.
142 Estructura de datos

4.4. EL TIPO GENRICO PUNTERO (POINTER)


Turbo Pascal permite un tipo especial de definicin de puntero: genrico o no tipifi-
cado. Difiere del puntero estndar en que no tiene un tipo base, no est definido como
un puntero hacia algn tipo, sino simplemente como una variable de tipo pointer.

EJEMPLO 4.13
var
enlace: pointer;

enlace:= lis; {la variable lis figura en declaraciones precedentes}

La direccin contenida en la variable 1 i s est asignada a la variable en 1 a e e.


Los punteros genricos estn especialmente concebidos para la programacin de bajo
nivel, para la cual Turbo Pascal ofrece buenas posibilidades.

4.5. LA ASIGNACiN DE MEMORIA EN TURBO


BORLAND PASCAL
Turbo Pascal divide la memoria de su computadora en cuatro partes: el segmento de
cdigo, el segmento de datos, el segmento pila (stack) y el segmento montculo o alma-
cenamiento dinmico (heap). Tcnicamente la pila y el montculo no estn totalmente
separados, pero funcionan como entidades separadas.
El segmento de datos est claramente dedicado al almacenamiento de datos, pero en
los otros tres segmentos tambin pueden almacenarse datos. La Figura 4.3 muestra el
mapa de memoria simplificada de Turbo Pascal 7.0. Cada mdulo (que incluye el pro-
grama principal y cada unidad) tiene su propio segmento de cdigo.
El programa principal ocupa el primer segmento de unidades (en orden inverso de
como estn listadas en la clusula uses) y el ltimo segmento de cdigo est ocupado
por la biblioteca en tiempo de ejecucin.
El tamao de un segmento de cdigo no puede exceder de 64 K, pero el tamao total
del cdigo est limitado slo por la memoria disponible. El segmento de datos contiene
todas las constantes con tipo seguidas por todas las variables globales. El tamao del
mento de la pila no puede exceder
, de 64 K (el tamao por defecto es 16 K, que se
pueden modificar con la directiva $M).
El buffer o memoria intermedia de solapamiento (overlay) se utiliza por la unidad
estndar Overlay para almacenar cdigo recubierto. Si el programa no tiene solapamiento,
el tamao de la memoria intermedia del solapamiento es cero.
La Figura 4.4 (modificacin de la 4.3) muestra cmo queda la memoria cuando un
programa arranca, y en ella se observa que todas las variables locales se almacenan en la
pila (stack) y las variables globales (tambin llamadas estticas) se almacenan en el seg-
mento de datos. El cdigo y el segmento de datos estn localizados en la parte baja de
la memoria y la pila (stack) y el almacenamiento dinmico o montculo (heap) ocupan la
zona alta de la memoria.
Estructuras de datos dinmicas: punteros 143

Cima de la memoria DOS

Lista libre (crece hacia abajo)

FreePtr

HeapPtr ~
Montculo (crece hacia arriba)

HeapOrg --I~ .... Ovr HeapEnd


Recubrimiento de Buffer
.... Ovr HeapOrg
Pila (crece hacia abajo)

SSeg:Sptr ~
Pila libre
SSeg:OOOO ~
Variables globales

Constantes con tipos


DSeg:OOOO ~

Segmento de cdigo de la primera unidad

Contenid o de una
imagen de
archiv o .EXE
Segmento de cdigo de la unidad System

Segmento de cdigo de la ltima unidad

Segmento de cdigo del programa principal

Program Segment Prefix (PSP)



PrefixSeg ~
Memoria baja

Figura 4.3. Mapa de memoria de Turbo Pascal 7.0.

El diagrama de la Figura 4.4 muestra tambin que la pila crece hacia abajo en la
memoria y el montculo crece hacia arriba en la memoria. Aunque la pila y el montculo
comparten la misma zona de la memoria, ellas nunca deben solaparse (recubrirse).
La mayora de las variables que se declaran en Turbo Pascal son estticas, su tamao
se fija en tiempo de compilacin y no pueden variar. Por el contrario, el montCulo alma-
cena variables dinmicas.

4.5.1. El montculo (heap) y los punteros


El montculo o heap (pila de variables dinmicas o almacenamiento dinmico) alma-
cena variables dinmicas, esto es, las variables asignadas a travs de los procedimientos
144 Estructura de datos

~ El tamao de la zona
Aqu se almacena el cdigo Comienzo del de cdigo es el total
objeto. programa del tamao del cdigo
principal de programa principal
ms el tamao del
cdigo de todas las
unidades utilizadas
por el programa. El
Cdigo unidad n
tamao total del
cdigo slo est

limitado por la
memoria disponible.
Cdigo unidad 2

Cdigo unidad 1
--------------------~~ Tamao de la zona de
Comienzo de datos (suma de todas
datos las variables globales
Se almacenan variables
del programa principal
globales (estticas)
y todas las unidades
y constantes con tipos.
Fin de datos utilizadas). El mximo
es 65.520 bytes.
----------------------~~

Se almacenan variables de El tamao de la zona


subprograma, parmetros de la pila se establece
pasados y otros valores con las directivas del
auxiliares. Comienzo de la compilador.
pila
---------------------~ La pila crece hacia la
zona baja de la
Se almacenan variables Comienzo del
memoria.
dinmicas creadas por New y montculo
GetMen.
El montculo crece
hacia la zona alta de la
Cima del montculo memoria.

El tamao del
montculo se
establece con las
Espacio del montculo no opciones del
utilizado disponible para compilador. Si la
almacenar variables dinmicas memoria disponible es
adicionales. menor que el lmite
~ bajo del montculo, el
programa no se
cargar.

Figura 4.4. Mapa prctico de memoria de Turbo Pascal 7.0.



Estructuras de datos dinmicas: punteros 145

estndar New y GetMem. El montculo puede crecer o disminuir en el segmento corres-


pondiente, ya que utiliza tipos de datos dinmicos: los punteros, que pueden crear o
liberar variables dinmicas mientras el programa se est ejecutando. En resumen, las
variables puntero pueden utilizar y reutilizar la memoria montculo.
El tamao real del montculo depende de los valores mnimos y mximos que pue-
den fijarse con la directiva del compilador $M. El tamao mnimo es de O bytes, y el
mximo por defecto es de 640 Kb; esto significa que poi defecto el montculo ocupar
toda la memoria restante (640 Kb viene definida por la mxima memoria direccionable
por el DOS, aunque los procesadores 8086/88 tienen diecisis segmentos que por un
valor de 64 K de RAM resultara 1.048.560 bytes = l Megabyte).
El lmite inferior del montculo se almacena en la variable HeapOrg, y el lmite o
cuota superior (lmite inferior de la memoria libre) se almacena en la variable HeapPtr.
Cada vez que una variable dinmica se asigna en el montculo (va Newo GetMen), el
gestor de la pila mueve GetPtr hacia arriba el tamao de la variable.
El uso de las variables puntero en el montculo ofrece dos ventajas principales. Pri-
mero se ampla la cantidad total de espacio de datos disponibles en un programa; el
segmento de datos est limitado a 64 K, pero el montculo, como ya se ha citado, est
limitado slo por la cantidad de RAM en su computadora. La segunda ventaja es penni-
tir que su programa se ejecute con menos memoria. Por ejemplo, un programa puede
tener dos estructuras de datos muy grandes, pero slo una de ellas se utiliza en cada
momento. Si estas estructuras de datos se declaran globalmente, ellas residen en el seg-
mento de datos y ocupan memoria en todo momento. Sin embargo, si estas estructuras
de datos se definen como punteros, se pueden poner en el montculo y quitarse cuando
no se necesiten, reduciendo, por consiguiente, los requisitos de memoria.

4.5.2. Mtodos de asignacin y liberacin de memoria


Los subprogramas que gestionan el montculo o almacenamiento dinmico son:
Asignacin dinmica de memoria Espacio ocupado en memoria
New Dispose MaxAvail
Mark Release MemAvail
Getmem FreeMem

4.5.3. New y Dispose


Cuando Di spose libera o destruye una variable dinmica, puede dejar un agujero en el
montculo. Si hace uso frecuente de New y Dispose, puede llegar a producirse una
acumulacin de espacio de memoria inservible basura (garbage). Algunos sistemas
Pascal proporcionan rutinas especficas para comprimir esa informacin inservible (gar-
bage col/ection), Turbo Pascal no las soporta, pero s utiliza un sistema de gestin de la
memoria montculo muy sofisticada que minimiza la prdida de esos espacios inservi-
bles. Los procedimientos Mark y Re lease proporcionan un mtodo alternativo de
gestin del montculo que eliminan la necesidad de la operacin eliminar basura. Sin
embargo, hay un inconveniente: Dispose no es compatible con Mark y Release.
146 Estructura de datos

4.5.4. Mark y Release


Mark y Release son una alternativa a utilizar New y Dispose para. asignar memo-
ria dinmicamente.
El procedimiento Mark registra la direccin de la parte superior del montculo en
una variable puntero. El procedimiento Release devuelve el montculo a un estado
dado (reestructura la direccin).

Mark (va r pun t) Release (varpunt)

varp un t variable puntero de cualquier tipo puntero


Nota

4.5.5. GetMem y FreeMem


Un tercer mtodo de asignar memoria es GetMem y FreeMem. Se asemejan a New y
Dispose en que asignan o liberan memoria, pero GetMem y FreeMem pueden especi-
ficar cunta memoria se desea asignar con independencia del tipo de variable que est
utilizando. Se pueden asignar bloques de memoria en la pila de una unidad de datos
cuyo tamao no se conoce en tiempo de compilacin.
GetMem crea una nueva variable dinmica del tamao especificado y pone la direc-
cin del bloque en una variable puntero.

Formato

GetMem (va r pu n t, tamao)

varpun t variable puntero de cualquier tipo puntero


tama o expresin de tipo word

FreeMem libera una variable dinmica de un tamao dado.

Formato

FreeMem (varpunt, ta ma o)

Las variables asignadas con GetMem se liberan con FreeMem.


Estructuras de datos dinmicas: punteros 147

EJEMPLO 4.14
GetMem (y, 100);
FreeMem (y, ~OO);

Nota

4.5.6. MemAvail y MaxAvail


El conocimiento de cunta memoria est realmente disponible para variables dinmicas
puede ser crtico. Turbo Pascal lleva un registro de cunta memoria queda en el montcu-
lo, de modo que si se solicita ms de la disponible, se generar un error en tiempo de
ejecucin. La solucin es no crear una variable dinmica que sea mayor que la memoria
disponible en el montculo. Turbo Pascal proporciona dos funciones para medir la me-
moria disponible: MemAvail y MaxAvail.
MaxAvail devuelve el tamao del bloque libre contiguo ms grande del montcu-
lo, correspondiente al tamao de la variable dinmica ms grande que se puede asignar a
la vez. (El valor devuelto es un entero largo.)

Formato

MaxAvail

MemAvail devuelve un valor (del tipo entero largo) que indica, en bytes, la cantidad
total de memoria disponible para variables dinmicas.

Formato

MemAvail

EJEMPLOS 4.15
begin
Writeln (MemAvail, 'bytes disponibles');
Writeln( 'el bloque libre ms grande es:', MaxAvail, 'bytes')
end

Programa
En el archivo Marathon van a almacenarse los datos personales de los participantes del
Marathon Jerez-97.
148 Estructura de datos

Anlisis. Este sencillo problema nos sirve para escribir un ejemplo de utilizacin de
variable puntero y variable apuntada o referenciada. El puntero va a referenciar a un
registro con los campos necesarios para representar los datos personales. Es evidente
que podramos utilizar una variable esttica de tipo registro, pero es un ejemplo.

Codificacin
program Marathon (input, output);
uses crt;
type
registro = record
nombre, apellido : string[25J;
direccin : string[30J;
ciudad : string [20J;
edad : integer;
marca : record
n, m, sg: integer
end;
end;
Ptrreg = Aregistro;
var
R : Ptrreg; F: file of registro;

procedure Datos (var Pr: Ptrreg);


begin
new (Pr);
with PrAdo
begin
write ('Nombre Apellido:'); readln (nombre, apellido);
write( 'Direccion ciudad:') ;readln (direccion, ciudad);
write ('Edad:') ;readln (edad);
write( 'mejor Marca:') ;readln(marca.h,marca.m,marca.sg)
end
end;
begin

assign (F,' carrera. Dat ) ;


rewrite (F);
writeln( 'Escribe los datos de cada participante');
writeln( 'Para acabar proceso:Crtln Z');
while not eof do
begin
Datos (R) ;
write(F,R A)
end
end.

RESUMEN
Un puntero es una variable que se utiliza slo para almacenar la direccin de memoria de otra
variable. Un puntero apunta a otra variable cuando contiene una direccin de la variable.
Pascal tiene mtodos especiales para declaracin, iniciacin y manipulacin de punteros. La
razn principal para utilizar punteros es que ellos hacen posible las estructuras de datos dinmi-
cas, que les permiten crecer, decrecer e incluso desaparecer mientras se estn ejecutando.
152 Estructura de datos

PROBLEMAS
4.1. Escribir las declaraciones necesarias para definir un tipo de datos puntero a un registro de
estudiante con los campos Apellido-I, Apellido-2, Nombre, Fecha-nacimiento y notas. Los
tres primeros campos definirlos de tipo puntero a cadena de 25 caracteres. El campo Fecha
puntero a un registro con los campos da, mes y ao. Y el campo Notas puntero a un array
de 10 elementos.
4.2. Escribir un procedimiento que devuelva los datos correspondientes a un registro de estu-
diante definido en 4.1. En el procedimiento se ha de reservar memoria para cada uno de los
campos del registro.
4.3. Definir un vector de registro del tipo definido en 4.1. Escribir un procedimiento en el que
se d entrada a los registros de los estudiantes de una clase que tiene un mximo de 40
alumnos. Utilizar el procedimiento definido en 4.2.
4.4. Definir un archivo cuyos elementos van a ser los registros definidos en 4. 1, con la salvedad
de que en vez de los campos puntero, los campos sean del tipo apuntado. Escribir un
procedimiento que tome como entrada el vector generado en 4.7 Y escriba los registros en
el archivo.
4.5. Definir de nuevo el registro enunciado en 4.5 para escribir el procedimiento de entrada de
campos del registro con la particularidad de que se reserve memoria con el procedimiento
GetMem. El nmero de bytes a reservar se debe ajustar al tamao real del campo.
4.6. Una ecuacin de segundo grado depende de tres parmetros de tipo real: a, b, c. Escribir un
programa que tenga como datos de entrada los coeficientes de la ecuacin de segundo gra-
do y como salida las races de la ecuacin. Definir los parmetros a, b, c como punte-
ros a nmeros reales de tal forma que en el procedimiento de entrada se reserve memoria
para ellos.
,
CAPITULO


Istas en aza as:

Ista en aza a

CONTE

5.1. Especificacin formal del tipo abstracto de datos lista.


5.2. Implementacin del TAO lista con estructuras dinmicas.
5.3. Implementacin del TAO lista mediante variables dinmicas.
5.4. Iniciar una lista enlazada.
5.5. Bsqueda en listas enlazadas.
5.6. Operaciones de direccin: siguiente, anterior, ltimo.
5.7. Insercin de un elemento en una lista.
5.8. Borrado de un elemento de una lista.
5.9. Recorrido de una lista.
5.10. Lista ordenada.
RESUMEN.
EJERCICIOS.
PROBLEMAS.

Una lista enlazada (o lista) es una secuencia de nodos en el que cada


nodo est enlazado o conectado con el siguiente. La lista enlazada es
una estructura de datos dinmica cuyos nodos suelen ser normalmente
registros y que no tienen un tamao fijo.
En el captulo se desarrollan algoritmos para insertar, buscar y bo-
rrar elementos. De igual modo se muestra el tipo abstracto de datos
(TAD) que representa a las listas enlazadas.

5.1. ESPECIFICACiN FORMAL DEL TIPO ABSTRACTO


DE DATOS LISTA

Una forma de almacenar elementos relacionados es alinearlos, formando una lista lineal
que necesita un enlace por cada elemento, para referenciar al elemento sucesor.

153
154 Estructura de datos

p-
7 15 34 67 nil

Figura 5.1. lista enlazada de nmeros enteros.

En la Figura 5.1 se muestra una lista enlazada de enteros a la que se accede a travs
del puntero P. Una lista es una estructura que se utiliza para almacenar informacin del
mismo tipo, con la caracterstica de que puede contener un nmero indeterminado de
elementos, y que estos elementos mantienen un orden explcito. Este ordenamiento ex-
plcito se manifiesta en que cada elemento contiene en s mismo la direccin del siguien-
te elemento.
Una lista es una secuencia de O a n elementos. A la lista de cero elementos llamare-
mos lista vaca. Cada elemento de una lista se denomina nodo. En un nodo po-
demos considerar que hay dos campos, campo de informacin ( I nfo) y campo de enla-
ce (Enl ac e) o direccin del elemento siguiente.

Info Sgte (Enlace)

Figura 5.2. Nodo de una lista enlazada.

El campo de direccin, a partir del cual se accede a un nodo de la lista, se llama


puntero. A una lista enlazada se accede desde un puntero externo que contiene la direc-
cin (referencia) del primer nodo de la lista. El campo de direccin o enlace del ltimo
elemento de la lista no debe de apuntar a ningn elemento, no debe de tener ninguna
direccin, por lo que contiene un valor especial denominado puntero nulo (ni/).
La lista vaca, aquella que no tiene nodos, tiene el puntero externo de acceso a la
lista apuntando a nulo.

NIL

... -- NIL

p:=nil
Figura 5.3. lista enlazada sin informacin o inicializacin de lista (lista vaca).

Una lista es una estructura de datos dinmica. El nmero de nodos puede variar rpi-
damente en un proceso, aumentando los nodos por inserciones, o bien disminuyendo por
supresin (eliminacin) de nodos.
Las inserciones se pueden realizar por cualquier punto de la lista. As pueden reali-
zarse inserciones por el comienzo de la lista, por el final de la lista, a partir o antes de un
nodo determinado. Las eliminaciones tambin se pueden realizar en cualquier punto de
la lista, aunque generalmente se hacen dando el campo de informacin que se desea
eliminar.
Listas en/azadas: e/ TAO lista en/azada 155

Especificacin formal del TAD lista


Matemticamente, una lista es una secuencia de cero o ms elementos de un determina-
do tipo.

(al, a2, a3, , an) donde n >= O,


si n = O la lista es vaca.

Los elementos de la lista tienen la propiedad de que sus elementos estn ordenados
de forma lineal, segn las posiciones que ocupan en la misma. Se dice que a j precede a
a j +1 para i = 1, 2, 3, 4, 5, ... , n -1 y que a j sucede a ajol para i = 2, 3,
4, 5, 6, ... , n.
Para formar el tipo de datos abstracto Lis t a a partir de la nocin matemtica de
lista, se debe definir un conjunto de operaciones con objetos de tipo Lista. Las opera-

ClOnes:

Listavacia(L) Inicializa la lista.


Esvacia(L) Funcin que determina si la lista es vaca.
Inserprim(X,L) Inserta un nodo con la informacin X como primer nodo de la
lista L.
Inserta(X,P,L) Inserta en la lista L un nodo con el campo X, delante del nodo
de direccin P.
Inserfin(X,L) Inserta un nodo con el campo X como ltimo nodo de la lis-
ta L.
Localiza(X,L) Funcin que devuelve la posicin/direccin donde est el cam-
po de informacin X. Si no est devuelve nulo.
Suprime(X,L) Elimina de la lista el nodo que contiene a X.
Suprimedir(P,L) Elimina de la lista el nodo cuya direccin/posicin viene dada
por P.
Anterior(P,L) Funcin que devuelve la posicin/direccin del nodo ante-
rior a P.
Siguiente(P,L) Funcin que devuelve la posicin/direccin del nodo siguien-
te a P.
Primero(p) Funcin que devuelve la posicin/direccin del primer nodo
de la lista L.
Ultimo (P) Funcin que devuelve la posicin/direccin del ltimo nodo
de la lista L.
Anula(L) Esta operacin vaca la lista L.
Visualiza(L) Esta operacin visualiza el campo de informacin de todos
los elementos de la lista L.

Estas operaciones son consideradas como bsicas en el manejo de listas. En realidad,


la decisin de qu operaciones son las bsicas depende de las caractersticas del proble-
ma que se va a resolver. Tambin depender del tipo de representacin elegido para las
listas, por lo que es posible que puedan aparecer otras operaciones posteriormente.
156 Estructura de datos

Independientemente de la implementacin de las operaciones, se escribe un ejemplo


de manejo de una lista. El objetivo es que dada una lista L, eliminar aquellos nodos
repetidos. El campo de informacin de los nodos puede ser cualquiera (Ti po inf o).
La funcin 1 gua 1 e s devuelve verdadero en el caso de que los dos parmetros de
Ti poi nfo sean iguales.

procedure Elimin adup( var L : Lista);


var
P, Q : Posicion; { P posicin actual en L,
,
1 Q posici n avanzada )

begin
P : = Pr im e r o( L ) ;

while P<> nul o do ,
,

begin
Q := Siguiente (P , L) ; ,
,

while Q < > n u l o do


if Iguales (I nf o(P) , Info(Q)) then
Suprimedir (Q ,L )
el se ,
,

Q:= Sig uiente(Q,L); i


J.
P:= Siguien te( P,L ) :
j
end;
1
end;

Para representar las listas y las correspondientes implementaciones pueden seguirse
dos alternativas:

Utilizacin de la estructura esttica array para almacenar los nodos de la lista.


Utilizacin de estructuras dinmicas, mediante punteros y variables dinmicas.

5.2. IMPLEMENTACiN
, DEL TAO LISTA CON ESTRUCTURAS
ESTATICAS
En la implementacin de una lista mediante arrays, los elementos de sta se guardan en
posiciones contiguas del array. Con esta realizacin se facilita el recorrido de la lista y la
operacin de aadir elementos al final. Sin embargo, la operacin de insertar un elemen-
to en una posicin intermedia de la lista obliga a desplazar en una posicin a todos los
elementos que siguen al nuevo elemento a insertar con objeto de dejar un hueco.
En esta realizacin con estructuras estticas se define el tipo Lis t a como un regis-
tro con dos campos: el primero, es el array de elementos {tendr un mximo nmero de
elementos, pre-establecido}; el segundo, es un entero, que representa la posicin que
ocupa el ltimo elemento de la lista. Las posiciones que ocupan los nodos en la lista son
valores enteros; la posicin i-sima es el entero i.

Declaraciones:
!
!

const ,,


1

Max= 1 00 ;
I
,

-
Listas en/azadas: e/ TAO lista en/azada 157

type
Ti po in fo= {t i po d e l campo i n form a c i n d e c a da nodo}
List a = record
E leme ntos: array [l . . Max] of Tip o info ;
Ultim o: integer
end;
pos icion = O " Max;

El procedimiento Lis t a vac i a ( L) inicializa la lista, para lo cual simplemente se


pone a cero UI timo.

procedure Lis tav ac ialvar L: Lista);


begin
L .Ultim o := O
end;

El procedimiento Inserprim (X, L), que inserta X como primer nodo, debe des-
plazar una posicin a la derecha todos los nodos, para as poder asignar X en la primera
. .,
poslclon.

procedure l nse rprimlX : Tip oinf o ;var L : List a ) ;


var
l: i nte ger ;
begin
with L do
begin
for 1: = Ul t im o downto 2 do
Elemen tos [l+ l] := Elem e n tos[ l];
E le ment o s [1 ] : = X
ult im o : = ultimo + 1
end
end;

El procedimiento 1 n s e r t a ( X P, L) desplaza los elementos de la lista a partir de


I

la posicin P e inserta X en dicha posicin.

procedure lnsertal X: Tipo in fo;P : Posicio n; var L: L i s ta);


var
Q : Posicion;
begin
if L .Ul t im o = Ma x then
< err or : l ista L llena >
else if (P> L.u lt im o) o r IP< 1) then
. " .
< err o r: p oslclon n o eX l ste >
el se beg1n
for Q := L.U lti mo downto P do
{despla za lo s e le ment os a l a dere c ha}
L. Element os [ Q+ 1 ] : = L. Elemen to s [Ql ;
L . Ultimo := L.U lt imo+l ;
L . Elemen t os [ P ] : = X
end
end;
158 Estructura de datos

Para implementar la operacin Supr ime (X, L) , primero hay que encontrar la po-
sicin que ocupa x, a continuacin se elimina.

procedure Suprime(X: Tipoinfo;var L: Lista);


var
l: integer;
P: integer;
begin
P: = Localiza (X, L);
if P> O then
begin
L.Ultimo:= L.Ultimo-l; ,,
for l:= P to L.Ultimo do
{desplaza a la izquierda}
L. Elementos [l] : = L. Elementos [l+ 1] ;
end
end;

Otra forma de escribir el procedimiento Supr ime es aprovechar el procedimiento

Suprimedir:

procedure Suprime(X: Tipoinfo;var L: Lista);


var
P: integer;
begin
P:= Localiza(X,L);
if P> O then
Suprimedir(P,L)
end;

La operacin Supr imedi r ( P , L) , que elimina de la lista el nodo cuya posicin


viene dada por P, tiene que hacer lo opuesto que la operacin Inserta: desplazar a la
izquierda los elementos que se encuentran a partir de la posicin P:

procedure Suprimedir(P: Posicion;var L: Lista);


var
Q: Posicion;
begin
if (P> L.Ultimo) or (P< 1) then
< error: posicin no existe>
else begin .
L.ultimo:= L.Ultimo-l;
for Q:= P to L.Ultimo do
{ desplaza a la izquierda }
L.Elementos [Q]:= L.Elementos [Q+l]
end
end;

La operacin de localizar, Local iza (X, L) devuelve la posicin de un elemento X:

function Localiza (X:Tipoinfo; L:Lista): Posicion;


var
Listas enlazadas: el TAO lista enlazada 159

Q: Pos i e i o n;
Le: bo o l e a n;
begin

Q:= 1;

Le : = fal s e;
while (Q < = L. Ult imo) and not Le do
begin
Le := L .El e ment os [Ql= X
if not Le then Q:= Q+1
end;
if Le then
Loea liza:= Q
else
Loea l i z a := O
end;

5.3. IMPLEMENTACiN DEL TAO LISTA MEDIANTE VARIABLES


DINMICAS

Este mtodo de implementacin de listas enlazadas utiliza variables puntero que permi-
ten crear variables dinmicas, en las cuales se almacena el campo de informacin y el
campo de enlace al siguiente nodo de la lista. Con esta implementacin se ajusta la memo-
ria ocupada al tamao real de la lista, no como ocurre en la realizacin mediante estructuras
estticas en las que es necesario prever un mximo de elementos o nodos. Ahora, cada
vez que sea necesario crear un nuevo nodo se llama al procedimiento que capta la memoria
necesaria de la pila de memoria libre, y se enlaza con la lista. De igual forma cuando sea
necesario eliminar un nodo, la memoria ocupada por ste se devuelve a la pila de memo-
ria libre. El proceso es dinmico, la lista crece o decrece segn las necesidades.
Con esta realizacin se evitan los desplazamientos de elementos a la derecha o a la
izquierda en las operaciones de insercin o eliminacin, respectivamente. Por contra,
cada vez que se quiere acceder a un nodo hay que recorrer la lista, a travs de los enlaces
hasta alcanzar su direccin. Tambin hay que tener en cuenta que en esta realizacin de
listas, cada nodo ocupa la memoria adicional del campo de enlace.
Las variables enteras contienen o pueden contener valores enteros, y sucede igual
con variables reales. El tipo de variables puntero (o apuntadores) son aquellas cuyo con-
tenido va a ser la direccin de memoria de un dato. Las variables puntero, al igual que
las variables enteras o reales, son variables estticas, ya que se crean (se reserva memo-
ria para ellas) en tiempo de compilacin.
Pu nte ro= ATipo ap unt ado ;

Con esta declaracin de tipo estamos expresando que los valores que contenga una
variable de tipo Puntero van a ser direcciones de memoria del tipo Tipoapuntado. Grfi-
camente:
p
160 Estructura de datos

Con los punteros se pueden construir toda clase de estructuras enlazadas. Estas es-
tructuras son dinmicas; es decir, el nmero de elementos puede cambiar durante la
ejecucin del programa. Para lo cual hay procedimientos que permiten crear y destruir
elementos durante la ejecucin del programa, y as se ajustan a las necesidades de cada
instante, cosa que no ocurre con las estructuras estticas como los arrays.
Al trabajar con estructuras dinmicas hay que manejar dos clases diferentes de varia-
bles: variables puntero (direccionan un dato) y variables referenciadas (son apuntadas).

type
Ptrentero= Ain t eger ;
Ptrcadena= As t ring[251;
, var
I
Pe: Ptrentero;
Pc: Pt r ca dena;

Las variables puntero Pe y Pe van a contener la direccin en memoria de un dato


entero y de un dato cadena, respectivamente.
Lo habitual ser que el tipo del dato al que apunta una variable puntero sea un regis-
tro, ste tendr un campo de informacin y otro, u otros campo de enlace, por consi-
guiente del mismo tipo puntero. ,

type
Ptrnodo - APers o na;
Persona - record
No mbre: stri ng[ 25 1;
Direcc: string[501;
Edad : intege r ;
Enlace: Ptrn odo
end;

Variables del tipo puntero Ptrnodo van a estar asociadas con variables referencia-
das del tipo Persona. '
var
P : Pt rn odo;
P Persona

En la declaracin anterior se crea la variable esttica P, cuyo valor, de momento, est


indefinido. Esta variable P apuntar a una variable referenciada, todava no creada, del
tipo Persona. La creacin de la variable referenciada se realiza mediante el procedi-
miento new

new(variable puntero); new(P};

Este procedimiento reserva memoria, crea una variable referenciada cuyo tipo (Per-
sona) est declarado dentro de las definiciones formales. Despus de la ejecucin del
procedimiento new la variable puntero tiene la direccin en memoria de la nueva varia-
ble creada.

,
Listas enlazadas: el TAO lista enlazada 161

As, P contendr la direccin de la variable creada del tipo Persona. Cmo se


nombran a las variables referenciadas? Tienen el mismo nombre que las variables punte-
ro poniendo a continuacin el carcter (o una flecha).
A

new (P) ; pA es la variable referenciada del tipo Persona.

Con esta variable se pueden hacer exactamente las mismas operaciones que con una
variable registro del tipo Persona.

new ( P) ;
pA.Nombre:= 'Juan Marco';
readln (PA. Edad) ;
pA.Enlace:= nil;

Existe una operacin inversa a new que permite liberar la memoria referenciada por
una variable puntero: procedimiento dispose.

di spose ( P) i libera la memoria! devtJ,c::lvees, mc::11}oria a la pila de memoria


libre, asignada anfer1rtnenfe onnew. . ..

Operaciones con variables puntero


Las variables puntero se pueden asignar y comparar con los operadores =, < >. Los pun-
teros pueden pasarse como parmetros a los subprogramas; una funcin puede ser de
tipo puntero, es decir, puede devolver un puntero.

type
Ptr= AElemento;
Elemento = record
Numero: integer;
Enlace: Ptr
end;
var
PI, P2: Ptr;

P2:= PI;
P2:= PIA.Enlace; Se asigna el campo Enlace de la variable referenciada por P l.
PIA.Enlace:= P2 A .Enlace;
P2:= nil; Es posible hacer que una variable puntero no apunte a nada
as ignando n il.

Despus de la operacin de liberar memoria, di spose (P) . La variable puntero se


queda con un valor arbitrario, entonces conviene asignar ni 1,

dispose (PI) ;
PI:= nil;

162 Estructura de datos

Ahora ya se puede escribir la implementacin de las operaciones con listas simple-


mente enlazadas utilizando variables dinmicas. Las operaciones sobre una lista enlaza-
da permiten acceder a la misma mediante un puntero externo, que contiene la direccin
del primer nodo de la lista.

p-- Juan Mar Peter ... Urban nil

I,
Supngase los tipos
type
T i po i n f o =
Pt rn o d o = ANodo ;
No do = record
In f o : Tip o i nfo ;
Sgte : Ptrn odo
I end;

5.4. INICIAR UNA LISTA ENLAZADA


Las operaciones usuales de iniciacin de una lista enlazada son: crear una lista vaca y
comprobar si una lista est vaca.

Crear lista
Inicia una lista sin nodos, como lista vaca.
procedure Listava c i a( var L: Ptrnodo);
begin
L:= nil
I
end;
I

Esvacia


! Esta operacin es una funcin que determina si la lista no tiene nodos.
,
,

function Esvac ia(L : Pt r nodo) : b o olean;

begin
Es v a cia := L = nil


end;


,

,

5.5. BSQUEDA EN LISTAS ENLAZADAS ,
,

1
La operacin de bsqueda en una lista enlazada, requiere una operacin Localiza
que permite localizar la direccin de un nodo que contenga un campo de informacin
1,,
-o

~
determinado; asimismo, se puede plantear una operacin Ex i s t e que sirve para deter- ,,
,
-~

l

~
I
I
Listas enlazadas: el TAO lista enlazada 163

minar si hay un nodo con cierta informacin. La funcin Loca 1 iza devuelve la direc-
cin de un nodo o ni l. Los cdigos fuente de ambas funciones son:

function Localiza(X:Tip o inf o ; L : Ptrno do): Ptrnodo;


var
T : Ptrno do;
begin
T : = L;
while (TA . Sgte<> nil) and (TA.lnfo<> X) do
T: = TA .Sgte;
if T A. ln fo< > X then
Loca l iza : = nil
elee
Local iza := T
end;

function Existe(X: T ipoinfo ; L: Ptr nodo): bool ean ;


begin
if not Es vacia(L) then
begin
while (LA .l nfo<> X) and (LA . Sg te<> nil) do
L: = LA . Sgte;
Existe : = L A. lnfo=X
end
elee
Msge( ' Error en lla mada ' )
end;

5.6. QPERACIONES DE DIRECCiN: SIGUIENTE, ANTERIOR,


ULTIMO

Operaciones usuales en la construccin de algoritmos de manipulacin de listas enlaza-


das son aquellas que permiten la bsqueda y localizacin
,
de un cierto nodo. Este es el
caso de las operaciones Anterior, Siguiente y Ultimo.

Anterior (P, L)/Siguiente (P, L)


Con esta operacin se obtiene la direccin del nodo anterior a P, o bien ni 1 si no existe
tal nodo. Para 10 que hay que recorrer la lista hasta encontrar P.

function Anterior(P: Ptr n odo ; L : Ptr nodo): Ptrnodo;


(El a nt e rior de lista vaca, del primer nodo y de d i reccin no
existente de l a l ista: nill
begin
if Esvac i a(L) or ( P= nil) or ( L=P) then
An terio r:= n il
elee begin
while ( LA. Sgte< > P) and (L A. Sg te< > n i l ) do
L : = LA . Sgte ;

Anterio r:= L
I

164 Estructura de datos

el se
An ter i or : = n i l
end
end;

La operacin siguiente devuelve la direccin del nodo siguiente a uno dado, o bien
n i 1 si es el ltimo nodo.

function S i gu i en te (P : Ptrnodo; L : Ptrnodo) : P trn odo ;


begin
if Esvac i a ( L) o r (P =n il) then
S igu i e n te : =nil
else
,
,
S igu i en te : =P~ . S gt e

end;

, .
Ultimo (L)
Para obtener la direccin del ltimo nodo se ha de recorrer toda la lista.
function Ultimo(L:P tr nodo ) : Ptrnodo ;
{ El l ti mo de l i s ta vaca co n s i der a mos nil }
begin
if Esv acia ( L ) then
Ult i mo := ni l
else
begin
while LA . Sgte <> n i l do
L:= L ~ . Sgte ;
Ult imo:= L
end
end;

,
5.7. INSERCION DE UN ELEMENTO EN UNA LISTA
La operacin de insercin de un elemento con un campo de informacin X siempre su-
pone crear un nuevo nodo. Para ello se utiliza el procedimiento new. Adems habr que
hacer un movimiento de enlaces. La funcin Crea r devuelve la direccin de un nuevo
nodo.
function Crear(X : T ipo i n f o ): Ptrnod o ;
var
N : Ptrnodo ;
begin
, n ew (N) ;
;
N ~ . In f o : = X;

N ~ . Sg t e : = nil;

Crea r: = N
end;

Inserprim(X,L)
Listas enlazadas: el TAO lista enlazada 165

Aade un nodo con la infolll1acin X como primer nodo de la lista

L-- N1 N2 N nil

A-- x

procedure In s e r p r im (X : T ipoin f o ; v ar L: Pt r n o do);


var
A : P t r n od o ;
beqin
A := Crear (X) ;
AA. Sgte:= L;
L: = A
end;

Inserta(X,P,L)

Aade a la lista L un nodo con el campo X, delante del nodo de direccin P.

p-

L- nil

A-....,
i
procedure I n se rt a(X : T i p o i n f o ; P: Ptrn o d o ; var L : Pt r n od o ) ;
var
A : Ptr n odo ; I
begin
A := Crea r ( X) ;
if Esvac ia(L) then
L: = A
elBe if P= L then
begin
AA. Sgte := P ;
L: = A
end
elBe begin {Ah ora es cuando se en l aza el nu evo n o do e n t r e e l n odo
a n t er i or y e l n o d o P }
Anter i or( P ,L ) A. Sg t e : = A;
AA. Sg t e := P
end
end;
I
,
I


166 Estructura de datos

Otra forma de enlazar el nuevo nodo consiste en aadir el nuevo nodo a continuacin
de P e intercambiar el campo de informacin:

procedure In serta(X : T i po i nfo ; P: Ptrnodo ; var L: Ptrnodo) ;


elae
begin {E l nuevo nod o es enl azad o a cont inu ac i n de P, d espus s e
intercamb i a el ca mpo Info }
AA . Sgte : = p A. Sgte ;
pA . Sg t e : = A;
AA . lnfo := P A. lnfo ;
pA .lnf o : = X
end;

Inserfin(X,L)

Aade un nodo con el campo X como ltimo nodo de la lista.

L- N1 N2 N x nil

procedure Inserfin(X : T i poinfo ; var L: Ptrnodo) ;


.
, var
.
A: Ptrno do;
I begin
A := Crea r (X) ;
if Esvac i a( L ) then
L := A
elae
Ult i mo(L)A. Sgte : = A
end;

5.8. SUPRESiN DE UN ELEMENTO DE UNA LISTA


I
La operacin de supresin (borrado) supone enlazar el nodo anterior con el nodo si-

guierlte al que va a ser borrado y liberar la memoria ocupada por el nodo a borrar. Esta
opera in se realiza con una llamada al procedimiento dispose.
Co las operaciones de supresin de un nodo y Ul t i mo resulta fcil eliminar todos
los nodos de una lista, quedando sta como lista vaca.
,

L- N1 N2 N3 N4 O " - N nil

Suprime(X,L) Se elimina el nodo que contiene a X.


- -- - - -
168 Estructura de datos

5.9. RECORRIDO DE UNA LISTA


Una operacin frecuente en cualquier algoritmo de manipulacin de listas es el re-
corrido de los nodos de la lista enlazada. El qu se haga con cada nodo depender
del problema que se est resolviendo, ahora son visitados para escribir el campo de in-
formacin.

procedure Vi s u a liz a( L: Ptrnodo );


var
Q : Ptrno d o ;
beg1n
Q := L;
wh11e Q< > n11 do
beg1n
wr ite ln (QA. Inf o, , ') ;
Q: = QA. Sgte
end
end;

5.10. LISTA ORDENADA

En las listas tratadas anteriormente los elementos de las mismas estn ordenadas por la
posicin que ocupan dentro de la lista. Si el tipo de informacin que representa cada
elemento es un tipo ordinal, o tiene un subcampo ordinal, se puede mantener la lista
ordenada respecto a dicho campo.
Al representar la lista ordenada mediante un puntero externo L , ste apuntar al pri-
mer nodo en el orden creciente de los elementos.
Dada la lista (al, a2, a3 , . . . ,an) estar ordenada si a, <= az <= a 3 <= ...
ano' <= an
La representacin enlazada:

L- ... -- ni!

5.10.1. Implementacin de una lista ordenada


La formacin de una lista ordenada se basa en dos operaciones: Inse ror d en, aade
el elemento X a la lista, manteniendo la ordenacin; Posinser, operacin que obtiene
la posicin a partir de la cual hay que aadir el elemento X en la lista para mantener la
ordenacin.
posinser(X,L)

Devuelve la direccin del nodo anterior a X segn la ordenacin de los elementos.


Ni 1, si es el anterior del primero .

i
Listas enlazadas: el TAO lista enlazada 169

function Pos i nser(X : T i poi nf o ; L:Ptrn o d o ) :Pt r n o d o ;


var
T : P t rn o do ;
begin
T : = nil;
if Not Esvacia (L) then
begin
while (X >= L A. Inf o ) and (L A.Sgte<> ni l) do
begin
T:= L;
L : = LA . Sgte
end;
if X>= L A.In fo then {Es e l lt i mo n odo}
T:= L;
end
Pos i ns e r:= T
end;
Inserorden(X,L)

Si la lista est vaca, el nodo se inserta como el primero de la lista. En caso contrario
se presentan dos casos:
a) El nodo ha de ser el primero de la lista.
b) El nodo ha de situarse entre dos nodos, o bien el ltimo. Al tener la direccin del
anterior, se reajustan los enlaces.
A

L-- 10 15 31 42 91 nil

37
N

procedure In serorden(X : Tipoinfo ; var L : Pt r nodo) ;


var
A, N : Pt r nodo ;
begin
N : = Cr ear ( X) ;
if Esvacia( L ) then
L : = N;
elee begin
A : = Posinser ( X, L) ;
if A = nil then {Se aade co mo prime r n odo}
begin
NA.Sgt e : = L;
L:= N
end
elee begin
NA.Sgte:= AA.S g te ;
AA. Sgte : = N
end
end
end;
170 Estructura de datos

5.10.2. Bsqueda en lista ordenada

La operacin de bsqueda de un elemento en una lista ordenada es ms eficiente que en


una lista general. Para decidir que un elemento no est en la lista basta encontrar un
elemento mayor, no hace falta recorrer la lista hasta el final. La funcin Buscorden
realiza la bsqueda en una lista ordenada.

function Buscorden(X:Tipoinfo; L:Ptrnodo) :Ptrnodo;


var
T: Ptrnodo;
begin
T:= L;
while (TA.Sgte<> nil) and (TA.Info< X) do
T:= TA.Sgte;
if TA.Info= X then

Buscorden:= T
elee
Buscorden:= nil
end;

El resto de operaciones sobre listas son iguales ya estn o no ordenadas. Como en la


operacin de borrado de un elemento hay que buscar antes la posicin que ocupa, es ms
eficiente cambiar la llamada a Localiza por Buscorden.

PROBLEMA 5.1

Como ejemplo de listas ordenadas, se escribe un programa en el que se forma una lista
ordenada de N nmeros enteros aleatorios. Una vez formada, se eliminan los elementos
repetidos y se muestra la lista.

Anlisis
La unidad Lis t aOrdenada contiene las operaciones de manejo de listas. El progra-
ma Lis t a Or contiene un procedimiento El i mi n a r Du p que sirve para eliminar ele-
mentos duplicados y otro procedimiento Mo s t r a r que visualiza la lista. El algoritmo
de EliminarDup recorre la lista nodo a nodo, comparando el nodo actual con el si- J
I

guiente; si son iguales se libera la memoria del nodo siguiente, se restablecen los punte- ,
ros y contina el proceso con el siguiente nodo. La lista estar formada por nmeros ,
!
enteros generados aleatoriamente de 1 a 99. El nmero de nodos, lo fijamos mediante la "
,

,
constante Elementos = 55.

Interfaz de la unidad
unit ListaOrdenada;
interface

type
Tipoinfo = integer;
Ptrnodo = ANodo;
Listas en/azadas: e/ TAO lista en/azada 171

Nodo = record
Inf o :Tipoinfo;
Sgte : Ptrnodo
end;
function Posinser (X:Tipoinf o ; L:Ptrnodo) : Ptr n od o ;
procedure Inserord e n (X : Tipoinfo, var L:Ptrnodo) ;
function Busc orden (X : T ip oinf o ; L :Ptr nodo) : Pt rn odo ;
implementation
.. . {C dig o correspondiente a los procedimientos / fu ncion es escrit os
anterior ment e }
end .

Codificacin del programa

program ListaOr(input, output);


uses Lista Orde n ada , Crt ;
const
Ele mentos - 55 ; ,

M = 99; i
var
L,Q:Ptrno do ;
Y: i n t ege r;

procedure Eli mi nar Du p(L : Ptrnodo);


var
A, Q: Ptrno do;
begin
A : - 'L ;
while A <> n i l do
if A ~ . Sgt e<> nil then
if A ~ .Info=A~.Sgte ~ . Info then {Un repetido}
begin
Q := AA . Sg te ;
AA. Sgte : = QA .Sg te ;
d i spose(Q)
end !
else A: =AA . Sg t e
else A:=AA . Sg te
end;

procedure Mo strar (L :P t rn o do);


var
Q:P t rno do ; ,
begin
Q: =L;
while Q <> ni l do
begin
wr ite (Q A.lnfo, " ); Q : =Q A.Sgte
end
end; , ,
. ' ;' .
begin {Bloque ppal }
L : =Nil; randomize;
for Y:= l to El ementos do
Ins e ro r de n (Random (99)+1, L );


172 Estructura de datos

c l rscr ; {l a l ista es mostrada}


Mos tr ar(L) ;
{Los e l ementos duplicados son e lim i nados d e la lista ordenada}
EliminarDup{L) ;
gotoxy(1 5, WhereY+l);
writel n ('L ista sin eleme n tos duplic ados') ;
Mostr ar(L)
end.

PROBLEMA 5.2 (vector dinmico)

Se desea definir un vector de nmeros reales de manera dinmica (vector dinmico),


utilizando punteros para formar una lista enlazada que represente el vector. La estrategia
de creacin consiste en crear en una nica operacin (<<de golpe) un espacio de memo-
ria que reserve memoria suficiente para contener mx elementos.
!
i En la operacin de asignacin se van aadiendo consecutivamente los nuevos ele-
mentos en la memoria reservada y si no hubiera espacio se ampla a otros mx elementos.
La operacin de supresin de un elemento requiere que un espacio equivalente al ocupa-
I do por el elemento quede libre para posteriores asignaciones.

, Solucin

El vector se representa mediante una lista enlazada con un puntero al primer nodo y otro
al ltimo nodo con nmero real aadido, La estrategia de asignacin es la indicada en el
enunciado del problema planteado,
La unidad Ve ctDi na contiene los tipos de datos y las operaciones necesarias para
cumplir los requisitos del problema.

unit VectD ina;


interface
const
Mx=20;
type
Te l e m=r ea l;
Pt r= AEl e m;
Elem= record
Dat : Tele m;
Sgte :Ptr
end;
Tvect or=record
A, Ult:Ptr;
N : i n t eger {nmero de eleme n to s del vector}
end;

procedure Cr eac i on (var V :T vecto r );


function Dir eccio n (V :Tvector ; X: Te l em) : Ptr ;
function An t e ri or (V :Tvector ; W: P t r ) :P t r ;
procedure Asig n ar (var V: Tvector ; T: Te l e m) ;
procedure Bo rr ar (var V : Tvector ; T : Telem ) ;
procedure Mo st rar (V :T vector) ;
176 Estructura de datos

La ventaja de una lista enlazada sobre un array es que la lista enlazada puede crecer y de-
crecer en tamao y que es fcil insertar o suprimir un valor (nodo) en el centro de una lista en-
lazada.
La lista enlazada es una estructura muy verstil. Los algoritmos para insercin y eliminacin
de datos constan de dos pasos:

Recorrer la lista desde el principio hasta que se alcanza la posicin apropiada .


Ejecutar cambios en los punteros para modificar la estructura de la lista.

El TAD lista enlazada es uno de los ms utilizados en gestin de proyectos software, debido a
que la estructura lista suele aparecer en la resolucin de numerosos problemas.

EJERCICIOS

Todos los ejercicios y problemas a los que se hace referencia deben de considerar la lista en-
lazada implementada mediante punteros. La direccin de acceso a la lista est en la variable
puntero L.
.

5.1. Escribir la funcin Cardinal que calcule el nmero de nodos de una lista enlazada.
5.2. Escribir un procedimiento que aada un nuevo elemento a la lista L a partir del elemento
. , .
-eSlmo.
5.3. Escribir un procedimiento que elimine de una lista L el nodo i-simo. 1
5.4. Escribir una funcin que devuelva la direccin del nodo i-simo de la lista L.
5.5. Escribir la funcin INVERSA que tiene como argumento de entrada la lista enlazada L,
devuelva la direccin de otra lista que tenga los nodos en orden inverso, es decir, ltimo
nodo pase a ser el primero, penltimo pase a ser el segundo, y as sucesivamente.
5.6. Escribir un procedimiento que tenga como argumento de entrada una lista L de nmeros
enteros, de la que se sabe que tiene nodos repetidos. El procedimiento crear otra lista
cuyos nodos contendrn las direcciones de los nodos repetidos en la lista L. Definir los
tipos de datos para representar ambas listas.
5.7. Una lista de cadenas de caracteres est ordenada alfabticamente. Escribir un procedimien-
to para suprimir aquel nodo que contenga la cadena S.
5.8. Se quiere implementar una lista enlazada mediante arrays de tal forma que cada elemento
del array contenga dos campos: campo de informacin y un segundo campo que llamare-
mos apuntador. El campo apuntador tiene la posicin que ocupa el siguiente nodo de la
lista, el ltimo nodo tiene el campo apuntador a cero.
Escribir los tipos de datos para esta representacin de la lista.
5.9. Dada la representacin de la lista propuesta en el anterior ejercicio, escribir el procedi-
miento de insertar un nodo como primer elemento de la lista.
5.10. Dada la representacin de la lista 5.8, escribir el procedimiento de insertar un nodo a partir
del que ocupa la posicin P.
5.11. Siguiendo con la representacin propuesta en 5.8, ahora escribir la funcin que localice un
nodo con el campo X.
5.12. Con la representacin de lista propuesta en 5.8, escribir el procedimiento de suprimir el
nodo con el campo de informacin X.

Listas enlazadas: el TAO lista enlazada 177

PROBLEMAS
5.1. Dada una lista enlazada de nmeros enteros, escribir las rutinas necesarias para que dicha
lista est ordenada en orden creciente. La ordenacin se ha de hacer intercambiando los
punteros a los nodos.
5.2. Se dispone una lista enlazada ordenada con claves repetidas. Realizar un procedimiento de
insercin de una clave en la lista, de tal forma que si la clave ya se encuentra en la lista la

inserte al final de todas las que tienen la misma clave.


5.3. Dos cadenas de caracteres estn almacenadas en dos listas. Se accede a dichas listas me-
diante los punteros L 1, L 2 . Escribir un subprograma que devuelva la direccin en la cade-
na L 2 a partir de la cual se encuentra la cadena Llo
5.4. Dada una cadena de caracteres almacenada en una lista L. Escribir un subprograma que
transforme la cadena L de tal fOllna que no haya caracteres repetidos.
5.5. Se quiere representar el tipo abstracto de datos conjunto de tal forma que los elementos
estn almacenados en una lista enlazada. Escribir una unidad para implementar el TAD
conjunto mediante listas. En la unidad deber de contener los tipos de datos necesarios y
las operaciones:

Conjunto vaco.
Aadir un elemento al conjunto.
Unin de conjuntos.
Interseccin de conjuntos.
Diferencia de conjuntos.
Nota: Los elementos del conjunto que sean de tipo cadena.

5.6. Escribir un programa en el que dados dos archivos de texto F 1, F 2 se formen dos conjun-
tos con las palabras respectivas de F 1 Y F 2 . Posteriollnente encontrar las palabras comu-
nes a ambos y mostrarlas por pantalla. Utilizar la unidad de conjuntos del problema 5.5
para resolver este supuesto.
5.7. Escribir un programa que forme lista ordenada de registros de empleados. La ordenacin
ha de ser respecto al campo entero Sueldo. Con esta lista ordenada realizar las siguientes

accIOnes:

Mostrar los registros cuyo sueldo S es tal que: P 1 ::::; S ::::; P 2 .
Aumentar en un 7 por 100 el sueldo de los empleados que ganan menos de P pesetas.
Aumentar en un 3 por 100 el sueldo de los empleados que ganan ms de P pesetas.
Dar de baja a los empleados con ms de 35 aos de antigedad.

5.8. Se quiere listar en orden alfabtico las palabras de que consta un archivo de texto junto con
los nmeros de lnea en que aparecen. Para ello hay que utilizar una estructura multienlaza-
da en la que la lista directorio es la lista ordenada de palabras. De cada nodo con la palabra
emerge otra lista con los nmero de lnea en que aparece la palabra en el archivo.

Escribir la unidad Li s ta_d e _Ent e r o s para encapsular el tipo lista de nmeros en-
teros.
Escribir la unidad L i s t a _ d e_Pa l abras para encapsular las operaciones que van a
manejar la lista de palabras propuesta.
Escribir un programa que haciendo uso de la(s) unidades anteriores resuelva el pro-
blema.
178 Estructura de datos

5.9. El polinomio P(x) = Go + G1X + G:zX 2 + ... + a"x" deseamos representarlo en una lista enlaza-
da, de tal forma que cada nodo contenga el coeficiente y el grado de un monomio. Escribir
un programa que tenga como entrada los coeficientes y exponentes de cada trmino de un
polinomio, y forme una lista enlazada para representarlo; ha de quedar en orden decrecien-
te respecto al grado del polinomio. En el programa deben de encontrarse las operaciones:
Evaluacin del polinomio para un valor dado de x.
Obtencin del polinomio derivada de P(x).
Obtencin del polinomio producto de dos polinomios.
5.10. Un vector disperso es aquel que tiene muchos elementos que son cero. Escribir un progra-
ma para representar mediante listas un vector disperso. Y realizar las operaciones:
Suma de dos vectores dispersos.
Producto escalar de dos vectores dispersos.

.... -.._ - -_. _- . . - --- ---- ---------------~=~~===~-------------'


,
CAPITULO


Istas emente en aza as

CONTENIDO

6.1. Especificacin de lista doblemente enlazada.


6.2. Realizacin de una lista doble mediante variables dinmicas.
6.3. Una aplicacin resuelta con listas doblemente enlazadas.
6.4. Especificacin de lista circular.
6.5. Realizacin de una lista circular mediante variables dinmicas.
6.6. Realizacin de listas circulares con doble enlace.
RESUMEN.
EJERCICIOS.
PROBLEMAS.

Las listas enlazadas se recorren en un solo sentido, normalmente en un


sentido establecido. En numerosas ocasiones es deseable avanzar en
cualquiera de los dos sentidos. Estas listas se denominan listas doble-
mente enlazadas. Otro tipo de listas que suelen ser tambin de gran
utilidad son listas circulares.
En el captulo se examinan las especificaciones de las listas doble-
mente enlazadas y listas circulares, as como los algoritmos que reali-
zan su implementacin.

6.1. ESPECIFICACiN DE LISTA DOBLEMENTE ENLAZADA


~ ....

En las listas simplemente enlazadas hay un solo sentido en el recorrido de la lista. Puede
resultar til el poder avanzar en ambos sentidos, de tal forma que los trminos predece-
sor y sucesor no tengan significado puesto que la lista es completamente simtrica. En
cada nodo de una lista doblemente enlazada existen dos enlaces, uno al siguiente nodo y
otro al nodo anterior.

179
180 Estructura de datos

Un nodo de una lista doblemente enlazada puede ser considerada como un registro
con tres campos: un campo informacin y dos campos de enlace.

Lo
4 ni! H o L
--1_ _' - - .- ... A ni!

La implementacin de listas doblemente enlazadas se puede realizar con estructuras


estticas, o bien con estructuras dinmicas.
Las operaciones que pueden ser definidas en el TAD lista doblemente enlazada son
similares a las operaciones con listas simplemente enlazadas.
Listavacia ( Ld) Inicializa la lista.
Esvac i a (Ld) Funcin que determina si la lista es vaca.
In s erprim (X,Ld) Inserta un nodo con la infOJ macin X como primer nodo de
la lista Ld.
In serta (X,P,Ld) Inserta en la lista Ld un nodo con el campo X delante del
nodo de direccin P.
,
I nse rf in (X,Ld) Inserta un nodo con el campo X como ltimo nodo de la lis-
I ta Ld.
Loca li za (X , Ld ) Funcin que devuelve la posicin/direccin donde est el cam-
po de informacin x. Si no est devuelve nulo.
Suprim e (X,L d) Elimina de la lista el nodo que contiene a x.
Suprimed ir ( P,L d) Elimina de la lista el nodo cuya direccin/posicin viene dada
por P.
Prime ro (P) Funcin que devuelve la posicin/direccin del primer nodo
de la lista L.
ultimo (Ld) Funcin que devuelve la posicin/direccin del ltimo nodo
de la lista Ld.
Anul a (Ld) Esta operacin elimina/libera todos los nodos de la lista Ld.
visualiza ( Ld) Esta operacin visualiza el campo de informacin de todos
los elementos de Ld.
Puede observarse que no aparecen las operaciones Anterior ni Siguiente. Al -

tener cada nodo dos enlaces, uno al siguiente y otro al anterior, y ser una lista simtrica,
se dispone directamente de las direcciones de los nodos contiguos a uno dado.
Las operaciones anteriores son las operaciones bsicas para manipulacin de listas.
Dependiendo del tipo de representacin elegida y del problema a resolver podrn existir

otras operaciones sobre listas .


,
6.2. PLEMENTACION DE UNA LISTA DOBLEMENTE
,
ENLAZADA MEDIANTE VARIABLES DINAMICAS
Se utiliza el tipo puntero a un dato. Este dato tendr un campo de informacin, relativo
a lo que queremos almacenar, y dos campos de enlace que por tanto tambin sern pun-
Listas doblemente enlazadas 181

teros. Con esta implementacin, la lista doble se representa con una variable puntero Ld
a un nodo extremo que por conveniencia le consideramos el primer nodo de la lista.
type
T i poi n for - ... ;
P trndble = ANododble
Nod odb l e = record
I nfo : T ipoinf o ;
Sgt e , An te r: Pt rn db l e
end;

6.2.1. Creacin de nodos en la lista


Las operaciones utilizadas sern Cargar la lista (L i s taVa c ia ), Esvacia, Localiza,
Existe, Ultimo, Inserta e Insertajin.

Crear lista
Inicia una lista doble sin nodos, como lista vaca.
procedure Li s t aVac i a (var Ld : Ptrndble) ;
begin
Ld : =nil
end;

P ---,

Esvacia
La funcin EsVaci a devuelve verdadero si la lista est vaca y falso en caso contrario.
function Esva c ia (Ld: Pt r ndble) : boole a n ;
begin
Esvacia : = Ld = n i l
end

Localiza
Devuelve la direccin de un nodo o ni l.
function Loca li za (X : T i poi n f o ; Ld : Ptrndb le) : Ptr n d b le ;
var
T: Pt rn dbl e;
begin
T : = Ld ;
if not Esvaci a (Ld) then
while (T A. Sgte < > n il) and (TA . lnfo < > X) do
T : = TA . Sgte ;
if T A. l n f o < > X then
Loca liza : =ni l
else
Locali za : = T
end;
!
,

182 Estructura de datos

Una versin de Localiza es la operacin Existe. Con esta operacin se inspec-


ciona si en una lista doble existe un nodo del cual se conoce su direccin .

Existe (P, Ld)

function Existe (P: P t rndb l e ; Ld:Ptrndbl e) : b oo lean;


, begin

if not Esvacia (Ld) and (P<> nil) then


begin
while ( Ld <> Pi and ( Ld A. Sgte<> nil ) do

Ld := Ld A.S gte ;
I Exis te := Ld = P
end
elee
Msge ( 'Err or e n l lamada ' )
end

Ultimo (Ld)

La operacin Ul tim o obtiene la direccin del nodo que se encuentra en el otro extremo
del nodo que consideramos el primero, el apuntado por Ld.
function Ult i mo (Ld: Pt r nd ble) : Ptrndble;
{El l t i mo de li sta vaca consideramo s n i l}
begin
if Esvacia ( Ld ) then
Ultimo := nil
elee begin
while LdA.Sgt e<> nil do
Ld := LdA. Sgte ;
Ultimo := Ld
end
end;

Cada vez que se realiza la insercin de un nodo con el campo de informacin x, hay
que reservar memoria para dicho nodo. La operacin crear realiza esta operacin.

function Crear (x : Tipo inf o) : Ptrndble;


var
N: Ptrndble;
begin
n e w (N);
NA.Info := X;
NA.Sgte := nil;
NA.Anter := nil;
Crear := N
end;

Inserta (X, P, Ld)


Aade a la lista Ld un nodo con el campo x, delante del nodo de direccin P.
184 Estructura de datos

P ~ . Sgte : = N;
N~ . Ante r: = P
end
end;

nil

Insertafin (X, Ld)

Aade un nodo con el campo x como ltimo nodo de la lista.

nil .. .

L ni I

procedure In sertafin (X : Ti p oinfo ; var Ld : P trndbl e);


var
N, U : Ptrndb l e ;
begin
N : = Cre ar (X) ;
if Esvac i a (Ld) then
Ld : = N
else begin
U := Ultim o (L d);

U~ . Sgte : = N;
N~ . Ante r := U
end
end;

6.2.2. Eliminacin de nodos


La eliminacin de nodos de una lista doble la planteamos en dos operaciones muy simi-
lares. En la primera es pasado el campo de informacin del nodo que queremos borrar, y
se elimina el primer nodo que se encuentra con dicho campo de informacin. En la se-
gunda se tiene la direccin del nodo que quiere ser eliminado. Las acciones de supresin
se realizan en la segunda operacin.
-------------~~ .... - - - - - - -
~.~. - - _ .... - - - - - - - _ . ---- - --- --- -- --- ----

Listas doblemente enlazadas 185

r-----------,
I I
I


nil ni I

I
I I
L ___________ .J

,
procedure Suprime (X: Tipoinfo; var Ld: Ptrndble);
var
P: Ptrndble;
begin
P := Localiza (X, Ld);
if P<> nil then
Suprimedir (P, Ld)
else
Msge ('No est')
end;

procedure Suprimedir (P: Ptrndble; var Ld: Ptrndble);


begin
if Existe (P, Ld) then
begin
if P = Ld then {Primer nodo}
begin
Ld := LdA.Sgte;
LdA.Anter := nil
end
else if P < > Ultimo (Ld) then
begin
pA.AnterA.Sgte := PA.Sgte;
pA.SgteA.Anter := pA.Anter
end
else {Es el ltimo nodo}
pA.AnterA.Sgte:= nil;
dispose (P)
end
end;

Anula (Ld)
Esta operacin libera la memoria ocupada por todos los nodos de la lista Ld. El estado
final de la lista Ld es vaca.
Una de las formas de realizar esta operacin es suprimir nodos desde aquel que arbi-
trariamente consideramos ltimo hasta el apuntado por Ld. Se fundamenta en las opera-
ciones de Ultimo y Suprimedir.
procedure Anula (var Ld: Ptrndble);
var
P: Ptrndble;
begin
while Ld < > nil do
begin
P := Ultimo(Ld);

,
I
186 Estructura de datos

Suprimedir(P,Ld) ; ,
end
end;

visualiza (Ld)
Esta operacin muestra el contenido de la lista en cualquier momento de manejo de la

mIsma.
procedure Visualiza (Ld: Ptrndble);
begin
while Ld<> nil do
begin
Escribir (LdA. Info) ;
Ld := LdA.Sgte
end
end;

6.3. UNA APLICACiN RESUELTA CON LISTAS


DOBLEMENTE ENLAZADAS
En un ambulatorio se desea asociar mdicos con asegurados. Para ello se trata de formar
una lista doblemente enlazada con todos los asegurados. Los datos de cada asegurado
son su nombre y nmero de afiliacin. A su vez, en otra lista doble se tendr a los mdi-
cos del ambulatorio. Los datos de cada mdico son nombre y nmero de telfono (f ono).
La lista de mdicos est ordenada alfabticamente; adems, cada nodo mdico tiene un
campo puntero, que referencia al nodo del primer asegurado asignado. Por consiguiente,
cada nodo de asegurado tiene, adems de los datos propios, un puntero al siguiente ase-
gurado que pertenece al mismo mdico; el ltimo de los asegurados a un mdico, contie-
ne nil en el campo que forma la lista de asegurados a un mdico.
La entrada de datos ser interactiva; primero se introducen los datos de los mdicos;
a continuacin, los datos de los asegurados. La asignacin de los asegurados a los mdi-
cos se har de manera aleatoria.

Anlisis
La representacin grfica de las dos listas a crear:
Mdico Referencia Asegurado Referencia

Amador 6 1 Luis M 5 ,
Castro 9 2 Marta B ,l
3 Mertoli 7 ,I
<


4 Tonino l
5 Rufis A 3 1
6 Rios e
j

7 Fausto F
8
nil

8 Slisa N 3

9 Doroteo

---~---- .

Listas doblemente enlazadas 187

De esta representacin podemos obtener que la lista de asegurados con el mdico


Amador comienza en el nodo <6>, Rios e, que le sigue <8>, Slisa N, al nodo <3>,
Mertoli, despus <7>, Fausto F, y aqu termina.
Para la representacin de datos, el nodo del mdico:

Anter Nomb re Te l fono Sgte

- - - --.

L_a s g : es el campo puntero al siguiente de la lista de asegurados.


El nodo del asegurado:

Anter Nomb re Idt Sg t e

- - - --.

Los tipos de datos y operaciones con lista doble de asegurados en la unidad Lis tA sg.

Unidad ListAseg
unit Lis t Aseg ;
interface
type
Ca dn a30 =st ri ng[30] ;
Cadna1 1 =st ri ng [1 1 ] ;
PtrAs= ~NodoAs ;
NodoAs= record
No mbre :Cadna 30 ;
I dt : Cadna11;
S_ asg : Pt r As; {Referenc i a a si guien te asegurado de u n mismo md i co}
Anter , Sgte : PtrAs
end;

{Oper aciones}
procedure Li stavacia (var Ld : PtrAs) ;
function Esva cia ( Ld: Pt r As ) : boole an;
function Localiza (x : Cadnall ; Ld:Pt r As) : PtrA s ;
function Ex i ste (P : PtrAs ; Ld : PtrAs) : boolean;
function Ult i mo (Ld : PtrAs) : PtrAs ;
procedure I nse rta (Nm: Cadna 30; I d : Cadnall ; P :P trAs ;var Ld : Pt rA s) ;
procedure In se rtad (Nm: Cadn a3 0 ; Id : Ca dnal1 ;P: PtrAs ;var Ld :Ptr As) ;
procedure Insertafi n (Nm:Cad n a 30 ; Id : Cadna l 1 ;var Ld :P trAs) ;
procedure Sup r ime (I d: Cadnall ; var Ld : Pt r As) ;
procedure Su pr emedir(P : PtrAs ; var Ld: Pt r As) ;
procedure Vis uali z a (Ld : Ptr As);
implementation
uses crt;
188 Estructura de datos

procedure Listavacia (var Ld:PtrAs);


begin
Ld:=nil
end;

function Esvacia (Ld:PtrAs) :boolean;


begin
Esvacia:=Ld=nil
end;

function Localiza (X:Cadnall;Ld:PtrAs) :PtrAs;


{Bsqueda se hace por el cdigo de identificacin}
var
T:PtrAs;
begin
T:=Ld;
if not Esvacia (Ld) then
while (TA.Sgte<>nil) and (TA.ldt<>X) do
T:=TA.Sgte;
if TA.ldt<>X then
Localiza:=nil
elee
Localiza:=T
end;

function Existe (p:PtrAs; Ld:PtrAs) :boolean;


begin
if not Esvacia (Ld) and (P<>nil) then
begin
while (Ld<>P) and (LdA.Sgte<>nil) do
Ld:=LdA.Sgte;
Existe:=Ld=P
end
elee
writeln ('Error en llamada'); {<Msge (Error) >}
end;

function Ultimo (Ld:PtrAs) :PtrAs;


{El ltimo de lista vaca consideramos nil}
begin
if Esvacia (Ld) then
Ultimo:=nil
elee begin
while LdA.Sgte<> nil do
Ld:=LdA.Sgte;
Ultimo:=Ld
end
end;
functlon Crear (Nm:Cadna30;Id:Cadnall) :PtrAs;
var
N:PtrAs;
begin
new(N) ;
NA.Nombre:=Nm;NA.ldt:=Id;NA.S_asg:=nil;
NA.Sgte:=nil;NA.Anter:=nil;
Crear:=N
end;
Listas doblemente enlazadas 189

procedure I ns erta(Nm: Cadna30 ; Id : Cad nal l ; P :P t r As ; var Ld :P t r As );


{A ade a l a l i s ta Ld un nodo co n e l campo X, de l a n te d e l n od o P }


var

A :P tr As ;
begin
A:= Cre a r (Nm, Id);
if Es vacia (Ld) then
Ld : =A i
el se if p=Ld then {D e l ante del pri mer n odo}

begin
AA . Sg te:=P;
p A. An t e r:= A ;

Ld : =A
end
else if Ex ist e (P , Ld) then
begin {Aho ra e s cuando se enlaza e l n uevo nodo e n tre e l n o d o
ante r i or y el nodo P}
pA . An t erA.Sgte:=A;
AA.Anter:=pA.An ter ;
AA. S gte:=P;
p A.Anter:=A
end
end;

procedure I nse rtad (Nm : Cad n a30 ;I d : Cadn a ll;p: Pt rA s; var Ld :P t rAs ) ;
{Aa d ir nodo c on el campo X a con t i nua cin de l nod o P e n l a l is ta}
var
N : Pt r As ;
begin
if Es v a c i a ( Ld ) then
Ld : =Cr ear(Nm, I d )
else if P = Ultim o( Ld ) then
In se rtafin(Nm,Id,Ld )
else if Existe(P,L d) then
begin {Ahora es cua n do se enl aza el n ue v o nodo, a co n ti nuacin
d el n odo P}
N: =C r ea r (Nm, I d ) ;
pA . Sg t eA . An ter : =N ;
NA. Sg t e :=p A. Sgte ;
p A. Sgte :=N;
NA. An te r:=P
end
end;

procedure Insertafin (Nm: Cad n a30 ;Id:Cadnall;var Ld :P trAs );


var
N, U: PtrAs;
begin
N : =Crear(Nm , I d) ;
if Esva c i a ( Ld ) then
Ld:= N
else begin
U: =Ult imo (Ld) ;
UA. Sgt e :=N;
NA . An t er := U
end
end;
190 Estructura de datos

{Borrado de n odos}
procedure Sup r ime(Id:Cadna l l ; var Ld: Pt r As) ;
var
P : PtrAs ;
begin
P : =Loca liza(I d , Ld) ;
if P<> nil then
Sup rimedir ( P , Ld)
el se
wri teln ( ' Error en la l lamada .' )
end;


procedure Su p r imedir ( P :PtrAs; var Ld : PtrAs) ;
begin
if Ex i ste (P , Ld) then
begin
if p=Ld then (Primer nodo)
begin
Ld:=LdA.Sg te ;
LdA.Anter: =nil
end
else if P<>Ultimo(Ld) then

begin
pA . An t e r A. Sgte : = p A. Sgte;
p A. Sg t e A. Anter := pA . Anter
end
el Be
p A. Ant erA . Sgte := nil;
dispose(P)
end
end;

procedure Visuali za( Ld :P t r As) ;


procedure Esc r ibir(A : NodoAs) ;
begin
write(A . No mbre} ; go t oxy(3l,whereY) ;
writeln(A . ldt)
end;
begin ,
while Ld<> nil do
begin
Esc ri b ir (Ld A) ;
Ld : =LdA.Sgte
end
end;
begin
end.

Los tipos de datos y operaciones bsicas para formar una lista doble ordenada las
representamos en la unidad Li s tM e d.
Unidad ListMed
unit Li stMe d;
interface
Listas doblemente enlazadas 191

ueee ListAseg;
type
Cadna30=string[30] ;
Cadnall=string[ll] ;
PtrMd=ANodoMd;
NodoMd=record
Nombre:Cadna30;
Fono:Cadnall;{telfono}
L_asg:PtrAs;
Anter,Sgte:PtrMd
end;

function Posinser (X:Cadna30;L:PtrMd) :PtrMd;


procedure Inserorden (M:Cadna30;F:Cadnall;var L:PtrMd);
function Buscorden (X:Cadna30;L:PtrMd) :PtrMd;
procedure Mostrar (L:PtrMd);
implementation

function Posinser (X:Cadna30;L:PtrMd) :PtrMd;


begin
if(L<>nil) then
begin
while (X >= LA.Nombre) and (LA.Sgte<>nil) do
L:=LA.Sgte;
if X >= LA.Nombre then {Es el ltimo nodo}
Posinser:=L
elee
A
Posinser:=L . Anter
end
elee {Lista vaca} ,

end;

procedure Inserorden(M:Cadna30;F:Cadnall;var L:PtrMd);


var
A, N:PtrMd;
begin
new(N); NA.Nombre:=M; NA. Fono:=F;NA.L_asg:=nil;
NA.Sgte:=nil; NA.Anter:=nil;
if L=nil then
L:=N
elee begin
A:=Posinser(M, L);
if A=nil then {Aadido como primer nodo}

begin
NA.Sgte:=L;LA.Anter:=N;
L:=N
end
, elee begin {Aadido a partir de A}
,
NA.Sgte:=AA.Sgte; NA.Anter:=A;
if AA.Sgte<>nil then
AA.SgteA.Anter:=N;
AA.Sgte:=N
end
end
end;
!

192 Estructura de datos


,
,

function Busc or d e n ( X : Cadna30 ; L :P t r Mdl : Pt r Md ; ,,


var
T:P t rMd ;
begin
T: =L ;
while (TA.Sg te <> n i ll and (TA .Nombre < Xl do
'.
T : =TA.Sgte; ~
if TA .Nombre =X then
Busc orden:=T
el se
,
Busc o r d e n : =nil
end;

procedure Mos t ra r (L : P trMd l ;


var
Q : P t r Md ;
begin
Q : =L ;
while Q<>nil do
begin
writeln(QA.N ombr e ," , QA.F o no); Q: =QA. Sg te
end
end;
end.

Programa Ambulatorio de creacin de listas

La primera accin para crear esta superestructura es dar entrada a los datos de los
mdicos y dar de alta los asegurados del ambulatorio. Por ltimo, asignar (se hace
aleatoriamente) cada asegurado a un mdico, y formar la lista virtual de asegurados de
un mdico.
Realmente hay dos nicas listas, mdicos y asegurados. A nivel lgico se forma una
lista por cada mdico para ello se utiliza el campo S_ asg con el que va enlazando los
asegurados del mismo mdico.
Los nombres de los mdicos y sus nmeros de fono se encuentran en el archivo de
texto Me d i e o s . t x t; al igual que los nombres de las personas adscritas al ambulatorio
que estn en el archivo As e gurad . t x t.
Una vez formada toda esta superestructura pueden plantearse otros problemas, como,
por ejemplo, dado un mdico listar sus asegurados; otra operacin, dado un asegurado
mostrar el doctor que le pertenece, y otras ms que podemos pensar de utilidad. En el
programa se realiza la operacin de listar todos los asegurados que tiene un mdico.

program Ambu l at o r io ;
uses ListAseg,ListM e d, Crt;
var
Lme d , Md : PtrMd ;
Las g : PtrMd ;
Fme d , Fasg : T e x t ;
Nb : Cadna3 0 ;
Ch : char ;
Listas doblemente enlazadas 193


procedure Medicos(var Lm:PtrMd);
,

var
,
Nm:Cadna30;F:Cadnall; ,

J:integer;
\
begin
!
Lm:=nil;
\,
repeat i
readln(Fmed,Nm) ;
readln(Fmed,F) ;
Inserdorden(Nm,F,Lm) ;
until eof(Fmed);
end;

procedure Asegurados(var Las:PtrAs);


var
Nm:Cadna30;Id:Cadnal1;
begin
Las:=nil;
repeat
readln(Fasg,Nm) ;
readln(Fasg,Id) ;
Insertafin(Nm,Id,Las)
until eof(Fasg)
end;

{LOS siguientes procedimientos asignan aleatoriamente cada asegurado a un


mdi co. Para ello se cuenta el nmero de mdicos y con una funcin
random, se asocia un asegurado al mdico}

function Posicion(L:PtrMd;K:integer) :PtrMd;


begin
while K>l do
begin
L:=L~.Sgte;

K:=K - l
end;
Posicion:=L
end; ,
,

procedure Asocia(Asg:ptrAs;Lm:PtrMd); I
var
C : integer ;
M:PtrMd;
function Cuantos(L:PtrMd) :integer;
var K:integer;
begin
K:=O;
while L<> nil do
begin
L:=L A.Sgte;
K:=K+l
end;
Cuantos := K
end

,
194 Estructura de datos

begin
randomize;
C:=Cuantos (Lm);if C=O then Asg:=nil; {Para no entrar en el bucle}
while Asg<>nil do
begin
M:=posicion(Lm, random(C)+l);
write(AsgA.Nombre) ;gotoxy(31,wherey);
write( 'tiene asignado al doctor');
writeln(MA.Nombre) ;
{Enlazamos en la lista de asegurados, como el primero de ella}
AsgA.S_asg:=MA.L_asg;
MA.L_asg:=Asg;
Asg:=AsgA.Sgte
end
end;

procedure VerAseg(M:PtrMd);
var A:PtrAs;
begin
{Recorre, visualizando por pantalla, los asegurados de un mdico}
A:=MA.L_asg;
while A<>nil do
begin
write(AA.Nombre) ;gotoxy(31,whereY) ;writeln(AA.Idt);
A:=AA.S_ asg ;
end
end;

begin {programa Ambulatorio}


clrscr;
{Es creada la lista doble ordenada de mdicos}
assign (Fmed, 'Medicos. txt'); reset (Fmed) ;
Medicos (Lmed);
Mostrar(Lmed) ;

repeat until readkey ln [#0 .. #255] ;clrscr;
{Es creada la lista doble de asegurados}
assign(Fasg, 'Asegurad.txt') ;reset(Fasg);
Asegurados (Lasg) ;
Visualiza(Lasg) ;
repeat until readkey in [#0 .. #255] ;clrscr;
{Se asocian}
Asocia (Lasg.Lmed);
repeat
gotoxy(lO,WhereY+2) ;
write( 'Nombre del mdico:') ;readln(Nb);
Md:=Buscorden(Nb,Lmed) ;
if Md<>nil then
VerAseg(Md)
elee
writeln( 'Mdico no est en el ambulatorio');
repeat write( 'Otro mdico:') ;readln(Ch)
until upcase (Ch) in [' S', 'N']
until Ch in ['N', 'n']
end. {Fin de programa Ambulatorio}
Listas doblemente enlazadas 195

6.4. PLE NTACIN DE UNA LISTA CIRCULAR


MEDIANTE VARIABLES DINMICAS
En las listas lineales siempre hay un ltimo nodo que tiene el campo de enlace a ni l .
Esto presenta el inconveniente de que dada la posicin de un nodo P no se puede alcan-
zar cualquier otro nodo que preceda al nodo P .
Haciendo un pequeo cambio en la estructura de una lista lineal, de tal manera que
no haya, al menos a nivel lgico, un ltimo nodo sino que los nodos formen una estruc-
tura circular, podremos acceder a todos los nodos a partir de uno dado.
Se podra decir que el cambio que hay que hacer es que el ltimo nodo en vez de
apuntar a n i 1 apunte al primer nodo. En realidad, en una estructura circular no hay

Le
4

primero ni ltimo.
Una lista circular, por su naturaleza no tiene primero ni ltimo nodo. Sin embargo,
resulta til establecer un primer y un ltimo nodo. Una convencin es la de considerar
que el puntero externo de la lista circular referencia al ltimo nodo, y que el nodo si-
guiente sea el primer nodo. Todos los recorridos de la lista circular se hacen tomando
como referencia el considerado ltimo.
Sobre una lista circular pueden especificarse una serie de operaciones, y as formar
el T A D lista circular. Estas operaciones coinciden con las definidas en los T AD lista y
lista doblemente enlazada

Listavaei a (Le) Inicializa la lista.


E sva e i a (L e) Funcin que determina si la lista es vaCa.
Primero ( Le) Devuelve la direccin del primer nodo.
Ultimo (Le) Devuelve la direccin del ltimo nodo.
Ante r i o r ( P, Le) Devuelve la direccin del nodo anterior a P.
In s erprim ( X, Le ) Inserta un nodo con la informacin X como primer nodo de
la lista L e .
Inserta (X, P, Le) Inserta en la lista Le un nodo con el campo X, delante del
nodo de direccin P.
I n se r f i n (X , Le) Inserta un nodo con el campo X como ltimo nodo de la lista L e .
Loc al i z a (X , Le) Funcin que devuelve la posicin/direccin donde est el cam-
po de informacin x . Si no est devuelve nulo.
S upr i me (X , Le) Elimina de la lista el nodo que contiene a X.
Sup r i med i r (P , Le ) Elimina de la lista el nodo cuya direccin/posicin viene dada
por P.
v is ual iz a ( Le) Muestra el campo de informacin de cada nodo de una lista
circular.

,.
,
196 Estructura de datos

,
6.5. IMPLEMENTACION
, DE UNA LISTA CIRCULAR MEDIANTE
VARIABLES DINAMICAS

En esta implementacin con punteros, hay un puntero externo Le que referencia al que
arbitrariamente se considera ltimo nodo de la lista. Esta realizacin de lista circular a
su vez es simplemente enlazada, por lo que el sentido de recorrido siempre es el mismo.
Puede hacerse con dos enlaces y as podra recorrerse en ambos sentidos.

type
Tipoinfo - ... ;
Ptrnlc = ANodolc
Nodolc = record
Info: Tipoinfo;
Sgte,
Anter: Ptrnlc
end;

Las operaciones de Listavaeia, Esvaeia no hace falta escribirlas, son exacta-


mentes iguales que en las listas dobles. El resto de las operaciones de la especificacin
se detallan a continuacin.

Primero (Le)
function Primero(Lc: Ptrnlc): Ptrnlc;
begin
if not Esvacia(Lc) then
Primero := LcA.Sgte
elee
Primero := nil {Consideracin arbitraria}
end;

Ultimo(Le)
function Ultimo(Lc: Ptrnlc) : Ptrnlc;
begin
Ultimo := Lc
end;

Anterior(P, Le)
function Anterior (P: Ptrnlc; Lc: Ptrnlc) : Ptrnlc;
{Consideramos que el anterior de lista vaca y de direccin no
existente de la lista: nil}
var
A: Ptrnlc;
begin
if Esvacia (Lc) or (P= nil) then
Anterior:= nil
elee begin
A:= Lc;
while (AA.Sgte < > P) and (AA.Sgte < > Lc) do
A :=AA.Sgte;
"'- -- -- - - _._ _ -- --
.. . - -- - -- ------ _ . _ - - - -- --

Listas doblemente enlazadas 197

if AA.Sgte= P then
An te ri o r:= A
elBe
An te rior:= ni l
end
end;

Loealiza(X, Le)

Funcin que devuelve la posicin/direccin donde est el campo de informacin X. Si


no est devuelve nulo.

function Loc aliza ( X: Ti po i n f o ; Le : Ptrnl e ): Ptrnl e ;


var
T: Ptrnle;
begin
T:= Le ;
while (TA.Sgte < > Le) and (T A.lnfo < > X) do
T : = TA.Sgte;
if T A.lnf o < > X then
Loca liza := nil
elBe
Loca liza := T
end;

Al igual que ocurre con listas doblemente enlazadas, una versin de Localiza es
la operacin Ex i s te. Es planteada de tal forma que busca la existencia de un nodo,
dada su direccin en una lista circular.

Existe(P, Le)
function Existe ( P: Pt r n l e ; Le: Pt rnl e) : b oo l ean ;
var
T: Ptrnl e ;
begin
if not Es v a e ia(L e ) and ( P < > nil) then
begin
T:= Le ;
while (Le < > P ) and ( Le A. Sgte < > T) do
Le := LeA.Sgte;
Ex i s te := Le = P
end
elBe
Ms ge ( 'Error en ll a ma d a' )
end;

Inserta (X, P, Ld)


Aade a la lista Lc un nodo con el campo X, delante del nodo de direccin P. Para
las operaciones de insercin escribimos la operacin de crear un nodo para una lista
circular.
198 Estructura de datos

function Crear(X: Tipoinfo): Ptrnle;


var
N: Ptrnle;
begin
new (N) ;
NA.Info -- X ,
NA.Sgte -- N ,
Crear := N
end;

f-
A Al aadir un nuevo nodo: Le A B
~ ~

procedure Insera(X:Tipoinfo; P:Ptrnle; var Le:Ptrnle);


var
A: Ptrnle;
begin
A:= Crear(X);
if Esvaeia(Le) then
Le:= A
elae if Existe(P, Le) then
begin {Ahora es cuando se enlaza el nuevo nodo entre el nodo anterior y
el nodo P}
Anterior(P, Le)A.Sgte := A;
AA.Sgte := P;
end
end;

Inserprim(X, Le)
Aade un nodo con campo de informacin X como nodo que est a continuacin del
considerado el ltimo, Lc. En el caso de que la lista est vaca, crea la lista con dicho
nodo.
Procedure Inserprim(X:Tipoinfo; var Le: Ptrnle);
var
N: Ptrnle;
begin
N := Crear(X);
if Esvaeia(Le) then
Le := N
elae begin
NA.Sgte := LeA.Sgte;
LeA.Sgte := N
end
end;

Inserfin(X, Le)
Aade un nodo con el campo X como ltimo nodo de la lista L c. De estar vaca crea la
lista con dicho nodo. En cualquier caso, esta operacin siempre devuelve la direccin
del nuevo nodo: el ltimo.
200 Estructura de datos

6.6. IMPLEMENTACION DE LISTAS CIR RES


CON DOBLE ENLACE

Esta implementacin de listas circulares con nodos que tienen dos punteros, permiten
recorrer la lista circular en sentido del avance del reloj, o bien en sentido contrario. Los
tipos de datos para realizar una lista circular con doble enlace son:

type
Tip oin f o - string;
PtrDne - ANodoDe;
NodoDe = record
Inf o : Tipo inf o ;
Sgte , Anter : PtrDnc
end;

Las operaciones de insercin tienen que contemplar el doble enlace para forlllar la
lista circular. Lo mismo a la hora de suprimir un nodo de la lista. La operacin de reco-
rrer la lista se puede hacer en dos direcciones o bien con el puntero sgte o bien con el
puntero An ter. A continuacin se escribe el procedimiento que recorre la lista hacia
adelante:

procedure Re eorre_ A (Lde:PtrDn c) ;


var A:PtrDne;
begin
if not Esvacia ( Ld e) then
begin
A:=Lde;
repeat
A := AA.Sgte;
Eseribir(AA.lnfo)
until A = Le;
end
end;

.. ..
rt t

a)

Cabecera --,

b)
Figura 6.1. Lista circular doblemente enlazada con un nodo cabecera.
Listas doblemente enlazadas 201

Tambin se escribe el procedimiento para recorrer la lista desde el ltimo nodo al


primero. Recordemos que Ldc referencia al nodo que por convenio consideramos
ltimo; se utiliza el puntero Anter.

procedure Recorre_D(Ldc:PtrDnc);
var D:PtrDnc;
begin
if not Esvacia (Ldc) then
begin
D: =Ldc;
repeat
Escribir(D A.lnfo) ;
D:=D A.Anter
until D=Ldc
end
end;

PROBLEMA 6.1. Lista circular doblemente enlazada y ordenada


Se trata de escribir un procedimiento que tenga como entrada una lista circular con
doble enlace, siendo el campo info ordinal, y nos devuelva la lista ordenada.
En realidad se construye con dos procedimientos. El procedimiento ordenar reci-
be la lista, rompe la estructura circular, se convierte en una lista lineal y ordena la
lista; el procedimiento ordene ir compone la estructura circular. E/'nodo de la lista
tiene como campo in f o valores enteros, y los dos campos puntero para enlazar que
ahora se /laman izqdo y dcho.
type
ptro=Anodo;
nodo=record
izdo,
dcho:ptro;
info:integer
end;
var
cab:ptro;

procedure ordenar (var cab:ptro);


var
p,q,aux:ptro;
begin
p:=cab;
while p<>nil do
begin
q:=pA.dcho;
while q<>nil do
if p A.info < = qA.info then
q:=q A.dcho
elee
begin
{"saca" de la lista el nodo q}
qA.izd o A.dcho:=q A.dcho;
202 Estructura de datos

if q A.dcho <> nil then


q A . d e hoA.l.Z
' d O:=q A .l.Z
' d O;
{aade q c om o anterior a p}
aux:=qA.d c ho;
qA.deho:=!);
qA.izdo:=pA.izdo;
pA.izdo:=q;
if qA.izdo =nil then
cab:=q
el se
qA.izdo A.dcho:=q;
p:=q;
q:=aux
end;
p:=P A.dcho
end
end;

procedure ordeneir (var el:ptro);


var
aux:ptro;
begin
if el<>nil then
begin
aux:=cl A.izdo ;
aux A.dcho :=nil;
cl A.izdo:=nil;
ordenar (el);
aux:=el;
while aux A.dcho <> nil do
aux:=aux A.deho;
auxA.dcho:=el;
elA.izdo:=aux
end
end;

PROBLEMA 6.2. Cadenas de caracteres mediante listas circulares

Dos cadenas de caracteres estn almacenadas en dos listas circulares. Se accede a di-
chas listas mediante los punteros Le 1, Le 2. Escribir un subprograma que devuelva la
direccin en la cadena Le 2 a partir de la cual se encuentra la cadena Lelo

Solucin

En primer lugar, se escribe una unidad que defina los tipos de datos necesarios y la
funcin que resuelve el supuesto planteado. A esta unidad se la puede aadir otros pro-
cedimientos o funciones para crear listas circulares, visualizarlas ...

unit Lista_ci
interface
type
Tinfo = ehar;
,"

,
,

Listas doblemente enlazadas 203

Ptrlc = ANodolc;
Nodolc= record
Info : Tinfo;
Sgte : Ptrle
endl
function Direccion(L c l, Le2:Ptrlc): Ptrle;
implementation
function Direeeion(Lel, Le2:Ptrlc): Ptrle;
var
A, A2, B: Ptrle; Sw:boolean;
bel1in
A := Lc2;
A2:= Le2;
B := Lel;
repeat
if AA.lnfo = BA.lnfo then
begin
A := AA.Sgte;Sw:=true; I
B := BA.Sgte
end
elee
bel1in
A2 :=A2 A .Sgte;A:=A2;
B := Lcl; Sw:=false
end
until (A = Lc 2 ) or (B=Lcl)and Sw;
if (B=Lel and Sw) then
Direeeion:= A2
elee
Direecion := nil
end;
end.
,
1

i"
,l
,

RESUMEN ,

l
1
1
,,
Las listas doblemente enlazadas son aquel tipo de lista que se puede recorrer avanzando en cual- ,

quiera de los sentidos.


Otro tipo de lista muy eficiente es la lista circular, que es, por naturaleza, la que no tiene
,
primero ni ltimo nodo.
Aunque una lista enlazada circularmente tiene ventajas sobre una lista lineal pero presenta
tambin algn inconveniente, como no poder recorrer la lista en sentido inverso. En estos casos la
lista idnea es una lista doblemente enlazada, en la que cada nodo de la lista contiene los punte-
ros, uno a su predecesor y otro a su sucesor.
Las listas doblemente enlazadas pueden ser o bien lineales o circulares y pueden o no conte-
,,
ner un nodo de cabecera.
Los nodos de una lista doblemente enlazada constan de tres campos: un campo in/o, que
contiene la informacin almacenada en el nodo, y los campos izquierdo y derecho, que contienen
punteros a los nodos de cada lado.
204 Estructura de datos

EJERCICIOS

6.1. Dibujar una lista doblemente enlazada, Ld, de nombres de personas con un nodo cabecera.
Escribir el procedimiento Lista_vaca que inicializa Ld como vaca.
6.2. Escribir la funcin Esvae ia que devuelve cierto si la lista Ld con nodo de encabezamien-
,
to es vaCla.
6.3. Dada la lista doble con nodo de encabezamiento Ld, escribir el procedimiento de insertar
un nodo antes del nodo de direccin P.
6.4. En la lista doble con nodo de encabezamiento borrar el nodo que tiene como campo de
informacin X.
6.S. Dada una lista doble sin nodo de encabezamiento cuya direccin de acceso Ld es el primer
nodo, la infoJlnacin de cada nodo es una cadena de caracteres; escribir un procedimiento
para visitar los nodos del primero (Ld) al ltimo, convirtiendo las cadenas a maysculas; a
continuacin visite los nodos del ltimo al primero (Ld) mostrando los nodos por pantalla.
6.6. Escribir un procedimiento que tenga como parmetro de entrada Le. Suponer que Le apun-
ta al primer nodo de una lista circular doblemente enlazada de caracteres. El procedi-
miento debe de escribir los caracteres de la lista Le en orden inverso, es decir, del ltimo al

pnmero.
c
La salida debe ser: R T J H
6.7. Hacer lo mismo que en el ejercicio 6.6 pero con una lista simplemente enlazada.

6.8. Dibujar una lista circular doblemente enlazada con nodo de cabecera. El nodo de cabecera
es tal que sus dos campos puntero referencian a los nodos extremos de la lista.

i
6.9. Dada la representacin de lista circular propuesta en 6.8, escribir las operaciones Lista_vaca
y la funcin Esvaca.
,"
,
,f 6.10. Con la representacin de lista circular de 6.8, escribir las operaciones de insertar como
,,! ltimo nodo e insertar como primer nodo.

6.11. Con la representacin de lista circular de 6.8, escribir la funcin de localizar el nodo con el
,
campo de informacin X y la operacin de eliminar el nodo con campo de informacin X.

PROBLEMAS
6.1. Dada una lista doblemente enlazada de nmeros enteros, escribir las rutinas necesarias para
que dicha lista est ordenada en orden creciente. La ordenacin se ha de hacer intercam-
biando los punteros a los nodos.
6.2. Tenemos una lista doblemente enlazada ordenada con claves repetidas. Realizar un proce-
dimiento de inserccin de una clave en la lista, de tal forma que si la clave ya se encuentra
en la lista la inserte al final de todas las que tienen la misma clave.
6.3. En una lista simplemente enlazada L se encuentran nombres de personas ordenados alfab-
ticamente. A partir de dicha lista L crear una lista doblemente enlazada LL de tal forma que
el puntero de comienzo de la lista est apuntando a la posicin central. Damos por supuesto
que la posicin central es el nodo que ocupa la posicin n/2, siendo n el nmero de nodos
de la lista. Obviamente, los nodos que se encuentran a la derecha de la posicin central
estn ordenados ascendentemente y los que se encuentran a la izquierda ordenados de ma-
nera decrecientemente.


Listas doblemente enlazadas 205

6.4. Dada una cadena de caracteres almacenada en una lista circular Le, escribir un subprogra-
ma que transforme la cadena Le de tal forma que no haya caracteres repetidos.
6.5. En el archivo LIBROS se encuentran almacenados los datos relativos a la biblitoeca
municipal de Lupiana. Los campos de que consta cada registro son: Autor, Ttulo, N-
mero de ejemplares. Escribir un programa que realice como primera accin formar una
lista doblemente enlazada ordenada respecto al campo Autor, cuya direccin de acceso
sea el nodo que ocupe la posicin central. Con la lista se podrn realizar estas otras opera-

ClOnes:

Mostrar todos los libros de un Autor.


Prestar un ejemplar de un libro, designado por Autor y Ttulo.
Aadir un nuevo libro a la lista.
Dar de baja a todos los libros de un autor.

Al finalizar el proceso deber guardarse en el archivo los libros actuales.

6.6. Escribir un programa para realizar operaciones con vectores dispersos. Un vector disperso
es aquel cuyo nmero de elementos es grande, sin embargo muchos de esos elementos son
cero. La representacin se ha de hacer mediante una lista doblemente enlazada. Cada nodo
de la lista ha de tener un elemento del vector distinto de cero junto al ndice del elemento.
El programa debe de permitir estas operaciones:

Dado un vector disperso, representarlo en una lista doble.


Dados dos vectores mediante sendas listas L 1, L2, obtener el vector suma L 1 + L2.
Podr haber nuevas posiciones que sean cero.
Dados dos vectores L 1, L 2, obtener el vector diferencia (L 1- L 2 ) . Tener en cuenta
que puede haber nuevas posiciones que sean cero.

6.7. El polinomio P(x) = ao + a IX + a2x2 +... + a,.x" deseamos representarlo en una lista circular
enlazada, de tal forma que cada nodo contenga el coeficiente y el grado de un monomio.
Escribir un programa que tenga como entrada los coeficientes y exponentes de cada trmi-
no de un polinomio, y forme una lista circular para representarlo. El puntero de acceso a la
lista circular ser el del nodo que contiene al tllnino de grado n, a partir de l se acceder
al tllnino de grado 0, y as sucesivamente. En el programa deben de encontrarse las opera-

ClOnes:

Evaluacin del polinomio para un valor dado de x.


Obtencin del polinomio derivada de P(x).
Obtencin del polinomio producto de dos polinomios.
6.8. Se desea sumar enteros muy largos utilizando listas circulares doblemente enlazadas. Es-
cribir una unidad donde se encuentren los tipos de datos y las operaciones para manejo de
listas circulares dobles. Escribir un programa que permita la entrada de enteros largos, rea-
lice la suma y los muestres por pantalla.
6.9. Escribir un programa para sumar enteros largos utilizando listas circulares con doble enla-
ce y un nodo de encabezamiento (segn se indica en los ejercicios 6,8,9, 10 Y 11). Previa-
mente escribir la unidad con tipos de datos y operaciones para manejo de listas circulares
con nodo de encabezamiento.
,
CAPITULO

pi a

CONTENIDO

7.1. Especificacin formal del tipo abstracto de datos Pila.


7.2. Implementacin del TAO pila con arrays.
7.3. Implementacin del TAO Pila mediante variables dinmicas.
7.4. Evaluacin de expresiones aritmticas mediante pilas.
RESUMEN.
EJERCICIOS.
PROBLEMAS.

Una pila es una estructura de datos en la que todas las inserciones y .


,!
eliminaciones de elementos se realizan por un extremo denominado
cima de la pila. Una analoga es una pila de platos o una pila de cajas.
La implementacin de una pila se puede realizar mediante arrays o
con punteros. El inconveniente de la implementacin de una pila con
un array es que su tamao mximo se debe especificar en tiempo de
compilacin. Para resolver este inconveniente, la implementacin de
una pila se ha de realizar con punteros (apuntadores).
El desarrollo de las pilas como tipos abstractos de datos es tam-
bin otro de los motivos centrales de este captulo. En el mismo se
ver cmo utilizar el TAD Pila para resolver problemas de diferentes
tipos.

,
7.1. ESPECIFICACION FORMAL DEL TIPO ABSTRACTO
DE DATOS PILA

Una pila es una lista ordenada de elementos en la que todas las inserciones y supresio-
nes se realizan por un mismo extremo de la lista. En una pila el ltimo elemento aadido
es el primero en salir de la pila. Por esa razn a las pilas, se las denomina tambin listas

207
208 Estructura de datos

Lifo (Last input jirst output, ltimo en entrar, primero en salir). En la mente se tiene la
imagen intuitiva de una pila. As, si nos referimos a una pila de platos, sabemos que los
platos se toman por arriba, por la cabeza. En la vida cotidiana se encuentran infini-
dad de ejemplos; as a veces se dice que apilamos los libros de un curso ...

Pila

Las pilas crecen y decrecen dinmicamente, es una estructura de datos dinmica. En


cuanto a la representacin de una pila utilizando las estructuras de datos que tiene el
lenguaje, existen varias formas. Al ser una pila una coleccin ordenada de elementos, y
ser los arrays tambin una coleccin ordenada de elementos se tiene una forma de repre-
sentar las pilas. En definitiva, una primera representacin se realiza mediante la estruc-
, .
tura estatlca array.
Una segunda forma de representar una pila es con listas enlazadas. Las listas crecen
y decrecen dinmicamente, al igual que ocurre en una pila. Es una representacin din-
mica que utiliza punteros y variables dinmicas. Las operaciones bsicas que definen el
TAO pi 1 a son las siguientes:

Pilavacia(P) Crea una pila sin elementos.


Esvacia(P) Devuelve verdadero si la pila P no tiene elementos.
Cima(P) Devuelve el elemento que est en la cima de la pila.
Suprime(P) Elimina el elemento que est en la cima de la pila.
Sacar(X,P) Devuelve el elemento cabeza y lo suprime.
Meter(X,P) Aade el elemento X en la pila.

7.2. I PLEMENTACIN DEL TAO PILA CON ARRAYS


Un array constituye el depsito de los elementos de la pila. El rango del array debe ser lo
suficientemente amplio para poder contener el mximo previsto de elementos de la pila.
Un extremo del array se considera el fondo de la pila, que permanecer fijo. La parte
Pilas: el TAD pi la 209

superior de la pila, cima, estar cambiando dinmicamente durante la ejecucin del pro-
grama. Adems del array, una variable entera nos sirve para tener en todo momento el
ndice del array que contiene el elemento cima. Las declaraciones, procedimientos y
funciones para representar el TAD pila forman parte de la unidad pilas.

const
Maxelems = 100; {Depender de cada realizacin}
type
Indicepila = O.. Maxelems;
Tipoelemen = ... {Tipo de los elementos de la pila}
Tipopila = record
Elementos: array[l .. Maxelemsl of Tipoelemen;
Cab: Indicepila
end;

En funcin de esta representacin se codifican las operaciones bsicas definidas en


TAD pi/a: Pi/avacia, Esvacia, Cima, Suprimir, Sacar, Meter y Pi/aliena.

Pilavacia(P)

procedure Pilavacia(var P: Tipopila);


begin
P.Cab:= o
end;

Esvacia(P)

function Esvacia(P: Tipopila): boolean;


begin
Esvacia:= P.Cab=O
end;

Cima(P)

Esta funcin devuelve el elemento cabeza de la pila, sin modificar la pila.

function Cima(P: Tipopila): Tipoelemen;


begin
if not Esvacia(P) then
cima := P.Elementos[P.Cabl
end;

Suprime(p)

Esta operacin elimina el elemento cabeza, modificando la pila.

procedure Suprime(var P: Tipopila);


begin
if not Esvacia(P) then
P.Cab:= P.Cab- 1
end;

210 Estructura de datos

Sacar(X, P)

Esta operacin devuelve el elemento cabeza y lo suprime.

procedure Sacar(var X:T ipoe 1emen; var P:Ti pop i1 a) ;


begin
if not Esvacia(P ) then
with P do
begin
X:= Ele me n t os [ CabJ ;
Cab : = Cab- 1
end
end;

Meter(X, P)

Esta operacin aade el elemento X a la pila. Cuando se aade un elemento se dice


que ste es empujado dentro de la pila.
Al estar representando la pila mediante una estructura esttica puede ocurrir que no
haya posiciones libres en el array. Por esta circunstancia se ha de incorporar una opera-
cin P 11 ena que devuelve verdadero si se ha alcanzado el nmero mximo de elemen-
tos previstos.

function P1 1ena(P : Tipop i1a): boo1ean ;


begin
P11ena := P.Cab=Maxe1ems
end;

procedure Meter(X: T ipo e1emen; var P: Tip opi1a) ;


begin
if not P11ena(P) then
with P do
begin
Ca b:= Cab+ 1;
E lementos[CabJ: = X
end
end;

1
,

PROBLEMA 7.1. Utilizacin de una pila

Se desea invertir una cadena de caracteres y se trata de determinar si han sido inverti-
dos correctamente dichos caracteres. Para ello se lee la cadena de caracteres; a conti-
nuacin, en la siguiente lnea los caracteres de la cadena invertidos.

La estrategia a seguir es sencilla, los caracteres de la cadena se almacenan en una


pila. Segn se van leyendo los caracteres de la cadena invertida se comparan con el
carcter cima de la pila; de este modo se aprovecha la principal caracterstica de una
Pilas: el TADPila 211

pila: ltimo en entrar primero en salir. El ltimo carcter introducido debe ser igual que
el primer carcter de la cadena invertida.

function Esinversa: boolean;


var
Ch: char;
Pila: Tipopila;
Inv: boolean;
begin
Pilavacia(Pila) ;
writeln ( 'Caracteres de la cadena: ');
repeat
read (Ch) ;
Meter(Ch, Pila)
until eoln;
readln;
{Los caracteres ledos son comparados con la pila}
Inv:= true;
while not Esvacia(Pila) and Inv do
begin
read (Ch) ; I
Inv:= Ch= Cima(Pila);
Suprimir(Pila)
end;
{Consideramos que si hay ms caracteres que en la pila, no ha
sido invertida correctamente}
Esinversa:= Inv and eoln;
readln
end;

Para sacar los elementos de la pila se puede seguir la alternativa de utilizar otra va-
riable carcter D y la operacin Sacar:
while not Esvacia(Pila) and Inv do
begin
read(Ch) ;
Sacar(D,Pila)
Inv:= Ch = D;
end;

7.3. IMPLEMENTACiN DEL TAO PILA DI ANTE VARIABLES


DINMICAS
La implementacin dinmica de una pila se hace almacenando los elementos como nodos
de una lista enlazada, con la particularidad de que siempre que se quiera meter (empu-
jar) un elemento se har por el mismo extremo que se extraer.
Esta realizacin tiene la ventaja de que el tamao se ajusta exactamente a los ele-
mentos de la pila. Sin embargo, para cada elemento es necesaria ms memoria, ya que
hay que guardar el campo de enlace. En la realizacin con arrays hay que establecer un
mximo de posibles elementos, aunque el acceso es ms rpido, ya que se hace con una
variable subindicada.
212 Estructura de datos

Pila

Los tipos de datos y operaciones en la realizacin con listas son muy similares a los
ya expuestos en listas enlazadas Pilavacia , Esvacia , Cima, Suprime , Sacar y Meter.

type
Ti poelemen= ... {Tipo d e los el emen tos de l a p i l a}
ptrp l a= ANo doPla;
Nodopla= record

Elemen t o : T i poeleme n;

Enl a ce : PtrP l a
, end;
I Pilavacia(crear pila)

Crea una pila sin elementos.

procedure Pil ava ci a( var Pila : Ptr p l a) ;


begin
,

Pi l a := n il
end;

Esvacia

Funcin que determina si la pila no tiene elementos.

function Esvacia(P il a : Pt rp l a) : boo l ea n;


begin
Esvac i a : = pil a= n i l
end;

Cima(Pila)

Devuelve el elemento cabeza de la pila, sin modificar la pila.


I
Pilas:elTADPila 213

, function Cima(Pila: Ptrp l a): Tipoel e men;


begin
if not Esvac i a( Pila) then
Cima := pi laA .El e me nt o
end;

Suprime (Pila)

Con esta operacin se elimina y libera el elemento cabeza, modificando la pila.

procedure Sup rim e( var Pil a : Pt rpl a) ;


var
Q : Ptrpla;
begin
, if not Esvac i a( Pi la ) then
begin
Q : = Pil a ;
p ila:= PilaA .Enla ce ;
d ispose (Q)
I,
end
end;

"'"

Pila

,
I

Sacar(X, pila)

Esta operacin engloba a las dos anteriores. Devuelve el elemento cabeza y lo su-

prime.
I
procedure Sacar( var X: Tipoe l eme n; var Pila : Ptrpla) ;
var
Q : P t rp la ;
I
214 Estructura de datos

begin
if not Esvacia(Pila) then
with pila A do
begin
Q:= Pila;
X:= Elemento;
pila:= Enlace;
dispose(Q)
end
end;

El procedimiento se puede escribir llamando a cima y Suprimir.

procedure Sacar(var X:Tipoelemen; var Pila: Ptrpla);


begin
X: = Cima ( pi 1 a) ;
Suprime(Pila)
end;

Meter(X, Pila)

Esta operacin aade el elemento X a la pila. En esta representacin con estructuras


dinmicas no tiene sentido la operacin pila llena, la pila crece o decrece segn lo nece-
sita.

----,
-- --
- --
--- -
Pila

nil

procedure Meter(X: Tipoelemen; var Pila: Ptrpla);


var
Q: Ptrpla;
begin
new(Q) ;
QA.Elemento:= X;
QA.Enlace:= Pila;
pila:= Q
end;
Pilas: el TAO pi l a 215

7.4. EVALUACiN DE EXPRESIONES ARITMTICAS


, MEDIANTE PILAS

Una de las aplicaciones ms tpicas del TAD pila es almacenar los caracteres de que
consta una expresin aritmtica con el fin de evaluar el valor numrico de dicha expre-
sin, Una expresin aritmtica est formada por operandos y operadores, As, la ex-
, ,
preslOn

R = X*Y - (A+B)

est escrita de la forma habitual: el operador en medio de los operando, Se conoce como
notacin infija, Conviene recordar que las operaciones tienen distintos niveles de prece-
dencia,

Par n t esis
() nivel mayor de prioridad
1\
Po t enc ia
Multip l / di v isi n : *, /
Suma / Resta
+, - nivel menor de prioridad

Tambin suponemos que a igualdad de precedencia son evaluados de izquierda a


derecha,

7.4.1. Notaciones Prefija (Polaca) y Postfija (Polaca inversa)


La forma habitual de escribir operaciones aritmticas es situar el operador entre sus dos
operandos con la citada notacin infija. Esta forma de notacin obliga en muchas oca-
siones a utilizar parntesis para indicar el orden de evaluacin,

A*B / (A+C) A * B/A + C

Representan distintas expresiones al no poner parntesis. Igual ocurre con las expre-

Slones:

La notacin en la que el operador se coloca delante de los dos operandos, notacin


prefija, se conoce como notacin polaca (en honor del matemtico polaco que la estudi),

A* B / (A+C) ( i nfija) --7 A* B / +AC --7 *AB / + AC --7 I*AB + AC (pol a c a )


A* B / A+C (infi j a) --7 * AB / A+C --7 I * ABA+C --7 + / *AB AC (po l aca)
(A - B) ~C +D ( i n f i j a) --7 - A B ~C + D --7 ~-ABC +D --7 + ~ - A BC D ( p o la c a)

Podemos observar que no es necesario la utilizacin de parntesis al escribir la ex-


presin en notacin polaca. La propiedad fundamental de la notacin polaca es que el
orden en que se van a realizar las operaciones est determinado por las posiciones de los
operadores y los operandos en la expresin.

l
,
..
216 Estructura de datos

Otra forma de escribir las operaciones es mediante la notacin postfija o polaca in-
versa que coloca el operador a continuacin de sus dos operandos.

A*B/ (A+C) (infija) ~ A*B/AC+ ~ AB*/AC+ ~ AB*AC+/ (polaca inversa)


A*B/A+C (infija) ~ AB*/A+C ~ AB*A/+C ~ AB*A/C+ (polaca inversa)
(A-B) AC+D (infija) ~ AB-AC+D ~ AB-CA+D ~ AB-CAD+ (polaca inversa)

7.4.2. Algoritmo para evaluacin de una expresin aritmtica


A la hora de evaluar una expresin aritmtica escrita, normalmente, en notacin infija la
computadora sigue dos pasos:
1.0 Transformar la expresin de infija a postfija.
2. Evaluar la expresin en postfija.
,
En el algoritmo para resolver cada paso es fundamental la utilizacin de pilas.
Se parte de una expresin en notacin infija que tiene operandos, operadores y pue-
de tener parntesis. Los operandos vienen representados por letras, los operadores
van a ser:
A (potenciacin), *, /, +, - .

La transformacin se realiza utilizando una pila en la que se almacenan los operado-


res y los parntesis izquierdos. La expresin se va leyendo carcter a carcter, los ope-
randos pasan directamente a formar parte de la expresin en postfija.
Los operadores se meten en la pila siempre que esta est vaca, o bien siempre que
tengan mayor prioridad que el operador cima de la pila (o bien igual si es la mxima
prioridad). Si la prioridad es menor o igual se saca el elemento cima de la pila y se
vuelve a hacer la comparacin con el nuevo elemento cima.
Los parntesis izquierdo siempre se meten en la pila con la mnima prioridad. Cuan-
do se lee un parntesis derecho, hay que sacar todos los operadores de la pila pasando a
formar parte de la expresin postfija, hasta llegar a un parntesis izquierdo, el cual se
elimina, ya que los parntesis no forman parte de la expresin postfija.
El algoritmo termina cuando no hay ms items de la expresin y la pila est vaca.
Sea por ejemplo la expresin infija A * (B + e - ( DIE F) - G) - H, la expresin en postfi-
A

ja se va ir formando con la siguiente secuencia:

Expresin Estado de la Pila


A Carcter A a la expresin; carcter * a la pila.
AB Carcter ( a la pila; carcter B a la expresin.
ABC Carcter + a la pila; carcter C a la expresin.
En este momento el estado de la pila es
+
(
* ,
Pilas: el TADpila 217

El nuevo carcter ledo es -, que tiene igual prioridad que el ele-


mento cima de la pila +; en consecuencia, el estado de la pila es:
-
(
*
y la expresin es:
ABC+
ABC+D Carcter ( a la pila; carcter D a la expresin.
ABC+DE Carcter / a la pila; carcter E a la expresin.
ABC+DEF Carcter /\ a la pila; carcter F a la expresin.
Carcter) (parntesis derecho) provoca vaciar la pila hasta un (.
La pila en este momento contiene
/\

/
(
-
(
*
El nuevo estado de la pila es

-
(
*
y la expresin
ABC+DEFAj
ABC+DEFAj- Carcter - a la pila y se extrae a su vez -;
ABC+DEFAj-G Carcter G a la expresin; carcter ), son extrados
de la pila los operadores hasta un ( la pila queda *
ABC+DEFAj-G-* Carcter -, se saca de la pila * y se mete -
ABC+DEFAj-G-*H Carcter H se lleva a la expresin
Fin de entrada, se vaca la pila:
ABC+DEFAj-G-*H-

En la descripcin realizada se observa que el parntesis izquierdo tiene la mxima


prioridad fuera de la pila, es decir, en la notacin infija; sin embargo, cuando est dentro
de la pila la prioridad es mnima. De igual forma, para tratar el hecho de que varios
operadores de potenciacin son evaluados de derecha a izquierda, este operador tendr
mayor prioridad cuando todava no est metido en la pila que el mismo pero metido en la
pila. Las prioridades son determinadas segn esta tabla:
.,
,
218 Estructura de datos

,Prlodaaa.aelltroplJa . Prioridad fuera pila


!Operador

/\
3 4
*, I 2 2
+, - 1 1 ,

( O 5
,
,
,
I
Obsrvese que no se trata el parntesis derecho ya que ste provoca sacar operadores 1
de la pila hasta el parntesis izquierdo. El algoritmo de paso de notacin infija a postfija: I,
,,l
l. Obtener caracteres de la expresin y repetir los pasos 2 al 4 para cada carcter.
I,

2. Si es operando, pasarlo a la expresin postfija.


-1
3. Si es operador:
1
3.1. Si pila est vaca, meterlo en la pila. Repetir a partir de 1.

3.2. Si la pila no est vaca:


Si la prioridad del operador ledo es mayor que la prioridad del operador 1
1
cima de la pila, meterlo en la pila y repetir a partir de 1.
1
Si la prioridad del operador es menor o igual que la prioridad del opera- !I
dor de la cima, sacar cima de la pila y pasarlo a la expresin postfija, vol- ,
,
'J
ver a 3. 1
I
4. Si es parntesis derecho: 1,,
,
I
4.1. Sacar cima de pila y pasarlo a postfija. ,,
1
'o!

4.2. Si nueva cima es parntesis izquierdo, suprimir elemento cima. :


~
j
4.3. Si cima no es parntesis izquierdo, volver a 4.1. 1
.,,,
4.4. Volver a partir de 1. j,
5. Si quedan elementos en la pila pasarlos a la expresin postfija. 1

6. Fin del algoritmo.

, , ,
7.5. APLlCACION PRACTICA
, DE LA
, EVALUACION I,
J
DE UNA EXPRESION ARITMETICA :
,I
,
,,
,
,
,

Los tipos de datos, procedimientos y funciones utilizados para codificar el algoritmo


,,
.;

tratado en el apartado anterior se realiza en las unidades Pilaop y ExpPost. .,,

7.5.1. Unidad Pilaop


La unidad pi 1 aop contiene los tipos bsicos para el manejo de las pilas, as como sus

operaciones asociadas.
unit pilaop;
interface
type
Plaopr = ANodopr;
Nodopr= record
Pilas:elTADPila 219

Info: char;
Sgte: Plaopr
end;

function Pvacia(P: Plaopr ): boolean;


procedure Pcrear(var P: Plaopr);
procedure Pmeter(Ch: char; var P: Plaopr);
procedure Psacar(var Ch: char; var P: Plaopr);
function Pcima(P:Plaopr) :char; {devuelve el elemento cima de la pila}
procedure Pborrar(var P: Plaopr);

implementation

function Pvacia(P: Plaopr): boolean;


begin
Pvacia:= P=nil
end;

procedure Pcrear(var P: Plaopr);


begin
P:=nil
end;

procedure Pmeter(Ch: char; var P: Plaopr);


var
A: Plaopr;
begin
new(A) ;
A~.Info := Ch;
A~.Sgte := p;
P := A
end;

procedure Psacar(var Ch: char; var P: Plaopr);


begin
Ch:= Pcima(P);
Pborrar(P)
end;

function Pcima(P:Plaopr) :char; {devuelve elemento cima de la pila}


begin
if not Pvacia(P) then
Pcima:= P~.Info
end;

procedure Pborrar(var P: Plaopr );


var
A: Plaopr ;
begin
if not Pvacia(P) then
begin
A: =P;
P:=P~.Sgte;

dispose(A)
end;
end;
end.
1,I
,,

j
222 Estructura de datos I
,!
I
Psacar(It, P); j
un ti l I t = ' ( , ; 1
.~

end;
end;
repeat
Psacar(It, P);
J:= J+l;
Ar [J] . e : = 1 t ;
Ar[J] .oprdor:= true;
until Pvacia(P); l,

end; {del procedure} iI
end.
.,i
j
,
7.5.3. Evaluacin de la expresin en postfija ,.:
,,

En un vector ha sido almacenada la expresin aritmtica en notacin postfija. Los ope-
randos estn representados por variables de una sola letra. La primera accin que va a
ser realizada es dar valores numricos a los operandos.
Una vez que tenemos los valores de los operandos la expresin es evaluada. El algo-
ritmo de evaluacin utiliza una pila de operandos, en definitiva de nmeros reales. Al
describir el algoritmo P f es el vector que contiene la expresin. El nmero de elementos
de que consta la expresin es n.

l. Examinar P f desde el elemento 1 hasta el n. Repetir los pasos 2 y 3 para cada


elemento de P f .
2. Si el elemento es un operando meterlo en la pila.
3. Si el elemento es un operador, lo designamos con &, entonces:
Sacar los dos elementos superiores de la pila, los llamamos X e Y, respectivamente.
Evaluar y & X, el resultado es Z = y & X.
El resultado Z, meterlo en la pila.
Repetir a partir del paso 1.
4. El resultado de la evaluacin de la expresin est en el elemento cima de la pila.
5. Fin del algoritmo.

Codificacin de evaluacin de expresin en postfija


Las operaciones para manejar la pila de operandos estn encapsuladas en la unidad
Pilaopdos. Los nombres de las operaciones han sido cambiados para distinguirlos de la unidad
Pilaop. La parte de implementation es la misma, por ello nos limitaremos a escribir la interfaz.

unit Pilaopdos;
interface
type
Plaopdos = ANodopdos;
Nodopdos=record
Info: real;
Sgte: Plaopdos
end;
Pilas:elTADPila 223

function Povacia(P: Plaopdos ): boolean;


procedure Pocrear(var P: Plaopdos );
procedure Pometer(var P: Plaopdos ;eh: char);
procedure Posacar(var P: Plaopdos ;var eh: char);
function Pocima(P: Plaopdo s): char;
{devuelve el elemento cima d e la pila}
procedure Poborrar(var P: Plaopdos );
{Fin de la seccin de interface. La seccin implementation es igual que
en la unidad Pilaop}

Ahora ya se puede escribir el programa completo que realiza todo el proceso. El


programa Eval ua_Expresion utiliza las unidades Crt, ExpPos t y pi laOpdos;
contiene el procedimiento Leer_oprdos que lee el valor numrico de los operandos,
as como el procedimiento Eva 1 ua que implementa el algoritmos de evaluacin.

program Evalua_Expresion;
uses
ert, ExpPost, Pilaopdos;
var
v: Oprdos;
T: Tag;
1, J:integer;
Valor: real;
procedure Leer_oprdos(E:Tag;N:integer; var V: Oprdos);
{En este procedimiento se asignan valores numricos a los operandos}
var
K: integer;
eh: char;
begin
K:= O;
repeat
K:= K+l;
if not E[K] .Oprdor then {Es un operando, peticin de su valor
numrico}
begin
Ch:= E[K] .e;
write(Ch, '- ');
readln (V[Ch])
end
until K=N
end

procedure Evalua(Pf: Tag; N: integer;


Oper: Oprdos; Var Valor: real);
var
Pila: Plaopdos;
1: integer;
Numl, Num2: real;
Op: char;
begin
1 := O;
Pocrear (Pila);
repeat
1:=1+1
224 Estructura de datos

if not Pf[1] .Oprdor then


Pometer(Oper[Pf [1] .C], Pila)
else if Pf[I] . Oprdor then
begin
Posacar(Num2, Pila);
Posacar(Numl, Pila);
case Pf [1].C of
,A, :Valor:= Exp(Numl*Ln(Num2)) {Potencia}
, * , : Valor: = Numl *Num2;
' / ' :Valor:= Numl / Num2;
'+' :Valor:= Numl+Num2;
'-' : Valor:= Numl-Num 2
end;
Pometer(Valor, Pila)
end;
until 1= N
end;
begin
c lrscr;
writeln( 'Expresin aritmtica(termina # ) ' ) ;
Postfija(T, J);
writeln( 'Asignacin de valores numric os a los operandos');
writeln ;
Leer_oprdos (T, J, V);
Evalua(T, J, V, Va lor);
writeln;
write('Resultado de evaluacin de la expresin: " Valor);
end.

RESU N

Una pila es una estructura de datos tipo UFO (last-in-first-out, ltimo en entrar/primero en salir)
en la que los datos se insertan y eliminan por el mismo extremo, que se denomina cima de la pila.
El proceso de insercin se denomina meter o poner y el de eliminacin se denomina extraer,
quitar o sacar.
Aadir un elemento a una pila se llama operacin meter o poner (push) y eliminar un ele-
mento de una pila es la operacin extraer, quitar o sacar (pop).
El intento de poner un elemento en una pila llena produce un error conocido como desborda-
miento de la pila (s tack overf low). El intento de sacar un elemento de una pila vaca produ-
ce un error conocido como desbordamiento negativo de la pila (s tack underf low).
Una pila puede ser implementada mediante un array o mediante una lista enlazada. Una ven-
taja de una implementacin de una pila mediante una lista enlazada sobre un array es que, con la
lista enlazada no existe lmite previo en el nmero de elementos o entradas que se pueden aadir
a la pila.
Las llamadas a procedimientos recursivos se implementan utilizando una pila (de hecho, to- .
das las llamadas a procedimientos, sean o no recursivas, se implementan utilizando una pila).
El TAO Pi la, al igual que eITAO Lis ta y TAO Cola son, posiblemente, los tipos abstrac-
tos de datos ms utilizados en la gestin de proyectos software, dado que la estructura tipo pila es
muy frecuente en numerosos problemas de tratamiento de infolluacin, as como en problemas
matemticos, estadsticos o financieros. Por ejemplo, se puede utilizar una pila para determinar si
Pilas: el TAO pila 225

una secuencia de vuelos existe entre dos ciudades. La pila mantiene la secuencia de ciudades
visitadas y permite a un algoritmo de bsqueda volver hacia atrs. Para ello se sita la ciudad
origen en la parte inferior de la pila, y la ciudad destino en la parte superior, con lo que las suce-
sivas ciudades de trnsito se van colocando en la secuencia correcta.

EJERCICIOS
7.1. Se desea implementar el TAD pila de tal forma que los elementos de la pila sean almacena-
dos en una lista circular. El puntero externo a la lista apunta al elemento cabeza. Escribir
las operaciones de meter, cima, suprimir y esvacia.
7.2. Supongamos que estarnos trabajando en un lenguaje de programacin que no tiene el tipo
de dato puntero. Se plantea la resolucin de un problema utilizando dos pilas de nmeros
reales. Las dos pilas se quiere guardar en un nico array, de tal forma que crecen en sentido
contrario, una de ellas crece desde la posicin l del array y la otra desde la ltima posicin
del array. Escribir la estrategia a seguir para esta representacin, variables necesarias para
contener la posicin del elemento cabeza de ambas pilas.
7.3. Dada la representacin de dos pilas propuesta en 7.2, escribir el algoritmo de la operacin
Crea pi la (Pi lal, Pi la2) que inicializan ambas pilas corno pila vaca. De igual for-
ma escribir las funciones Esvac ial y Esvac ia2 que determinan si las respectivas pi lal
y pi la 2 estn vacas.
7.4. Completar las operaciones de las pilas propuestas en 7.2: Meterl, Meter2 y Supri-
mel, Suprime2. En las operaciones hay que tener en cuenta condiciones de error.
7.5. Utilizando una pila de caracteres, hacer un seguimiento para transformar la siguiente ex-
presin infija a su equivalente expresin en postfija.
E: (X-Y)/Z*W+(Y-Z)"V
7.6. Aplicando el algoritmo de evaluacin de una expresin, obtenga el resultado de las si-
guientes expresiones escritas en postfija .
XY+Z-YX+Z I\-
XYZ+*ZYX-+*
paraX=l, Y=3, Z =2

PROBLEMAS

7.1. Escribir un programa para determinar si frases (cadenas) son palndromos. Utilizar para
ello el TAD pila de caracteres realizado en una unidad. La entrada de datos son las frases y
la salida la propia frase junto a la etiqueta ES PALNDROMO, o bien NO ES PALN -
DRoMo .
. 7.2. Escribir un programa que convierta expresiones escritas en notacin infija (forma habitual)
a notacin postfija. Cada expresin se encuentra en una lnea, el programa ha de terminar
cuando la lnea conste de 3 asteriscos.
7.3. Escribir un programa que convierta expresiones escritas en notacin postfija a notacin
infija. Cada expresin se encuentra en una lnea, el programa ha de terminar cuando la lnea
conste de 3 asteriscos.
226 Estructura de datos

7.4. Escribir un programa que convierta expresiones escritas en notacin postfija a notacin
prefija. Cada expresin se encuentra en una lnea, el programa ha de terminar cuando la
lnea conste de 3 asteriscos.
7.5. Un mapa de carreteras podemos representarlo mediante la matriz simtrica MM de N x N
elementos enteros, donde los valores 1 a N representan los pueblos/ciudades que aparecen
en el mapa.
Los elementos de la matriz son tales que MM(i,j) = O si no hay conexin directa entre el
pueblo i y el pueblo j. MM(i,j) = d si hay conexin directa entre el pueblo i y el pueblo j, y
su distancia es d.
Con esta representacin del mapa queremos escribir un programa que simule el mapa des-
crito y que tenga como entrada dos pueblos (origen, destino) entre los que no hay conexin
directa; decida si hay un camino que pase por los pueblos del mapa y determine la distancia
de ese camino. Utilizar una pila para ir almacenando los pueblos que van formando el ca-
mino recorrido y poder volver atrs si se alcanza un pueblo desde el que no se puede prose-
guir la ruta, y probar con otra ruta.
7.6. Utilizando nicamente las operaciones bsicas sobre pilas: Met er, Cima, Supr ime y
Esvacia, construir las operaciones que realicen las siguientes acciones:
a) Asignar a X el segundo elemento desde la parte superior de la pila, dejando la pila sin
sus dos elementos de la parte superior.
b) Asignar a X el segundo elemento desde la parte superior de la pila, sin modificarla.

e) Dado un entero positivo n, asignar aX el n-simo elemento desde la parte superior de la
pila, dejando la pila sin sus n elementos de la parte superior.
d) Dado un entero positivo n, asignar aX el n-simo elemento desde la parte superior de la
pila, sin modificarla.
e) Asignar a X el elemento fondo de la pila, dejando la pila vaca.
j) Asignar a X el elemento fondo de la pila, sin modificarla. 1
1
7.7. Utilizando las operaciones del TAD pila, escribir una operacin de copia, tal que devuelva 1,,
,,
la copia de una pila. I
7.8. Escribir una funcin para determinar si una secuencia de caracteres de entrada es de la I

fOllna: ,;,
X & Y

Donde X es una cadena de caracteres, e Y es la cadena inversa, siendo & el carcter sepa-
rador.
7.9. Escribir una funcin para determinar si una secuencia de caracteres de entrada es de la
forma:
A#B#C# ...

Donde cada una de las cadenas A, B, e ... son de la forma X & Y, que a su vez estarn
separadas por el carcter #.
,
CAPITULO


..,,0 as CO as e rlO
e CO a
.' ,
,', '" ..
,': ,. .. , ' , .... . ' ' . . '

CONTENIDO

8.1. Especificacin formal del tipo abstracto de datos cola.


8.2. Implementacin del TAD cola con arrays lineales.
8.3. Implementacin del TAD cola con arrays circulares.
8.4. Implementacin del TAD cola con listas enlazadas.
8.5. Implementacin del TAD cola con listas circulares.
8.6. Bicolas.
8.7. Colas de prioridades.
8.8. Implementacin de colas de prioridades.
8.9. Un problema complejo resuelto con colas de prioridades.
8.10. Problema: Suma de enteros grandes.
RESUMEN.
EJERCICIOS.
PROBLEMAS.

El concepto de cola es uno de los que ms abundan en la vida cotidia-


na. Espectadores esperando en la taquilla de un cine o de un campo de
ftbol; clientes de un supermercado esperando la compra de un artcu-
lo comercial; etc. En una aplicacin informtica, una cola es una lista
en la que todas las inserciones a la lista se realizan por un extremo, y
todas las eliminaciones o supresiones de la lista se realizan por el otro
extremo.
Las colas se llaman tambin estructuras FIFO (jirst-in, first-ont;
primero en entrar, primero en salir). Las aplicaciones de las colas son
numerosas en el mundo de la computacin: colas de las tareas a reali-
zar por una impresora, acceso a almacenamiento de disco, o incluso,
en sistemas de tiempo compartido, el uso de la UCP (Unidad Central
de Proceso). En el captulo se examinan las operaciones bsicas de
manipulacin de los tipos de datos cola.

227
228 Estructura de datos

,
8.1. ESPECIFICACION FORMAL DEL TIPO ABSTRACTO
DE DATOS COLA

Una cola es una lista ordenada de elementos, en la cual las eliminaciones se realizan en
un solo extremo, llamado frente o principio de la cola, y los nuevos elementos son aa-
didos por el otro extremo, llamado fondo o jinal de la cola. La Figura 8.1 muestra una
estructura cola en una organizacin original (a) y sus modificaciones (b y e) despus de
eliminar y aadir un elemento de modo sucesivo.
En esta estructura de datos el primer elemento que entra es el primero en salir. Por
esta causa a las colas tambin se les llama listas FIFO (jirst input jirst output). Las
operaciones bsicas que definen la especificacin del TAD cola son:

Qcrear(Q) Crea la cola Q como cola vaca.


Qvacia(Q) Nos devuelve cierto si la cola est vaca.
Frente(Q) Devuelve el elemento frente de la cola.
Qborrar(Q) Elimina el elemento frente de la cola.
Qanula(Q) Convierte la cola en vaca.
Quitar(X,Q) Elimina y devuelve el frente de la cola.
Qponer(X,Q) Aade un nuevo elemento a la cola.

a) Estructura original

AGHK

frente final

b) Estructura despus de eliminar un elemento

GHK

frente final

e) Estructura despus de aadir un elemento

GHKL

frente final

Figura 8.1. Una estructura de datos tipo cola.


Colas y colas de prioridades: el TAO cola 229

Al igual que las pilas, la implementacin de colas puede hacerse utilizando como
depsito de los elementos un array o bien una lista enlazada y dos punteros a los
extremos.

8.2. IMPLEMENTACiN DEL TAD COLA CON ARRAYS LINEALES


La forma ms sencilla de representacin de una cola es mediante arrays lineales. Se
utiliza como depsito de los elementos de la cola un array unidimensional cuyo tipo es
el mismo que el tipo de los elementos de la cola. Son necesarios dos ndices para refe-
renciar al elemento frente y al elemento final. El array y las dos variables ndice se agru-
pan en el tipo registro de nombre cola.
const
Max = 100;
type
Tipoelemen ~
II definicin del tipo de elemento
I

posicion= O.. Max;


Cola= record
Datos: array[l .. Max] of Tipoelemen;
Frente,
Final: posicion
end;
var Q:Cola;

Un array es una estructura esttica y por tanto tiene dimensin finita; por el contra-
rio, una cola puede crecer y crecer sin lmite, y en consecuencia se puede presentar la
posibilidad de que se presente un desbordamiento. Por esa razn dentro de las operacio-
nes de este TAD se incorpora, normalmente, la operacin de verificacin de que la cola
est llena.
La operacin de aadir un nuevo elemento en la cola comienza a partir de la posicin
1 del array
1 234

AGHK
t t
frente final

Supongamos que la cola se encuentra en la situacin anterior: el frente est fijo y el


final de la cola es el que se mueve al aadir nuevos elementos. Si ahora se quita un
elemento (evidentemente por el frente) la cola queda as:

123 4

GHK Se ha dejado un hueco no uti-


lizable, por lo que se desapro-
t t vecha memoria.
frente final
230 Estructura de datos

Una alternativa a esta situacin es mantener fijo el frente de la cola al comienzo del
array; este hecho supone mover todos los elementos de la cola una posicin cada vez
que se quiera retirar un elemento de la cola.
Estos problemas quedan resueltos con los arrays circulares que se describen ms
adelante. Las operaciones ms importantes incluidas en la especificacin de una cola
con esta representacin son: Crear, Cola Vacia, ColaLlena , A adir y Quitar.

Crear (Qcrear(Q
La operacin Qcrear inicializa la cola como cola vaca.
procedure Qc r ear( var Q : Co l a) ;
begin
Q.Frente := 1;
Q.Fina l := O;
end;

Cola vaca (Qvacia(Q


La operacin Qva e i a devuelve verdadero si la cola no tiene elementos.
function Qva cia(Q : Co la) : boolean ;
begin
Qvacia : = Q .Fina1 < Q . Fre n te
end;

Cola llena (Qllena(Q


La operacin Q 11 e na devuelve verdadero si en la cola no pueden aadirse ms elementos.
function Qllena( Q: Cola) : boo lean;
begin
Qll e na := Q.Fi nal = Max
end

Aadir (Qponer(X,Q
Aade el elemento X a la cola. Se modifica la cola por el extremo final.
procedure Qponer(X : T i poe l e me n; var Q: Co l a) ;
begin
if not Ql l e na(Q) then
with Q do
begin
Final:= Final+ 1 ;
Dat os [Final]: = X
end
end;

Quitar (Quitar(X,Q
Elimina y devuelve el frente de la cola.
procedure Qu i tar( var x : T i poe l emen ; var Q: Cola) ;
procedure Desplazar ;
var l: posi cion ;
Colas y colas de prioridades: el TAO cola 231

begin
for I :~l to Q . F i nal - l do
Q . Da t o s [ 1 J : ~ Q . Da t o s [ 1 + 1 J
end;
begin
X: = Q .Datos[F rent e l ;
Despl azar
end;

,
8.3. IMPLEMENTACION DEL TAD COLA CON ARRAYS
CIRCULARES
La implementacin de colas mediante un array lineal es poco eficiente. Cada operacin
de supresin de un elemento supone mover todos los elementos restantes de la cola.
Para evitar este gasto, imagnese un array como una estructura circular en la que al
ltimo elemento le sigue el primero. Esta representacin implica que aun estando ocupa- '
do el ltimo elemento del array, pueda aadirse uno nuevo detrs de l, ocupando la
primera posicin del array.
Para aadir un elemento a la cola, se mueve el ndice final una posicin en el sentido de
las manecillas del reloj, y se asigna el elemento. Para suprimir un elemento es suficiente
con mover el ndice frente una posicin en el sentido del avance de las manecillas del
reloj. De esta manera, la cola se mueve en un mismo sentido, tanto si se realizan inser-
ciones como supresiones de elementos.
Segn se puede observar en la representacin, la condicin de cola vaca [fren-
te = siguiente (final)] va a coincidir con una cola que ocupa el crculo completo, una
cola que llene todo el array.
Para resolver el problema, una primera tentativa sera considerar que el elemento
final referencie a una posicin adelantada a la que realmente ocupa el elemento, en el
sentido del avance del reloj.

n 1 2

4 ,
Final/"
~Frente
---
" - -,

~*-
_o,
::...-
0_. _

I~-------vr--------~I
i ~Frente
Cola

Figura 8.2. Arrays circulares.


232 Estructura de datos

Final-----n~'{...2
n 1

p S B p 2....--Final


3

A
4
'Frente
T

i ~Frente
Figura 8.3. Evolucin de arrays circulares.

Teniendo presente esta consideracin cuando la cola estuviera llena, el ndice si-
guiente a final ser igual al frente.
Consideremos ahora el caso en que queda un solo elemento en la cola. Si en estas
condiciones se suprime el elemento, la cola queda vaca, el puntero Frente avanza una
posicin en el sentido de las manecillas del reloj y va a referenciar a la misma posicin
que el siguiente al puntero Final. Es decir, est exactamente en la misma posicin rela-
tiva que ocupara si la cola estuviera llena.
Una solucin a este problema es sacrificar un elemento del array y dejar que Final
referencie a la posicin realmente ocupada por el ltimo elemento aadido. Si el array
tiene long posiciones, no se debe dejar que la cola crezca ms que long-lo

n 1 n 1

B p 2 2
/Frente
u
W 3 Final W 3

A
4
~ Frente

Figura 8.4. Insercin de nuevos Figura 8.5. Supresin de un


elementos en un array circular. elemento en un array circular.
Colas y colas de prioridades: el TAO cola 233

Segn lo expuesto anteriormente, las declaraciones necesarias para especificar el tipo


cola son:
const
Long - . .. ,
type
Tipoelemen - r
posicion= O .. Long;
Cola= record
Elementos: array[l .. long] of Tipoelemen;
Frente,
Final: Posicion
end;

Las operaciones definidas en el TAD cola con esta representacin de array circular
son: Siguiente, Crear, Cola Vacia, CalaLlena, Frente, Borrar y Quitar.

Siguiente(J)
La funcin Si gu i en te ( J) obtiene la posicin siguiente a J en el sentido circular de
avance, segn las manecillas del reloj.
function Siguiente(J: integer): integer;
begin
Siguiente:= (J mod Long) +1
end;

Crear(Q)
La operacin de crear inicializa los ndices de la cola de tal manera que la condicin
de cola vaca aplicada sobre la cola creada sea cierta.
procedure Qcrear(var Q: Cola);
begin
Q.Frente:= 1;
Q.Final:= Long;
end;

,
Cola VaCl.a

La operacin Qva c i a devuelve verdadero si la cola no tiene elementos.


function Qvacia(Q: Cola): boo1ean;
begin
Qvacia:= Siguiente(Q.Final)= Q.Frente
end;

Cola llena
La operacin Q 11 ena devuelve verdadero si en la cola no pueden aadirse ms ele-
mentos, es decir, si estn ocupadas Long-l posiciones del array.
234 Estructura de datos

function Qllen a(Q : Co l a ) : bool ean ;


begin
Ql l e na := Sig u ie n te (Sig u i e n te(Q .F i n a l ) )= Q . F r e nt e
end; i

Frente (Frente(Q
function Frente (Q : Co l a ) : Ti poe l e men;
begin
if not Qvacia (Q) then
Fr ente := Q . El e men tos [Q . F ren t e ]
end;

Borrar (Qborrar(Q
Esta operacin modifica la cola, elimina el elemento frente de la cola.
procedure Qborr ar( var Q: Co l a ) ;
begin 1

if not Qvacia (Q) then 1
l
Q . Fren te:= Q . Fr e nt e+ l
end;
i
Quitar (Quitar(X, Q 1
1
Elimina y devuelve el frente de la cola. En realidad esta operacin es un compendio de
las operaciones F rente y Qborrar.
procedure Quita r( var x: T i poeleme n; var Q : Col a );
,
,
begin
X : = F rente(Q);
Qb o rra r(Q)
end;

n ~--Final

e 2

3
-Frente
Q
4

o
p
5
6

Figura 8.6. Llenado del array circular.


;

Colas y colas de prioridades: el TAV cola 235

Qponer(X, Q)
Aade el elemento X a la cola. Se modifica la cola por el extremo final.

procedure Qp oner(X : Ti poel eme n; var Q: Cola) ;


begin
if not Qllena (Q) then
with Q do
begin
I Fina l:= S i guiente(F inal);
,

Elementos [ Final] : = X
end
end;

,
8.4. IMPLEMENTACION DEL TAD COLA CON LISTAS
ENLAZADAS

Como ocurre con toda representacin esttica, una de las principales desventajas es que
hay que prever un mximo de elementos, de ese mximo no podemos pasamos. La rea-
lizacin de una cola mediante una lista enlazada permite ajustarse exactamente al nme-
ro de elementos de la cola.
Esta implementacin con listas enlazadas utiliza dos punteros para acceder a la lista.
El puntero Frente y el puntero Final.

Frente Final

H K M "'---1 T nil

Figura 8.7. Cola implementada con lista enlazada.

I
El puntero Frente referencia al primer elemento que va a ser retirado. El puntero
Final referencia al ltimo nodo que fue aadido, en definitiva, al ltimo que ser retira-
do (1 i s t a F i f o). En esta representacin no tiene sentido la operacin que determina
si una cola est llena (Ql le na). Al ser una estructura dinmica crece y decrece segn
las necesidades. Las declaraciones para la representacin de cola mediante listas:

type
Tipoelemen - ... ;
Ptr n odoq = ANodoq ;
Nodoq= record
I nEo : Tipoe l eme n;
Sgte : Pt rnodoq
end;
Cola= record
Fr e n te ,
Final :Pt rnodoq
end;
,
236 Estructura de datos

Las operaciones definidas en la especificacin del tipo en esta estructura son: Crear,
Cola Vaca, Frente, Borrar, Quitar y Poner.
Crear (Qcrear(Q
La operacin Qcr ear inicializa la cola como Cola vaCa.
procedure Qcrea r(var Q : Cola) ;
begin
Q . Frente := nil ;
Q.Fina l:= nil
end;
,
Cola vac1a (Qvacia(Q) )
La operacin Qvacia devuelve verdadero si la cola no tiene elemento.
function Qva c i a(Q : Cola) : boolea n;
begin
Qvacia := Q.Fr ente= n i l
end;

Frente (Frente (Q) )


Devuelve el elemento Frente de la cola.
function F r e n te(Q : Co l a) : Tipoe l e me n;
begin
if not Qvacia(Q) then
Frente := Q . Fren t e A. lnfo
end;

Borrar (Qborrar(Q
Esta operacin modifica la cola, elimina el elemento frente de la cola y es liberado.
procedure Qb o r rar( var Q : Cola) ;
var
A : Ptrnodoq ;
begin
if not Qvac i a(Q) then
with Q do
begin
A : = F re n te ;
Frente := F renteA . Sgte ;
,,
if Frente = nil Then ,
F inal:= nil;

d i s pose(A)
end
end;

Quitar (Quitar(X,Q
Elimina y devuelve el frente de la cola.
procedure Quitar( var X : Tipoele me n; var Q : Co l a);
begin
X : = Fren t e (Q) ;
Qborrar(Q)
end;
Colas y colas de prioridades: el TAO cola 237

Poner (Qponer(X,Q

Aade el elemento X a la cola. Este elemento se aade como ltimo nodo, por lo que se
modifica la cola al cambiar Final.

function Crear (X:Tipoelemen): Ptrnodoq;


var T:Ptrnodoq;
begin
new(T); T~.rnfo:= x; T~.Sgte:= nil
Crear:= T
end;

procedure Qponer(X: Tipoelemen; var Q: Cola);


var
N: Ptrnodoq;
begin
N:= Crear(X); {Crea nodo con campo X, devuelve su direccin}
with Q do
begin
if Qvacia(Q) then
Frente:= N;
elee
Final~.Sgte:= N;
Final:= N
end
end;

8.5. I PLE NTACIN DEL TAD COLA CON LISTAS


CIRCULARES

Esta implementacin es una variante de la realizacin con listas enlazadas. Al realizar


una lista circular se estableci, por convenencia, que el puntero de acceso a la lista refe-
renciaba al ltimo nodo, y que el nodo siguiente se considera el primero. Segn este
convenio y teniendo en cuenta la definicin de cola, las inserciones de nuevos elementos
de la cola sern realizados por el nodo referenciado por Le, y la eliminacin por el nodo
siguiente. Las declaraciones de tipos para esta representacin:

type
Tipoelemen - . . . ,
Cola= ~Nodoq;
Nodoq= record
rnfo: Tipoelemen;
Sgte: Cola
end;

Las operaciones son similares a las realizadas con listas enlazadas: Crear, Cola Va-
cia, Frente, Borrar, Quitar y Poner. El puntero necesario para realizar inserciones y
supresiones es el mismo: Q. Teniendo en cuenta que Q referencia al ltimo (Final)
y Q"'. Sgte al primero (Frente).
238 Estructura de datos

Le
~

Figura 8.8. Cola implementada con una lista circular con punteros.

Crear (Crear(Q
procedure Qcrear(var Q: Cola);
begin
Q:= nil;
end;

,
Cola vaC1a (Qvacia(Q
function Qvacia(Q: Cola): boolean;
begin
Qvacia:= Q= nil
end;

Frente(Q)
function Frente(Q: Cola): Tipoelemen;
begin
if not Qvacia(Q) then
Frente:= Q.SgteA.lnfo
end;

Qborrar(Q)
procedure Qborrar(var Q: Cola);
var
A: Cola;
begin
if not Qvacia(Q) then
begin
A:= QA.Sgte;
if QA.Sgte= Q then
Q:=nil;
else
QA.Sgte:=QA.SgteA.Sgte;
dispose(A)
end
end;
Colas y colas de prioridades: el TAO cola 239

Quitar(X, Q)
I

procedure Quita r (var x:Tipoelemen; var Q:Cola);


begin
X : = Frente (Q) ;
Qborra r(Q )
end;

Qponer(X, Q)
procedure Qponer(x: Tipoelemen; var Q: Co l a) ;
var
N: Col a;
begin
new(N) ;NA.Inf o : =X;NA.Sgte:=N;{Crea n o do co n campo xl
, if not Qvacia(Q) then
begin
NA. Sgte : = QA .S gte ;
QA . Sgt e: = N
end
Q : = N;
end;

8.6. BleOlAS
Una variacin del tipo de datos cola es la estructura bicola. Una bicola es un conjunto
ordinal de elementos en el cual se pueden aadir o quitar elementos de cualquier extre-
mo de la misma. Es, en realidad, una cola bidireccional.
Los dos extremos de una bicola los llamaremos Izquierdo y Derecho, respec-
tivamente. Las operaciones bsicas que definen una bicola son:
,
Cre arB q (Bq) : inicializa una bicola sin elementos.
Esvaci a (Bq) : devuelve verdadero si la bicola no tiene elementos.
Inserlzq (x, Bq ) : aade un elemento por extremo izquierdo.
InserDch (x , Bq) : aade un elemento por extremo derecho.
i Elimnlzq (x, Bq) : devuelve el elemento Izquierdo y lo tetira de la bicola.
Eli mnD ch (x , Bq) : devuelve el elemento Derecho y lo retira de la bicola.
Para representar una bicola se puede elegir una representacin esttica, con arrays, o
bien una representacin dinmica, con punteros.
En la representacin dinmica, la mejor opcin es mantener la bicola con una lista
doblemente enlazada: los dos extremos de la lista se representan con las variables punte-
ro 1 zquierdo y Derecho, respectivamente.
En la representacin esttica se mantienen los elementos de la bicola con un array
circular y dos variables ndice del extremo izquierdo y derecho, respectivamente.
Al tipo de datos bicola se pueden imponer restricciones respecto al tipo de entrada o
al tipo de salida. Una bicola con restriccin de entrada es aquella que slo permite in-
serciones por uno de los dos extremos, pero pel mite la eliminacin por los dos extremos.
Una bicola con restriccin de salida es aquella que permite inserciones por los dos ex-
tremos, pero slo permite retirar elementos por un extremo.
,
,

i,
240 Estructura de datos

Frente: 3
LUZ AGUA RIO
Final: 5
1 2 3 4 5 6 7 8

Al aadirse el elemento SOL por el frente

Frente: 2
SOL LUZ AGUA RIO
Final: 5
1 2 3 4 5 6 7 8

Puede eliminarse por el final

Frente: 2
SOL LUZ AGUA
Final: 4
1 2 3 4 5 6 7 8

Figura 8.9. Estructura tipo Bicola.

PROBLEMA 8.1

El estacionamiento de las avionetas de un aerdromo es en lnea, con una capacidad


hasta 12 avionetas. Las avionetas llegan por el extremo izquierdo y salen por el extremo
derecho. Cuando llega un piloto a recoger su avioneta, si sta no est justamente en el
extremo de salida (derecho), todas las avionetas a su derecha han de ser retiradas,
sacar la suya y las retiradas colocadas de nuevo en el mismo orden relativo en que
estaban. La salida de una avioneta supone que las dems se muevan hacia adelante, de
tal forma que los espacios libres del estacionamiento estn en la parte izquierda.
El programa para emular este estacionamiento tiene como entrada un carcter que
indica una accin sobre la avioneta, y la matrcula de la avioneta. La accin puede ser,
llegada (E) o salida (S) de avioneta. En la llegada puede ocurrir que el estacionamiento
est lleno, si es as la avioneta espera hasta que se quede una plaza libre, o hasta que se
d la orden de retirada (salida).

Anlisis
El estacionamiento va a estar representado por una bicola de salida restringida. Por
qu? La salida siempre se hace por el mismo extremo, sin embargo la entrada se puede
hacer por los dos extremos, y as contemplar la llegada de una avioneta nueva, y que
tenga que entrar una avioneta que ha sido movida para que salga una intermedia. La
lnea de espera para entrada de una avioneta (estacionamiento lleno) se representa por
una bicola a la que se aaden avionetas por un extremo, salen para entrar en el estacio-
Colas y colas de prioridades: el TAO cola 241

namiento por el otro extremo, aunque pueden retirarse en cualquier momento si as lo


decide el piloto; en este caso puede ocurrir que haya que retirar las avionetas que tiene
delante, o bien si es la ltima retirarla por ese extremo.
Las avionetas que se mueven para poder retirar del estacionamiento una intermedia
se disponen en una lista L i f o; as la ltima en entrar ser la primera en aadirse en el
extremo salida del estacionamiento y seguir en el mismo orden relativo.
La unidad 1 i f o (p i 1 a) se describe slo con in ter fa c e ya que su implentacin
se ha escrito anteriormente. En la unidad bicola se implementan las operaciones de una
bicola, la representacin con array circular, adems se incorpora la operacin que da las
plazas libres que hay en el estacionamiento. La restriccin de salida se refleja en que no
es vlida la operacin Rem_en t (retirada por el extremo de salida).
unit Lifo;
interface
type
Avioneta=string[15]; {En realidad sera un registro con ms campos
identificativos}
PtrPila =AItemp;
Itemp = record
Info: Avioneta;
Sgte: PtrPila
end;
procedure Pilavacia(var Pila: PtrPila);
function Pvacia (Pila: PtrPila): boolean;
procedure Pmeter(X: Avioneta; var Pila: PtrPila);
procedure Pcima(var X: Avioneta; Pila: PtrPila);
procedure Pborrar(var Pila: PtrPila);
procedure Psacar(var X: Avioneta; var Pila: PtrPila);
{Fin de la seccin de interfaz}

La unidad Bi colas utiliza la lista Li f o:

unit Bicolas;
interface
uses Lifo;
const
Long = 13;
type
Avioneta = string [15] ;
posicion= o .. Long;
Bicola= record
Elementos: array[l .. long] of Tipoelemen;
Salida,
Entrada: posicion
end;
procedure CrearBq (var Bq: BiCola);
function Esvacia(Bq: BiCola): boolean;
function EsLLena(Bq: BiCola): boolean;
procedure InsEntrada(A:Avioneta;var Bq:Bicola);
procedure InsSalida(A:Avioneta;var Bq:Bicola);
procedure EliEntrada(var A:Avioneta;var Bq:Bicola);
procedure EliSalida(var A:Avioneta;var Bq:Bicola);
!
Colas y colas de prioridades: el TAO cola 243

procedure In s Entrada(A:Avioneta; var Bq:Bicola);


begin
if not EsLLena(Bq) then
with Bq do
begin
Entrada:= Siguiente(Entrada) ;
Elementos [Entrada) := A
end
end;

procedure InsSalida(A:Avioneta;var Bq:Bicola);


begin
if not EsLLena(Bq) then
with Bq do
begin
Sa lida:= Anterior(Salida);
Elementos [Salida) := A
end
end;

procedure EliEntrada(var A:Avioneta;var Bq:Bicola);


,i
begin

if not Esvacia(Bq) then


begin
A:=BQ.Elementos[Bq.Entrada);
Bq.Entrada:= Anterior[Bq.Entrada)
end
end;

procedure EliSalida(var A:Avioneta;var Bq:Bicola);


begin
if not Esvacia(Bq) then
begin
A:=BQ.Elementos[Bq.Salida) ;
, Bq.Entrada:= Siguiente[Bq.Salida)
end
end;

procedure Retirar(A:Avioneta;var Bq:Bic ol a;var Ok:boolean);


{Esta operac in retira una avioneta. O bien por un extremo, o bien
intermedia}
var
i D: integer;
I
Pl:Ptrpila;
begin
D:=Posicion(A ,Bq) ;
Ok:=true;
if D<> O then
if D=Bq.Salida then
EliSalida (A, Bq)
!. e1ee begin
Pilavacia(Pl) ;
(Se sacan elementos intermedios, desde Salida hasta D)
repeat
Elisalida(A,Bq) ;
Pmeter(A,Pl) ;

I
244 Estructura de datos

until Bq.Sa l ida=D;


Elisalida ( A,Bq); (es retir ado el elemento pedido)
(Son intr odu cid os los el e mentos saca dos)
repeat
Psacar(A,Pl ) ;
In sSalida(A ,Bq )
until Pva c ia(Pl)
end
else
Ok:=fa l se ; {No est la avi o n et a}
end;
{fin de la unidad bi co l a }
end.

Por ltimo, el programa que emula el estacionamiento es Avionetas.


program Avionetas(input,output);
uses c rt,Lif o ,Bic o la ;
var
u: Avi on eta;
Ch : char ;
Bq : Bicola;
Bqw: Bi co la; {Bi co la de espera de e n trada en estacionamiento}
Sw: boolea n;
begin
clrsc r ;
CrearBq (Bq) ; Crear Bq ( Bqw);
write ( 'La entrada inter a ctiva, son lneas con un cha r y ');
writeln( 'nm ero matr icu la:E( l legada) , S(S al ida) ' ) ;
repeat
repeat
read(Ch) ; Ch := upcase(Ch)
until Ch in[ 'E', ' S ' J ;
re adl n (U) ;
if Ch = 'E' then
if not Esl lena (Bq) then
InsEnt rada (U,B q)
el se
En s Entrada(U,Bqw); {se aade a b i co la d e espe ra}
el se {re t irada de avio ne tas}
Reti rar (U ,Bq,Sw)
Until n ot Sw
end.

8.7. COLAS DE PRIORIDADES


El trmino cola sugiere la forma en que esperan ciertas personas u objetos la utilizacin
de un determinado servicio. Por otro lado, el trmino prioridad sugiere que el servicio
no se proporciona nicamente aplicando el concepto de cola (el primero en llegar es el
primero en ser atendido) sino que cada persona tiene asociada una prioridad basada en
un criterio objetivo.
Un ejemplo tpico de organizacin formando colas de prioridades, es el sistema
de tiempo compartido necesario para mantener un conjunto de procesos que esperan

Colas y colas de prioridades: el TAD cola 245

servicio para trabajar. Los diseadores de estos sistemas asignan cierta prioridad a cada
proceso.
El orden en que los elementos son procesados y por tanto eliminados sigue estas
reglas:

l. Se elige la lista de elementos que tienen la mayor prioridad.


2. En la lista de may or prioridad, los elementos se procesan segn el orden de
llegada; en definitiva, segn la organizacin de una cola: primero en llegar,
primero en ser procesado.

Las colas de prioridades pueden implementarse de dos formas: mediante una nica
lista o bien mediante una lista de colas.

8.8. IMPLE ENTACIN DE COLAS DE PRIORIDADES

Para realizar la representacin, se define en primer lugar el tipo de dato que representa
un proceso.

type
Ti po_i d en tif = ... {Tipo de l i d e ntif icado r d el p r oceso}
Ti po_ proceso = record
Idt: Tipo_ i d e nt i f;
Prio ri dad : int eger
end;

8.8.1. Implementacin mediante una nica lista


Cada proceso forma un nodo de la lista enlazada. La lista se mantiene ordenada por el
campo prioridad.
La operacin de aadir un nuevo nodo hay que hacerla siguiendo este criterio:
La posicin de insercin es tal que la nueva lista ha de permanecer ordenada. A igual-
dad de prioridad se aade como ltimo en el grupo de nodos de igual prioridad. De
esta manera la lista queda organizada de tal forma que un nodo X precede a un
nodo y si:

l. Prioridad(X) > Prioridad(Y).


2. Ambos tienen la misma prioridad, pero X se aadi antes que Y.

Cp
41 P1 I ~ 1P21 ~I P31 r.lp21 I ~lp221 r. ... -.1 Pn I I
Figura 8.10. Cola de prioridad con una lista enlazada .


246 Estructura de datos

Los nmeros de prioridad tienen el significado habitual: a menor nmero mayor prio-
ridad. Esta realizacin presenta como principal ventaja que es inmediato determinar el
siguiente nodo a procesar: siempre ser el primero de la lista. Sin embargo, aadir un
nuevo elemento supone encontrar la posicin de insercin dentro de la lista, segn el
criterio expuesto anteriormente.

8.8.2. Implementacin mediante una lista de n colas


Se utiliza una cola separada para cada nivel de prioridad. Cada cola puede representarse
con un array circular, mediante una lista enlazada, o bien mediante una lista circular, en
cualquier caso con su Frente y Final. Para agrupar todas las colas, se utiliza un array de
registros. Cada registro representa un nivel de prioridad, y tiene el frente y el final de la
cola correspondiente. La razn para utilizar un array radica en que los niveles de priori-
dad son establecidos de antemano.
La definicin de los tipos de datos para esta realizacin:
const
Max_prior= ... ; {Mximo nmero de prioridades previsto}
type
Tipo_identif= ... {Tipo del identificador del proce so}
Tipo_proceso= record
Idt: Tipo_identif;
Prioridad: integer;
end;
Ptrnodoq= ANodoq;
No doq= record
info: Tipo_pro ceso ;
sgte : Ptrnodoq
end;

Cp

1 P1 Q1 Ip11 P12 P1KI

2 P2 Q2 Ip21 P2K I

n Pn Qn IPn1 PnK I

Figura 8.11. Cola de prioridad con n colas .

Colas y colas de prioridades: el TAO cola 247

Cola = record
Numpr i dad : in teger ;
fr e n t e ,
f ina l: Pt rn o do q
end;
Tabl a_cp = array[ l .. Max_p ri orl of Co la;

El tipo Ta bl a_c p es el que define la lista de colas y cada cola representa una prio-
ridad. Las acciones ms importantes al manejar una cola de prioridades son las de aadir
un nuevo elemento, con una determinada prioridad al sistema, y la accin de retirar un
elemento para su procesamiento. Estas acciones se expresan en forma algortmica en la
realizacin de n colas, como se muestra a continuacin.

Algoritmo para aadir nuevo elemento


Aade un elemento P que tiene un nmero de prioridad m.
l. Buscar el ndice en la tabla correspondiente a la prioridad m.
2. Si existe y es K, poner el elemento P como final de la cola de ndice K.
3. Si no existe, crear nueva cola y poner en ella el elemento P.
4. Salir.

Algoritmo para retirar un elemento


Retira el elemento de frente de la cola que tiene mxima prioridad.
1. Buscar el ndice de la cola de mayor prioridad no vaca. Cola k.
2. Retirar y procesar el elemento frente de la cola k.
3. Salir.

8.9. IMPLEMENTACiN DE UN PROBLEMA CON COLAS


DE PRIORIDADES

El objetivo del supuesto planteado es emular un sistema simple de procesamiento en


tiempo compartido. Para ello, van a generarse tareas aleatoriamente con un nmero de
prioridad de 1 a 8.
La simulacin se va a realizar hasta que hayan sido finalizadas un nmero detenni-
nado de tareas (Ma x _pr oc ). Adems, cada vez que el sistema retira una tarea, sta se
procesa en su totalidad.
La cadencia es: por cada tarea procesada llegan al sistema dos nuevas tareas, as
hasta completar el proceso del mximo de tareas previstas.
La realizacin es con un sistema de n colas. En la unidad col a s estn encapsuladas
las operaciones de manejo de colas, los tipos de datos y los procedimientos para aadir
y eliminar una tarea cuyos algoritmos se han expuesto anteriormente.
Colas y colas de prioridades: el TAO cola 249

begin
new(A) ;
AA.lnfo:=X;
AA.Sgte:=nil;
if Qvacia(Q) then
Q.Frente:= A
elBe
Q.FinalA.Sgte:=A;
Q.Final:= A
end;

procedure Qborrar(var Q: Colap);


var
A:Ptrnodoq;
begin
if (not Qvacia(Q) )then
begin
A:=Q.Frente;
Q.Frente:=Q.FrenteA.Sgte;
dispose(A)
end
end;

procedure Quitar (var X: Tipo_proc; var Q:Colap);


begin
if (not Qvacia(Q)) then
X:= Q.FrenteA.lnfo;
Qborrar(Q)
end;

procedure CrearQP (var Tcp:Tablacolas;Max_prior:integer);


var
i:integer;
begin
for i:=l to Max_prior do
begin
Qcrear(Tcp[i]) ;
Tcp [i] . Prd: = o
end
end;

function Nurncola(P: integer; var Tcp:tablacolas): integer;


{Busca cola de prioridad P; Si no Existe devuelve la siguiente libre.
Todas ocupadas, devuelve O}
var
J: integer;
Sw: boolean;
begin
Sw:= false;
J:= O;
while (J < Max_prior) and not Sw do
begin
J:= J+l;
Sw:= (Tcp[J] .Prd= P) or (Tcp[J] .Prd= O)
end;
if Sw then
250 Estructura de datos

Nu mcola := J
elee
Numco l a := o
end;

function Qmaxp ri (var Tcp : tab l ac olas): int eger ;


{Bu sca cola de mx ima prioridad . si toda s las t a r eas e stn pro cesadas
devuelve Ol
var
J ,K: i n teger;
M: integer ;
begin
J: = O;
K : = O;
M: = Ma x_pr ior + 1 ; { valor de arra n que }
while J< Max_prior do
if not Qvac ia(Tcp [ J ] ) and (Tcp [ J] . Prd< M) then
begin
K:= J;
M:= Tcp[J]. P r d
end;
Qma x pr i:= K
end;

procedure pr esentar _ proc ( T : Co l aQp) ;


{ Es t e p r oce d im i en t o mue s t ra en pa n talla la tarea que va a ser procesada }
begin
if LL = O then
clrscr ;
LL : = LL+1
write (T.Frent eA . lnfo .T area ) ;
Write ln( 'Prio ri da d :', T.FrenteA.Info.P rior) ;
if (LL mod 24) = O then
begin
de la y(1000) ;
c l rsc r
end
end;

procedure g e nerar _ proc( var Tcp : Tablacolas ; j : i nteger);


var
N : integer;
X : Tipo_proc;
function Tarea(K: integer) : St ring[20];
conet
Nt = 9 ;
Tareas = array [ l .. Max_ prior ] of string [ 20] -
( 'RSET ' , ' COPIAR ', 'ENLAZAR ',
'L E ER DISCO ', ' COMP I LAR ' , ' HWAX ' ,
, EJECUTAT ' , ' ES TA T ' , ' TMTAX ' ) ;
begin
if K i n [1 .. Max_ prior ] then
Tarea := Tar eas [ K]
end;
Colas y colas de prioridades: el TAO cola 251

begin
N := random( Nt) + 1 ; {Tarea al azar}
X .Ta rea : = Ta rea(N );
N := random(Max _ prio) + 1 ; {Prioridad al azar}
X. P rior:= N;
{Busca de Nmero de cola de prioridad}
N := Nu mco la(X. Pr ior);
if N= O then
begin
writeln( ' Overf l ow en tabla de colas ' ) ;
ha lt( l )
end;
Tcp[N ] . P rd : = X . Prior ;
Qponer(X , T cp[N])
writ eln( ' S E GENERA TAR EA N Q : ' , J)
end;

procedure procesar _ proc (var Tcp:Tablaco l as ; var En co : boolea n );


var
1 : i ntege r;
begin
1 : = Qmaxpri(Tcp) ; {Co l a de mayor pr i oridad}
En c o : = 1<>0 ;
if 1 <> O then
begin
p resenta r_proc( T cp [ l ] ) ;
borrar (Tcp [ 1 ] )
end
end;
begin
LL : = O; {Para presentar ta r eas procesadas }
end.

Codificacin del programa de gestin de colas de prioridades

program Co l asdeprior i dades ;


uses
u nit co l a , c rt;
var
Tab l aq : Tab l aco l as;
1, J : in t eger;
Hm: boole a n ;
C : char ;
begin
ra n domi ze ;
CrearQp (Tablaq , max_ prio r ) ;
{El b ucl e se real iza max_proc * 3 di v 2 ite raci one s par a que
se generen Ma x _proc tareas . Por cada tare a p r ocesada , se
genera n dos n u evas}
J : =O ;
for i:= 1 to (Ma x_p roc*3 di v 2) do
if i mod 3 = O then
procesar_ proc (Tablaq , Hm)
252 Estructura de datos

else begin
J:= J + 1;
generar_pr o c (Tablaq,j);
end;
repeat
pr o ce s ar_pr oc (Tablaq, Hm);
until not Hm
end.

PROBLEMA 8.2

En un archivo de texto F estn almacenados nmeros enteros arbitrariamente grandes.


La disposicin es tal, que hay un nmero entero por cada lnea de F. Escribir un progra-
ma que muestre por pantalla la suma de todos los nmeros enteros. Nota: Al resolver el
problema habr que tener en cuenta que al ser enteros grandes no pueden almacenarse
en variables numricas.

Anlisis
Partimos de que los nmeros estn dispuestos de tal forma que hay uno por lnea. El
objetivo es obtener la suma de todos estos nmeros y mostrarlo por pantalla.
Para leer los nmeros, los hacemos dgito a dgito (como caracteres).
Esta lectura capta los dgitos de mayor peso a menor peso; como la suma se realiza
en orden inverso, guardamos los dgitos en una pila de caracteres. As, el ltimo dgito
que entra (la unidad) es el primero en salir.
A partir de este hecho, podemos seguir dos estrategias:

Tener un array de enteros, de un mximo nmero de elemento establecido


(n = 250, por ejemplo). La suma se hace dgito a dgito, y guardando el resulta-
do en la misma posicin del array. Esto es, sacando de la pila y sumado el dgito
con el entero almacenado en la posicin n del array; en la siguiente iteracin se
saca de la pila y se suma con la posicin n - 1 del array, y as sucesivamente hasta
que la pila est vaca. En cada iteracin hay que guardar un posible acarreo.
La alternativa descrita tiene el inconveniente de que hay que establecer un
mximo de elementos del array, pudiendo ocurrir que nos quedemos cortos.
Otra estrategia consiste en sustituir el array de enteros por una lista enlazada.
Ahora se saca un dgito de la pila y se suma con el primer elemento metido en la
lista y con el acarreo. El dgito resultante se almacena en una nueva lista, a partir
del ltimo dgito insertado. En definitiva, es el tpico tratamiento de una lista fifo.
Con esta fOlma de proceder, cada vez que se accede a la lista para sumar dgito
hay que liberar el correspondiente nodo.

Esta alternativa nos peIlnite que no haya ningn tipo de restriccin en cuanto al n-
mero de dgitos. Como contrapartida, el proceso es ms lento, hay que realizar muchas
operaciones de creacin y liberacin de nodos.
Colas y colas de prioridades: el TAO cola 253

El programa que presentamos sigue la segunda alternativa. Para ello utilizamos dos
unidades, la unidad de manejo de pilas y la unidad de manejo de listas fifo. Presentamos
nicamente la seccin de interface de pila, la codificacin puede verse en las diversas
realizaciones de pilas escritas en el captulo anterior.

Codificacin de la unidad Pila



unit Pil a ;
interface
type
T ipoele m = c har ;
Ptr Pi l a =Altemp;
Itemp = record
I n f o : T i poelem;
Sgte : P t rP il a
end

procedure Pilava cia( var Pil a : PtrP ila);


function Pvaci a(P il a: PtrPi la) : boo lea n ;
procedure Pm e ter(X : Tipoelem; var P i la : Pt r Pila) ;
procedure Pc ima( var X: Ti poe l e m; Pi l a : Ptr Pila) ;
procedure Pbo rr ar( var Pi l a : PtrP il a) ;
procedure Ps a car( var X: T i poelem ; var Pila : PtrPila) ;
{Fin de la secci n de i nter faz}

Codificacin de la unidad Colas


unit Lf ifo ;
interface
type
T ipoi nf o - in teger ;
Ptrnodoq =ANodoc;
Nodoc = record
In f o : T i p o inf o ;
Sgte : Pt rn odoq
end;
Col a = record
F r en t e ,
F i na l: Pt r nodoq
end;

procedure Qc re ar(var C : Cola);


function Qvacia (C : Co l a ): b oolea n;
procedure Qpone r(X : T i p oinf o ; var C :Col a) ;
procedure Qbo r rar( var C : Cola) ;
function Fre n te(C : Co l a) : T ipoi n fo ;
procedure Qu ita r (var X : Tipoi n fo ; var C : Co l a) ;
implementation

procedure Qcrea r ;
begin
C . Frente := ni l ;
C .F inal : = nil
end;

)
~

254 Estructura de datos

function Qvacia;
begin
Qvacia := (C .Fren te - nil)
end;

procedure Qponer;
var
A: pt rno d.,q;
begin

new (A) ;
AA.lnfo ..-- X,
AA.Sgte := nil;
if Qvacia(C) then
C.Frente := A
else
C. Final A.Sg te := A;
C .Final:= A
end;

procedure Qborrar;
var
A:Ptrnodoq;
begin
if (not Qvacia(C) )then
begin
A := C.Frente;
C. Frente : = C.FrenteA.Sgte;
dispose(A)
end
end

function Frente;
begin
if (not Qvacia(C)) then
Frente := C.FrenteA.lnfo
end

procedure Quitar;
begin
X : = Frent e (C) ;
Qborra r(C)
end;
begin
end.

Codificacin completa del programa de gestin


program NurnerosGrandes(output, Dat os) ;
uses
Crt, P ila , Lfif o ;
var
Datos: text;
pla : Ptrpil a ;
Lfo : Cola;
-----------------------------..

256 Estructura de datos

if not Qvacia(Lfo) then


Qu i tar(52, L fo);
5 2 : = 51 +52 +R;
R : = 52 div 10;
52 := 52 mod 10 ;
Qp o n er (5 2, Nq )
end;
while not Qvac i a( L fo) do
begin
Quit a r(52 , L fo) ;
52 := 52+R ;
R := 52 d i v 10 ;
52 := S2 mod 1 0 ;
Qponer(S2 , Nq)
end;
if R <> O then Qpo ner (R , Nq ) ;
L f o : = Nq
end;

procedure Escribir(Q : Cola) ;


var
N : integ er;
begin
if not Qvacia (Q) then
begin
Qu i t ar (N, Q) ;
Esc ri b ir (Q) ;
write(N)
end
end;

begin
Abrir(Datos) ;
Qcrear( Lf o);
while not eo f (Dat os) do
begin
Leer n u mero(Datos , P l a);
Su ma r(Pl a, L fo)
end;
if not Qvacia(L f o) then
begin
wri teln( ' Res u l t ado d e l a suma d e n me r os gr an des ');
Esc ri b i r(L f o)
end
end.

RESUMEN
El proceso de insercin de datos se denomina acolar (enquering) y el proceso de eliminacin se
llama desacolar (dequering).
Una cola es una estructura de datos del tipo FIFO (jirst-in, first-out , primero en entrar, prime-
ro en salir); tiene dos extremos: una cola, donde se insertan los nuevos elementos, y una cabecera
o frontal , de la que se borran o eliminan los elementos.
Colas y colas de prioridades: el TAO cola 257

El tipo abstracto de datos cola se suele implementar mediante listas enlazadas por las mismas
razones que en el caso de las pilas: facilidad para gestionar el tamao variable o dinmico frente
al caso del tamao fijo.
Numerosos modelos de sistemas del mundo real, tanto fsicos como lgicos, son del tipo cola;
tal es el caso de la cola de trabajos de impresin en un servidor de impresoras, la cola de priorida-
des en viajes, programas de simulacin o sistemas operativos. Una cola es el sistema tpico que se
suele utilizar como buffer de datos, cuando se envan datos desde un componente rpido de una
computadora (memoria) a un componente lento (por ejemplo, una impresora).
Cuando se implementa una pila, slo se necesita mantener el control de una entrada de la
lista, mientras que en el caso de una cola, se requiere el control de los dos extremos de la lista.
Una cola de prioridad se puede implementar como un array de colas ordinarias o una lista
enlazada de colas ordinarias.

EJERCICIOS

8.1. Se ha estudiado en el captulo la realizacin de una cola mediante un array circular; una
variante a esta representacin es aquella en la que se tiene una variable que tiene la posi-
cin del elemento Frente y otra variable con la longitud de la cola (nmero de elementos),
LongCo 1 a, y el array considerado circular. Dibujar una cola vaca; aadir a la cola
6 elemento; extraer de la cola tres elementos; aadir elementos hasta que haya over f low.
En todas las representaciones escribir los valores de Frente y LongCola.
8.2. Con la realizacin de 8.1 escribir las operaciones de Cola: Qcrear, Qvacia, Qponer,
Frente y Qborrar.
8.3. Con la realizacin de una cola descrita en 8.1,2 consideremos una cola de caracteres. El
array consta de 7 posiciones. Los campos Frente, LongCola actuales y el contenido de
la cola:
Frente = 2 LongCola = 3 Cola: J, K, M
Escribir los campos Frente, LongCola y la Cola segn se vayan realizando las si-
guientes operaciones:
a) Se aaden los elementos F, J, G a la cola.
b) Se eliminan dos elementos de la cola.
e) Se aade el elemento A a la cola.
d) Se eliminan dos elementos de la cola.
e) Se aaden los elementos B, C, W a la cola.
f) Se aade el elemento R a la cola.
8.4. La realizacin de una cola mediante un array circular sacrifica un elemento del array; esto
se puede evitar aadiendo un nuevo campo a la representacin: Vac io de tipo lgico.
Escribir una unidad en la que se defina el tipo de datos y se implementen las operaciones de
manejo de colas.
8.5. Considere la siguiente cola de nombres, representada por un array circular con 6 posicio-
nes, los campos Frente, Final y Vacio:
Frente= 2, Final= 4, Vacio= Falso Cola: ,Mar,Sella,Licor,
Escribir el contenido de la cola y sus campos segn se realizan estas operaciones:
1,
,

258 Estructura de datos

a) Aadir Folk y Reus a la cola,


b) Extraer de la cola.
e) Aadir Kilo.
d) Aadir Horche a la cola.
e) Extraer todos los elementos de la cola.

8.6. Una bicola con restriccin de entrada slo permite insercciones por uno de sus extremos,
permitiendo extraer elementos por cualquier extremo. Definir e implementar las operacio-
nes para este tipo de datos.
8.7. Una bicola con restriccin de salida slo permite extraer elementos por uno de sus extre-
mos, permitiendo insertar elementos por cualquier extremo. Definir e implementar las ope-
raciones para este tipo de datos.
8.8. Consideremos una bicola de caracteres representada en un array circular. El array consta de
9 posiciones. Los extremos actuales y el contenido de la bicola:
Izquierdo = 5 Derecho = 7 Bieola: A, e, E
Escribir los extremos y la bicola segn se vayan realizando las siguientes operaciones:
a) Se aaden los elementos F, J a la derecha de la bicola.
b) Se aaden los elementos R, W, V a la izquierda de la bicola.
e) Se aade el elemento M a la derecha de la bicola.
d) Se eliminan dos letras a la izquierda.
e) Se aaden los elementos K, L a la derecha de la bicola.
f) Se aade el elemento S a la izquierda de la bicola.

PROBLEMAS
8.1. Con un archivo de texto se quieren realizar estas acciones: formar una lista enlazada, de tal
forma que en cada nodo est la direccin de una cola que contiene todas las palabras del
archivo que empiezan por una misma letra. Una vez formada esta estructura, se desea vi-
sualizar las palabras del archivo, empezando por la cola que contiene aquellas palabras que
empiezan por la letra a, luego las de la letra b, y as sucesivamente.
8.2. Una empresa de reparto de propaganda contrata a sus trabajadores por das. Cada repartidor
puede trabajar varios das continuados o alternos. Los datos de los repartidores se almace-
nan en una lista simplemente enlazada. El programa a desarrollar contempla los siguientes
puntos:
Crear una estructura de cola para recoger en ella el nmero de la seguridad social de
cada repartidor y la entidad anunciada en la propaganda para un nico da de trabajo.
Actualizar la lista citada anteriormente (que ya existe con contenido) a partir de los
datos de la cola.
La informacin de la lista es la siguiente: nmero de seguridad social, nombre y total de
das trabajados. Adems, est ordenada por el nmero de la seguridad social. Si el trabaja-
dor no est incluido en la lista debe aadirse a la misma de tal manera que siga ordenada.
8.3. En un archivo de texto se quiere determinar todas las frases que son palndromo. Para ello
se sigue la siguiente estrategia: aadir cada carcter de la frase a una pila y a la vez a una
cola. La extraccin de caracteres simultnea de ambas y su comparacin determina si la
Colas y colas de prioridades: el TAD cola 259

frase es o no palndromo. Escribir un programa para determinar todas las frases palndromo
del archivo de texto. Considerar que cada lnea de texto es una frase.
8.4. En un archivo de texto se encuentran los n;sultados de una competicin de tiro al plato, de
tal forma que en cada lnea se encuentra Apellido, Nombre, nmero de dorsal y nmero de
platos rotos. Se desea escribir un programa que lea el archivo de la competicin y determi-
ne los tres primeros. La salida ha de ser los tres ganadores y a continuacin los concursan-
tes en el orden en que aparecen en el archivo (utilizar la estructura cola).
8.5. El despegue de aeronaves en un aeropuerto se realiza siguiendo el orden establecido por
una cola de prioridades. Hay 5 prioridades establecidas segn el destino de la aeronave.
Destinos de menos de 500 km tienen la mxima prioridad, prioridad 1, entre 500 y 800 km
prioridad 2, entre 800 y 1.000 km prioridad 3, entre 1.000 y 1.350 km prioridad 4 y para
mayores distancias prioridad 5. Cuando una aeronave recibe cierta seal se coloca en la
cola que le corresponde y empieza a contar el tiempo de espera. Los despegues se realizan
cada 6 minutos segn el orden establecido en las distintas colas de prioridad. El piloto de
una aeronave puede pasar el aviso a control de que tiene un problema, y no puede despegar
por lo que pasa al final de la cola y se da la orden de despegue a la siguiente aeronave.
Puede darse la circunstancia de que una aeronave lleve ms de 20 minutos esperando, en
ese caso pasar a formar parte de la siguiente cola de prioridad y su tiempo de espera se
inicializa a cero.
Escribir un programa que simule este sistema de colas mediante una lista nica, cada vez
que despegue un avin saldr un mensaje con las caractersticas del vuelo y el tiempo total
de espera.
8.6. Resolver el problema 8.4 realizando el sistema de colas mediante un array de 5 colas.
PARTE
,
CAPITULO


ecurslvl a

a orltmos recursIvos

CONTENIDO

9.1. Recursividad.
9.2. Cundo no utilizar recursividad.
9.3. Algoritmos divide y vence.
9.4. Implementacin de procedimientos recursivos mediante pilas.
9.5. Algoritmos de vuelta atrs.
9.6. Problema de la seleccin ptima.
9.7. Problema de los matrimonios estables.
RESUMEN.
EJERCICIOS.
PROBLEMAS.

Un procedimiento o funcin recursiva es aquella que se llama a s mis-


ma. Esta caracterstica permite a un procedimiento recursivo repetirse
con valores diferentes de parmetros. La recursin es una alternativa a
la iteracin muy elegante en la resolucin de problemas, especialmen-
te si stos tienen naturaleza recursiva.
Normalmente, una solucin recursiva es menos eficiente en trmi-
nos de tiempo de computadora que una solucin iterativa debido al
tiempo adicional de llamada a procedimientos.
En muchos casos, la recursin permite especificar una solucin ms
simple y natural para resolver un problema que en otro caso sera difi-
cil. Por esta rzn la recursin (recursividad) es una herramienta muy
potente para la resolucin de problemas y la programacin.

9.1. RECURSIVIDAD

Un objeto recursivo es aquel que forma parte de s mismo. Esta idea puede servir de
ayuda para la definicin de conceptos matemticos. AS, la definicin del conjunto

263
264 Estructura de datos

de los nmeros naturales es aquel conjunto en el que se cumplen las siguientes ca-
, .
ractenstlcas:
O es un nmero natural.
El siguiente nmero de un nmero natural es otro nmero natural.
Mediante una definicin finita hemos representado un conjunto infinito.
El concepto de la recursividad es muy importante en programacin. La recursividad
es una herramienta muy eficaz para resolver diversos tipos de problemas; existen mu-
chos algoritmos que se describirn mejor en trminos recursivos.
Suponga que dispone de una rutina Q que contiene una sentencia de llamada a s
misma, o bien una sentencia de llamada a una segunda rutina que a su vez tiene una
sentencia de llamada a la rutina original Q. Entonces se dice que Q es una rutina re-

cursiva.
Un procedimiento o funcin recursivos han de cumplir dos propiedades generales
para no dar lugar a un bucle infinito con las sucesivas llamadas:
Cumplir una cierta condicin o criterio base del que dependa la llamada re-

cursiva.
Cada vez que el procedimiento o funcin se llamen a s mismos, directa o indirec-
tamente, debe estar ms cerca del incumplimiento de la condicin de que depen-
de la llamada.

EJEMPLO 9.1. Secuencia de nmeros de Fibonacci


Esta serie numrica es un ejemplo tpico de cumplimiento de las dos propiedades ge-
nerales de todo procedimiento recursivo. La serie de Fibonacci es:
O, 1, 1,2, 3, 5, 8, 13, 21, 34...
El trmino inicial es ao = 0, y los siguientes son: al = 1, a 2 = 2, a3 = 3, a 4 = 5, a 5 = 8 ...
observndose que cada trmino es la suma de los dos tlIninos precedentes excepto ao yal'
La serie puede ser definida recursivamente del modo siguiente:
Fibonacci(n) = n si n = O o n = 1
Fibonacci(n) = Fibonacci(n-2) + Fibonacci(n-l) para n >l
Esta definicin recursiva hace referencia a ella misma dos veces. Y la condicin para
que dejen de hacerse llamadas recursivas es que n sea O o 1. La llamada recursiva se
hace en trminos menores de n, n- 2, n-l, por lo que se va acerc~ndo a los valores de los
que depende la condicin de terminacin.
j
I
1
9.2. CUNDO NO UTILIZAR RECURSIVIDAD 1,
1
~

La solucin recursiva de ciertos problemas simplifica mucho la estructura de los progra- !
mas. Como contrapartida, en la mayora de los lenguajes de programacin las llamadas 1
<

recursivas a procedimientos o funciones tienen un coste de tiempo mucho mayor que sus ,

,,I
Recursividad: algoritmos recursivos 265

homlogos iterativos. Se puede, por tanto, afirmar que la ejecucin de un programa


recursivo va a ser ms lenta y menos eficiente que el programa iterativo que soluciona
el mismo problema, aunque, a veces, la sencillez de la estructura recursiva justifica el
mayor tiempo de ejecucin.
Los procedimientos recursivos se pueden convertir en no recursivos mediante la in-
troduccin de una pila y as emular las llamadas recursivas. De esta forma se puede
eliminar la recursin de aquellas partes de los programas que se ejecutan ms frecuente-
mente.

PROBLEMA 9.1

Dada una lista enlazada imprimirla en orden inverso.

Se tiene una lista enlazada que se referencia por un puntero externo al primer nodo
de la lista. Se desea imprimir los nodos del ltimo al primero. Los tipos de datos que se
utilizan en la lista son:

type
Tipoinfo - . . . ,
Puntero = ANodo;
Nodo = record
Info: TipoInfo;
Sgte: Puntero
end;

nil

La variable L referencia al primer nodo de la lista. El problema va a ser descompues-


to de forma recursiva, de tal forma que se vaya reduciendo la lista hasta llegar al ltimo
nodo. Es posible considerar la tarea a realizar dividida en los siguientes pasos:

Imprimir desde el segundo nodo hasta el ltimo en orden inverso.


Imprimir el primer nodo.

Ya se ha reducido la lista en un nodo. A su vez, la primera parte se puede efectuar en


dos pasos:

Imprimir desde el tercer nodo hasta el ltimo en orden inverso.


Imprimir el segundo nodo.

El primer paso est formulado recursivamente. El proceso llega a su fin cuando no


quedan elementos en la lista.
266 Estructura de datos

Codificacin
procedure I mpri melnvers o( L: Pun tero);
begin
if L <> nil then
begin
I mprimelnver so( L A. Sg t e ) ;
write(LA.lnfo)
end
end;

9.2.1. Eliminacin de la recursividad


Para eliminar la recursividad se utiliza una pila. En la pila el primer elemento que entra
es el ltimo en salir. Por consiguiente habr que recorrer la lista, nodo a nodo. Las direc-
ciones de los nodos (punteros) son almacenados en una pila hasta alcanzar el ltimo
nodo. Una vez alcanzado el ltimo nodo se escribe el campo de informacin y aqu es
donde se simula la recursividad. La vuelta atrs conseguida con la recursividad se consi-
gue sacando de la pila las direcciones de los nodos, escribiendo la informacin, as hasta
que quede vaca la pila.

Codificacin
uses Pi las;
procedure Imprime i nverso (L : Puntero ) ;
var
Pi la: p trpila;
P : Puntero;
begin
Pcrear (Pila) ;
P : = L;
while P <> nil do
begin
Pmeter( P, Pila) ;
P := P A.S g t e
end;
{En l a pi l a estn todas las direcciones de l os nodos }
while not Pvacia ( Pil a) do
begin
Psacar(P, Pi la);
Escribir(PA.lnf o)
end
end;

PROBLEMA 9.2
Multiplicacin de dos nmeros enteros por el mtodo de la montaa rusa.

Descripcin: El mtodo consiste en formar dos columnas, una por cada operando.
Las columnas se forman aplicando repetidamente los pasos siguientes:
Recursividad: algoritmos recursivos 267

Dividir por 2 el multiplicando. Anotar el cociente en la columna del multiplican-


do como nuevo multiplicando.
Duplicar el multiplicador y anotarlo en la columna del multiplicador.

Una vez hecho esto, se suman los valores de la columna del multiplicador que se
correspondan con valores impares de la columna de multiplicandos. La suma es el pro-
ducto.

Codificacin
El problema se resuelve con una funcin que tiene como entrada dos enteros X, Y, Y
devuelve el producto aplicando el mtodo de la montaa rusa.

function Pr o du cto(X , Y: l o ngi n t): l o n g int;


begin
if X >= 1 than
if (X mod 2) <> o then { Es impar }
Pro duct o := Y + Prod uc t o( X div 2 , Y * 2)
elee
Pro du cto : = Pr o du c t o(X div 2 , Y * 2)
alee
Producto .. - O
end;

9.3. ALGORITMOS DIVIDE Y VENCERS


Una de las tcnicas ms importantes para el diseo de algoritmos recursivos es la tc-
nica llamada divide y vencers. Consiste esta tcnica en transformar un problema de
tamao n en problemas ms pequeos, de tamao menor que n. De modo que dando
solucin a los problemas unitarios se pueda construir fcilmente una solucin del pro-
blema completo.
El algoritmo de bsqueda binaria es un ejemplo tpico de esta tcnica algortmica.
La lista ordenada de elementos se divide en dos mitades de forma que el problema de
bsqueda de un elemento se reduce al problema de bsqueda en una mitad; as se pro-
sigue dividiendo el problema hasta encontrar el elemento, o bien decidir que no se
encuentra. Otro ejemplo claro de esta tcnica es el mtodo de ordenacin rpido
(quick sort).
Un algoritmo divide y vencers puede ser definido de manera recursiva, de tal
modo que se llama a s mismo aplicndose cada vez a un conjunto menor de elementos.
La condicin para dejar de hacer llamadas es, normalmente, la obtencin de un solo
elemento.

9.3.1. Torres de Hanoi


Este famoso juego/acertijo que a continuacin se describe, va a permitir aplicar la tcni-
ca de divide y vencers en la resolucin de un problema. El juego dispone de tres

,,
I
268 Estructura de datos

postes, A, B, C; en el poste A se encuentran n discos de tamao decreciente. El objetivo


es mover uno a uno los discos desde el poste A al poste C utilizando el poste B como
auxiliar. Adems, nunca podr haber un disco de mayor radio encima de otro de menor
radio.

A B e

Vamos a plantear la solucin de tal forma que el problema se vaya dividiendo en


problemas ms pequeos, y a cada uno de ellos aplicarles la misma solucin. En lengua-
je natural lo podemos expresar as:

l. El problema de mover n discos de A a C consiste en:


mover los n-J discos superiores de A a B
mover el disco n de A a e
mover los n- J discos de B a e

Un problema de tamao n ha sido transformado en un problema de tamao n- J. A su


vez cada problema de tamao n-J se transforma en otro de tamao n-2 (empleando el
poste libre como auxiliar).

2. El problema de mover los n-J discos de A a B consiste en:


mover los n-2 discos superiores de A a e
mover el disco n-J de A a B
mover los n-2 discos de a B e

De este modo se va progresando, reduciendo cada vez un nivel la dificultad del pro-
blema hasta que el mismo slo consista en mover un solo disco. La tcnica consiste en ir
intercambiando la finalidad de los postes, origen destino y auxiliar. La condicin de
terminacin es que el nmero de discos sea 1. Cada accin de mover un disco realiza los
mismos pasos, por lo que puede ser expresada de manera recursiva.
El procedimiento recursivo TorresH resuelve el acertijo o juego.

procedure Torr es H (N: inte ger ; A, B, C : cha r);


procedure Movimiento(N: integer; A, C : cha r);
begin
writeln( 'M ove r disco I ,N, I de I ,A, I a I/e)
end;
Recursividad: algoritmos recursivos 269

begin
if N=l then
Mov imi e nt o (N, A, e)
else begin
To rr es H (N - 1, A, e , B ) ;
Mov imiento(N, A, e) ;
Torres H(N - 1, B , A, C)
end
end;

9.3.2. Traza de un segmento


Se desea dibujar un segmento que conecta dos puntos (x 1, Y 1) Y (x2, y2). Suponemos
que siempre xl, Y 1, x2, y2 son> = O. Planteamos la solucin de manera recursiva, utili-
zando la estrategia divide y vencers. El procedimiento consiste en dibujar el punto
medio del segmento; sobre las dos mitades que detennina ese punto medio volvemos a
aplicar el algoritmo de dibujar su punto medio. As hasta que, a base de dividir el seg-
mento, se proporcione un segmento de longitud prxima a cero.
El programa Dibuj ar en el que se define el tipo de dato coordenada (Coord), se
establecen los extremos del segmento y se dibuja.

program Dibujar;
uses c rt;
type
eoo r d = record
X : r eal ;
y : rea l
end;
var
O, F : Coo rd;
procedure Dib_sgmto(O, F: eoord) ;
var
M: eoo r d ;
begin
with M do
if (O.X+O .S) < F. X then
begin
X := ( O . X+ F. X) / 2 ;
y := (O . Y+F. Y) / 2 ;
Dib_ sg mt o(O , M) ;
if WhereX > 7 0 then
Goto XY( S , Wh e re Y + 1 ) ;
wr i t e (I X : 3 : 1, , , , Y : 3 : 1, ' )
( I , I I ) ;

Dib_sgmt o (M, F ) ;
end
end;
begin
el rsc r; GotoXY ( 5,1 ) ;
O.X := 1 ; O.Y := 2 ;
F. X := 1 2 ; F. Y := 7 ;
Di b _ sgmt o (O, F )
end.
270 Estructura de datos

9.4. IMPLEMENTACiN DE PROCEDIMIENTOS RECURSIVOS


MEDIANTE PILAS
Un procedimiento, una funcin contiene tanto variables locales como argumen-
tos ficticios (parmetros). A travs de los argumentos se transmiten datos en las llama-
das a los subprogramas, o bien se devuelven valores al programa o subprograma in-
vocante.
Adems, el subprograma debe guardar la direccin de retomo al programa que reali-
za la llamada. En el momento en que termina la ejecucin de un subprograma el control
pasa a la direccin guardada.
Ahora el subprograma es recursivo, entonces adems de la direccin de retomo, los
valores actuales de las variables locales y argumentos deben de guardarse ya que se
usarn de nuevo cuando el subprograma se reactive. Supongamos que se ha llamado al
subprograma P, que tiene llamadas a s mismo, es decir, es recursivo. El funcionamiento
del programa recursivo P:

Se crea una pila para cada argumento.


Se crea una pila para cada variable local.
Se crea una pila para almacenar la direccin de retomo.

Cada vez que se hace una llamada recursiva a P, los valores actuales de los argumen-
tos y de las variables locales se meten en sus pilas para ser procesadas posteriormente.
Asimismo, cada vez que hay un retomo a P procedente de una llamada recursiva ante-
rior, se restauran los valores de variables locales y argumentos de las cimas de las pilas.
Para la obtencin de la direccin de retomo vamos a suponer que el procedimiento P
contiene una llamada recursiva en la sentencia N. Entonces guarda en otra pila la direc-
cin de retomo, que ser la sentencia siguiente, la N + 1. De tal forma que cuando el
nivel de ejecucin del procedimiento P actual termine, alcance la sentencia end final,
usar dicha pila de direcciones para volver al nuevo nivel de ejecucin. De esta forma
cuando la pila de direcciones se quede vaca volver al programa que llam al subpro-

grama recursIVO.

PROBLEMA 9.3
Hacemos una traza del estado de las pilas en la ejecucin de funcin producto, por el
mtodo de la montaa rusa, para los valores de 19 y 45.

1 no nO+Prod ...
2 360 ProductoO
4 180 ProductoO
9 90 90+Prod ..
19 45 45+Prod ..
Pila Pila Pila de
de X de Y direcc.
Recursividad: algoritmos recursivos 271

La estrategia a seguir para emular un procedimiento recursivo Pes:

l. Definir una pila para cada variable local y cada argumento, y una pila para alma-
cenar direcciones de retorno.
2. En la sentencia n donde se haga la llamada recursiva a P:
(1) Meter en las respectivas pilas los valores actuales de las variables locales y
argumentos; (2) Meter en la pila de direcciones la direccin de la siguiente
sentencia.
Inicializar los argumentos con el valor actual de ellos y empezar la ejecucin
desde el principio del procedimiento.
3. Vuelta de la ejecucin despus de la llamada recursiva:
Si la pila de direcciones est vaca, devolver control al programa invocador.
Sacar de las pilas los valores de la cima. Llevar la ejecucin a la sentencia
extrada de la pila de direcciones.
,

9.4.1. El problema de las Torres de Hanoi resuelto


sin recursividad
El problema de las Torres de Hanoi, cuya solucin recursiva se ha descrito, se puede
resolver de forma no recursiva siguiendo esta estrategia.

Algoritmo no recursivo Torres de Hanoi

Los argumentos conocidos son:


N N me ro de di s co s .
A
B
Vari ll a A
Var il l a B
e va ri l la e
Para cada uno de ellos se define una pila:
Pil aN
P i l aA
Pi l a B
p i lae
Adems la pila de direcciones: Pi 1 aD i r
Torre _ Ha noi(N, A , B, el
Crear pilas: Pi laN, Pil aA , Pi l a B , Pi l a e , P i la Di r

Las etapas a considerar en la construccin del algoritmo To r res de Hano i son:


1. Condicin para acabar.
si N = 1 entonces
Escribir Pa l o A - > Pa l o e
Ir a 5
fin si
272 Estructura de datos

2. Llamada recursiva.
a) Guardar en pilas:
Meter (N, PilaN)
Meter ( A, PilaA)
Meter(B, PilaB)
Meter(C, PilaC)
Meter (e Pas o 3 > , PilaDir )

b) Actualizar los argumentos:


N ~ N - 1
A ~ A
Inter c ambiar B, C :
t ~ B
B ~ C

C ~ t

e) Volver a paso 1.

3. Escribir varilla A ~ Varilla C.

4. Segunda llamada recursiva:


a) Guardar en pilas:
Meter(N, PilaN)
Meter(A, PilaA)
Meter ( B, PilaB)
Meter(C, Pil aC )
Meter (e Pas o 5 > , PilaDir)

b) Actualizar los argumentos:


N ~ N-l
C ~ C
Intercambiar A, B:
t ~ B
B ~ A
A ~ t

e) Volver a paso 1.

5. Este paso se corresponde con el retomo de las llamadas recursivas .


a) Si Pila vaca entonces fin de algoritmo: volver a la rutina llamadora.


b) Sacar de la pila:
Sa c ar(N, PilaN)
Sa c ar ( A, PilaA )
Sacar(B, PilaB)
Sacar ( C, PilaC)
Sa c ar(Dir, Piladir)

e) Ir al paso que est guardado en Di r.


Recursividad: algoritmos recursivos 273

Codificacin no recursiva del problema de las Torres de Hanoi

Para realizar la codificacin del algoritmo no recursivo de las Torres de Hanoi es ne-
cesario una pila de enteros (P ila N) y tres pilas de elementos char (Pi l aA , p i la B,
p i 1 aC ). Para simular direcciones de retomo se utili za otra pila de enteros en la que se
guarda 1 o 2, segn se simule la primera llamada o la segunda llamada recursiva. Los
tipos de datos y las operaciones estn en las unidades de pilas.

uses pi l acha r, P i l a in t ;

procedure Ha n o i t e r (N : i nteg er ; A, B , C : c h a r ) ;
var
Pil a A , P il a B , p ilaC : Pil a c ha r . Pt rPil a ;
Pi laN , P i l aD : P ilaint . PtrPi la ;
Paso : in t eger;
T : c ha r ;
begin
P i lachar .Pc re a r( P i laA ) ;
P ila cha r . Pcr ear (P i l a B ) ;
P ilachar . Pcrear (PilaC) ;
P il a i n t . Pcrea r (Pi laN) ;
p il ain t . Pc rear ( Pi l aD ) ;
P i laint . Pm e t e r( l,P il aD ) ;
while not P i l aint . Pv acia (PilaD) do
i f (N = 1 ) then
begin
Mov e r di sco(N ,A , C) ;
P i la int . P s a car (P as o , pi l aD) ;
if not P i lain t . Pva c i a(P il aD) then
begin
Pi la cha r . P saca r(A, pilaA) ;
Pi la cha r . P sac a r (B, pilaB) ;
P i la c h a r . Ps ac ar(C , PilaC) ;
P il a i n t . Psaca r ( N ,P il aN)
end
end
else begin
P i l aint. P saca r(Pas o , Pil aD ) ;
Case Pas o of
1 : begin
Pila char . Pme t er ( A,Pi laA) ;
P i l a c h a r . Pmeter (B ,P ilaB ) ;
Pi l ach a r . Pm eter IC , PilaC) ;
P ilai nt . Pmet e r(N, Pi l a N) ;
P il a i nt . Pmete r (2, P il aD ) ; {Pa so ac tual }
P i 1 a i n t . Pme t er ( 1 , p i 1 a D) ;
N := N - l;
T := B ; B : = C ; C : = T
end;
2 : begin
Move r d iscO ( N,A, C) ;
{No e s n e c esario alm ac ena r los argum e n to s A, B, C , N p ue s no
se utilizan }
Pi l a i n t . Pmet er (1, Pi l aD) ;
274 Estructura de datos

N := N-1;
T := B; B := A ; A : = T
end
end
end
end;

Esta solucin resulta un tanto farragosa debido a la utilizacin de 5 pilas. Una sim-
plificacin fcil que puede hacerse es utilizar una nica pila, en sta se guarda el estado
completo de los argumentos y la direccin de retomo. En la unidad p i 1 a S t a t est
declarado el tipo elemento, un registro con los campos necesarios para guardar A, B, e,
N y Di r , y adems las operaciones de manejo de pilas.
Los tipos de datos en la unidad Pi laSt a t:

type
Elemento = record
Pa , Pb , Pe : ehar ;
Nd , Oir: in te g er
end;
Ptr P i l a = AI te mp;
I te mp = record
I nf o : Ele me n t o ;
Sgte : PtrP il a
end;

El procedimiento Ha n o i ter 2 :

procedure Ha n oi ter2( N : in tege r; A , B, e : eha r) ;


var
P il a : P trPil a ;
T : Ele mento;
procedure Est a d o( var S t : E lemen to ; A,B , e : eha r; N,O : in t ege r) ;
begin
with S t do
begin
Pa -- A',
Pb -- B;
Pe -- e ;
Nd -- N ;
Oi r .. -- D
end
end;
begin
Pe r ear (Pil a ) ;
E s ta d o(T , A , B, e , N, l J ;
Pmeter (T, P i l a ) ;
while not Pva e i a (P i la) do
with T do
begin
Psa ear ( T, P i l a );
if (Nd = 1 ) then
Mo ver _ d i seo( Nd , Pa , Pe)
else
Recursividad: algoritmos recursivos 275

case Dir of
1: begin
Dir := 2;
Pmeter (T, Pila ); {Estado actual}
Estado(T,Pa,Pc,Pb,Nd-l,l) ;
Pmeter(T,Pila) ;
end;
2: begin
Mover_disco (Nd, Pa, Pc);
Estado(T,Pb,Pa,Pc,Nd-l,l) ;
Pmeter(T,pila) ;
end
end
end
end;

En el programa Torrehanoi se muestran diversas soluciones de las Torres de Hanoi


segn el nmero de discos. Se aplica tanto la solucin recursiva como a las dos solucio-
nes iterativas. La salida se dirige a la impresora.

program Torrehanoi;
uses P il aint , Pilachar, Pilastat , crt, printer ;
const
Maxnumdiscos = 15;
var
N: integer;
A,B,C: char;

procedure mover_d isco (N: in t eger; A,C: Ch ar) ;


begin
writeln(Lst, 'Mover disco' ,N,' de ',A,' a ',C)
end;
procedure mover_torre (N : integer ;A,B,C: Char) ;
begin
if N = 1 then
mover_disco(N,A,C)
el se
,I
begin

mover_torre(N-1,A,C,B) ;
mo ver_disco(N,A,C) ;
mover_t orre(N-1,B ,A,C)
end;
end;

procedure Hanoit e rl(N: integer; A, B, C:char);


var
pilaA, Pi laB, pilaC: Pilachar.PtrPila;
PilaN, PilaD: Pilaint. PtrPila;
Paso: integer;
T: char;
begin
Pilachar.Pcrear(PilaA) ;
Pilachar,Pcrear(PilaB) ;
Pilachar.Pcrear(PilaC) ;
. ..... _._------------------

276 Estructura de datos

Pi l aint .Pcrear(PilaN} ;
P i laint.Pcrear(PilaD} ;
Pilaint.Pmeter(l,PilaD} ;
while not Pilaint.Pvacia(pilaD} do
if (N = 1) then
begin
Mover_disco(N,A,C) ;
Pilaint.Psacar(Paso,PilaD) ;
if not Pilaint.Pvac i a(pilaD) then
begin
Pilachar.Psacar(A,Pi l aA) ;
Pilachar.Psacar(B,PilaB} ;
Pilachar.Psacar(C,PilaC} ;
Pilaint.Psacar(N,P i laN}
end
end
else begin
Pilaint.Psacar(Paso,PilaD) ;
Case Paso of
1: begin
Pilachar.Pmeter(A,PilaA) ;
Pilachar.Pmeter(B,PilaB) ;
pilachar.Pmeter( e ,Pilae) ;
Pilaint.Pmeter(N,Pi l aN} ;
Pilaint. Pmeter (2, Pi l aD); {Paso ac t ual }
Pilaint.Pmeter(l,PilaD} ;
N := N- 1;
T := B; B : = e ; e := T
end;
2 : begin
Mover_disco(N,A , e} ;
Pilain t . Pmeter(l,Pila D} ;
N := N- 1;
T := B; B := A; A : = T
end
end
end
end;

procedure Hanoiter 2 (N: integer; A, B, e:char};


var
Pila: PtrPila;
T: Elemento ;
procedure Estado(var St: Elemento; A,B, e : char; N,D: integer);
begin
with St do
begin
Pa -- A;
Pb -- B;
Pc -- e;
Nd -- N;
Dir .. -- D
end
end;
begin
Pcrear(Pila) ;
Recursividad: algoritmos recursivos 2n

Est ado (T,A,B, C ,N,l) ;


Pmet e r (T, P i l a) ;
while not Pvac i a(Pi la ) do
with T do
begin
Psaca r (T , Pi l a) ;
if (Nd = 1) then
Mo ver_di sco (Nd , Pa, Pc)
else
Case Dir of
1: begin
Dir : = 2 ;
Pmeter (T , P ila ) ; { Est ado actual}
Est ado( T,Pa,Pc, Pb ,Nd- l,l) ;
Pm eter(T , P ila) ;
end;
2 : begin
Move r_d i sco(Nd, Pa , Pc );
Estado( T, Pb , Pa , Pc , Nd-l , l) ;
Pmeter( T, P ila) ;
end
end
end
end;
begin
clrscr ;
A:= 'A';
B . - 'B",
.-
C - 'C",
wr i t e( 'Numero d e discos? : ' ) ;
repeat
read ln ( N)
until N in (l .. Maxnumdi scos ];
cl r scr ;
I wr i te l n(Lst , ' Soluc i n recursiva con ' ,N , ' d i scos ' ) ;
mover_t o rr e (N, A,B ,C ) ;
wri teln(L s t ) ;
writ e ln ( Ls t , ' So l uc i n it e rativ al con ', N, ' di s co s' ) ;
I Ha no it e rl(N,A,B, C) ;
wr i teln;
writeln(L s t , ' So l uc in i terativ a2 con ', N,' di scos ' ) ;
Ha n o iter2(N , A, B, C)
end.

9.5. ALGORITMOS DE VUELTA ATRS (BACKTRACKING)


Esta tcnica algortmica recurre a realizar una bsqueda exhaustiva sistemtica de una
posible solucin al problema planteado. El procedimiento general es descomponer el
proceso de tanteo de una solucin en tareas parciales. Cada tarea parcial se expresa fre-
, cuentemente en forma recursiva.

El proceso general de los algoritmos de vuelta atrs se contempla como un mtodo


de prueba o bsqueda, que gradualmente construye tareas bsicas y las inspecciona para

278 Estructura de datos

determinar si conducen a la solucin del problema. Si una tarea no conduce a la solu-


cin, prueba con otra tarea bsica. Es una prueba sistemtica hasta llegar a la solucin, o
bien determinar que no hay solucin por haberse agotado todas las opciones que probar.
Aplicamos esta tcnica algortmica al conocido problema de la vuelta del caballo que se
describe a continuacin.
En un tablero de ajedrez de N x N casillas. Un caballo sigue los movimientos de las
reglas del ajedrez. El caballo se sita en la casilla de coordenadas (x o, Yo)' El problema
consiste en encontrar, si existe, un circuito que permita al caballo pasar exactamente una
vez por cada una de las casillas del tablero.
La tarea bsica en que va a basarse el problema es la de que el caballo realice un
nuevo movimiento, o bien decidir que ya no quedan movimientos posibles. El algoritmo
que exponemos a continuacin trata de llevar a efecto un nuevo movimiento del caballo
con el objetivo de visitar una vez todas las casillas.

Algori t mo Caball o ;
inicio
Repetir
Seleccio nar n uevo movimiento del caballo
si (Est e n tablero) y (No pas ya) entonces
An ota r movi mi e n to e n e l table ro
si (No comp l etado t able ro) entonces
Nuevo ensay o : Caballo
{Vuelta de l l ama d a recurs i va }
si (No se a l can z so lu cin) entonces

Borrar anotac~ o n ante r~or
fin_si
fin si
fin si
hasta (Completa do t ab l ero) o (No ms p os i b l es mov imientos)
fin

En los algoritmos de vuelta atrs siempre hay nuevas tentativas en busca de solucin,
nuevos ensayos. En el caso de que un ensayo no conduzca a alcanzar la solucin, se da
marcha atrs. Esto es, se borra la anotacin hecha al realizarse el ensayo y se vuelve a
hacer otro, en el caso de que sea posible (en el caso de un caballo, ste puede realizar
hasta ocho movimientos desde una posicin dada).
Para describir con ms precisin el algoritmo, definimos los tipos de datos para re-
presentar el tablero y los movimientos.

const
N= 8 ;
type
Tab l ero = array[l .. N, 1 .. N) of i n teger ;
var
T : Ta bl e r o ;

El tablero se representa mediante un array de enteros para guardar el nmero de


movimiento en el que pasa el caballo. Una posicin del tablero contendr:

Recursividad: algoritmos recursivos 279

o Por la casilla (X, y ) no pas el caballo.


T[ X, Y]
i Por la casilla (x ,Y) pas el caballo en el movimiento i.

Para la accin de seleccionar un nuevo movimiento, hay que tener en cuenta que
dada una posicin el caballo puede realizar 8 posibles movimientos. En una matriz de
dos dimensiones se guardan los 8 desplazamientos relativos para conseguir un siguiente
salto. La figura nos muestra los desplazamientos:

3 .2

.4 1


5 .a
+
.6 .7

La condicin de que el nuevo movimiento est en el tablero y de que no hubiera


pasado anteriormente:

(X i n [1 .. N]) and (Y i n [1 .. N]) and (T[X,Y ]= O)

La condicin no completado tablero se representa con el nmero de movimiento i


y el total de casillas:

~ < NxN

Para no penalizar en tiempo de ejecucin, las variables array son definidas globales.

CODIFICACiN DEL ALGORITMO VUELTA DEL CABALLO


CON UN MTODO RECURSIVO
const
N = 8;
type
Tab l er o = array [ l .. N, 1 .. N ) of integer ;
Coord = array[1. . 2 , 1. .8 ) of i nteger ;
var
T: Tab l ero ;
H : Coord;
r , J : intege r;
S : boolea n;
Estructura de datos

procedure Caballo(I: integer; x, Y: integer; var s: boolean);


var
Nx, Ny: integer;
K: integer;
begin
S := false;
K := O; {Inicializa el conjunto posible de movimientos}
repeat
K := K+1;
Nx := X+ H[l,K];
Ny := Y+ H[2,K];

if (Nx in [1 .. N]) and (Ny ln [ 1 .. N]) then
if T[Nx, Ny] = O then
begin
T [Nx, Ny] : = I; {Anota movimiento}
if I < N * N then
begin {Se produce un nuevo ensayo}
Caballo(I+1, Nx, Ny, S);
if not S then {No se alcanza la solucin}
T[Nx, Ny] := O {Borrado de la anotacin para probar con
otro movimiento}
end
else {Tablero completado}
S := true
end
until S or (K= 8)
end;

En las sentencias del bloque principal se inicializa las posiciones del tablero y los
desplazamientos relativos para obtener nuevas coordenadas.
begin
H[l,l] -- 2 ; H[2,1] -- 1;
H[1,2] -- 1 ,. H[2,2] -- 2;
H[1,3] -- -1,, H[2,3] -- 2 ,.
H[1,4] -- ~ 2 ; H[2,4] -- 1 ,.
H[1,5] - - 2 ; H[2,5] -- -1;
H[1,6] -- -1 ; H[2,6] -- -2;
H[1,7] -- 1 ; H[2,7] -- -2;
H[1,8] -- 2 ; H[2,8] -- -1;
for I -- 1 to N do
for J -- 1 to N do
T[I,J] .. -- O ;
{El caballo parte de la casilla (l,l)}
T[l,l] -- 1 ;
Caballo(2,1,1,S) ;
if S then
for I := 1 to N do
begin
for J := 1 to N do
wr i t e (T [ I , J] : 4 ) ;
writeln
end
el se
writeln('NO SE ALCANZA SOLUCION')
end.
Recursividad: algoritmos recursivos 281

La caracterstica principal de los algoritmos de vuelta atrs es intentar realizar


pasos que se acercan cada vez ms a la solucin completa. Cada paso es anotado, bo-
rrndose tal anotacin si se determina que no conduce a la solucin, esta accin consti-
tuye una vuelta atrs. Cuando se produce una vuelta atrs se ensaya con otro paso
(otro movimiento). En definitiva, se prueba sistemticamente con todas las opciones
posibles hasta encontrar una solucin, o bien agotar todas las posibilidades sin llegar a
la solucin.
El esquema general de este mtodo:

procedimiento EnsayarSolucion
Inicio
Inicializar cuenta de opciones de seleccin
repetir
Se lec cio nar nuevo paso hacia l a soluci n
si vl id o entonces
Anotar el paso
si no completada solucin entonces
EnsayarSolu c in a partir del nuev o paso
si no alcanza solucin completa entonces
.
borrar anotac~on
,

fin_si
fin_si
fin
Hasta (Completada solucin) o (No ms opciones )
fin

Este esquema puede tener variaciones. En cualquier caso siempre habr que adaptar-
lo a la casustica del problema a resolve~.

9.5.1. Solucin del problema Salto del caballo con esquema


iterativo
Ampliamos el problema anterior para encontrar todas las rutas que debe seguir el caballo
I para completar el tablero pero utilizando pilas y as transformar el esquema recursivo en
iterativo. En la unidad PilasC tenemos todas las operaciones de manejo de pilas. En la
pila se almacena el nmero de movimiento, nmero de salto y posicin. A continuacin
escribimos el cdigo de la unidad PilasC.

unit PilaC;
Ii interface
const
I
N = 8;
,
type
I ndice = 1. .N;
Tipoelem = record
Nummov: integer;
, Salto: integer;
X: Indice;
Y: I ndi ce
end;
282 Estructura de datos

PtrPila =Altemp;
Itemp = record
Info: Tipoelem;
Sgte: PtrPila
end;

procedure Pcrear(var Pila: PtrPila);


function Pvacia(Pila: PtrPila): boolean;
procedure Pmeter(var Pila: PtrPila; X: Tipoelem);
procedure Pcima(Pila: PtrPila; var X: Tipoelem);
procedure Pborrar(var Pila: PtrPila);
procedure Psacar(var Pila: PtrPila; var X: Tipoelem);
implementation

procedure Pcrear(var Pila: PtrPila);


begin
pila := nil
end;

function Pvacia(Pila: PtrPila): boolean;


begin
Pvacia := (Pila = nil)
end;

procedure Pmeter(var Pila: PtrPila; X: Tipoelem);


var
A: PtrPila;
begin
new (A) ;
AA.lnfo := X;
AA.Sgte := Pila;
pila := A
end;

procedure Pcima(Pila: PtrPila; var X: Tipoelem);


begin
if not Pvacia(Pila) then
X := PilaA.lnfo
end;

procedure Pborrar(var Pila: PtrPila);


var
A: PtrPila;
begin
if not Pvacia(Pila) then
begin
A := Pila;
pila := PilaA.Sgte;
dispose(A)
end

end;

procedure Psacar(var Pila: PtrPila; var X: Tipoelem);


var
A: PtrPila;
begin
if not Pvacia(Pila) then
- - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - _ ... ... .

Recursividad: algoritmos recursivos 283

begin
A : = Pi l a ;
X : = Pila A.I nfo ;
Pila := Pila A. Sgte;
d i spose( A)
end
end;
begin
end.

Esta unidad la utilizamos para escribir el programa que iterativamente encuentra to-
das las rutas que puede seguir el caballo para recubrir el tablero.

program Caba it ef;


uses
c rt, P i l aC ;
type
I ncr e mentos - array [1 .. 8 ] of integer;
Tabla = array [ind ice, i n d i ce] of intege r ;
var
Cp : Ptrp ila;
R : Tipoelem;
Xn, Xp , Yn , Yp : integer; {c oo rde n adas cas il las}
Fila, Co l u mna: I ndice;
Rl : set of Indice ;
In c X,
I n c Y: I n c remen t o s ; {Des pla za mie n tos relativos }
Ta b lero : Tabla;
So luciones, Salto, Nu mMo v : i n t eger ;
Recorrido , Colo cado : b o o l e a n;

procedure Anotar (var Nw: Tipoelem; Nm, S: integer;


U, V : Ind i ce) ;
begin
with Nw do
begin
Nu mmo v := Nm;
Sa l to := S ;
X := U;
Y : = V

end
end;

procedure Escribepil a (Cp : PtrPila);


begin
if Cp <> nil then
begin
Es cr i bepila (Cp A. sg te) ;
with Cp A do
write ( i n Eo.numm ov : 4 , in f o . sa l to : 2, i n fo . x:2, '-', i n Eo . y) ;
end
end;

procedure Iniciartable r o (var Tab l ero : Tabla);


var
Fila, Columna : Indi c e;


284 Estructura de datos

begin
for Fila := 1 to N do
for Columna := 1 to N do
Tablero[Fila, Columna] ..-
- O
end;

procedure Incre(var Incx, Incy: Incrementos);


begin {Desplazamientos relativos para desde una posicin dada dar ,

,
un salto de caballo} ,,
e,,
IncX[1] := 2; IncY[1] := 1;
IncX[2] := 1; IncY[2] := 2; ,
I
IncX[3] := -1; IncY[3] := 2; ,
IncX[4] -- -2; IncY[4] -- 1; ,
IncX[5] -- -2; IncY[5] -- -1; ,I
1
IncX[6] - -1; IncY[6] -- -2;
IncX[7] --
IncX[8] -
1 ; IncY[7] -- -2;
2 ; IncY[8] - -1;
I
end;
l
procedure Escribetablero(var Tablero :Tabla);
var
Fila, Columna: Indice;

begin
for Columna := N downto 1 do
begin
for Fila := 1 to N do
write (Tablero [Fila, Columna]: 5) ;
writeln
end;
end;
begin
clrscr;
Rl := [l..N];
Incre(Incx, Incy);
Iniciartablero(Tablero) ;
Write ('Introduzca casilla inicial:');
Nummov : = 1;
with R do
begin ,
,

readln (X, Y) ;

Nummov : = 1;
Tablero[X,Y] := Nummov;
Salto := 8
end;
Pcrear (Cp) ;
Pmeter(Cp, R);
Recorrido := false;
Soluciones := O;

while not Pvacia(Cp)do J
;
begin ,
if Recorrido then j

begin
Pcima (Cp, R);
with R do
Tablero[X,Y] := O;
Salto := R.Salto;
Pborrar (Cp) ;

,
1
Recursividad: algoritmos recursivos 285

" Vu e lta atrs " tl asta l legar a u n a casi~la des de la q lle rl o


se ago ta r o n todos los saltos y asi pode r encont r ar otra
. "
s o 1.UC lon
while ( Salto = 81 and not Pvaci a(Cpl do
begin
Pcim a ( Cp , R I;
with R do
Tab ler o [X , Y] .. -- () ,,
Pbo, rar (Cpl ;
NUTIIInOV : ~ N\;nmov 1;
if not Pvacia(Cpl then
begin
Pcima(Cp, RI ;
SalLo : = R. . Salto
end
end
if not pvacia(Cp l then
begin
T abl ero [R , X, R , V j := O; {D es ha ce a n te rior para b squ e d a
d e otra SC)l tl(::i!" .\
.

Numm e)v : = R . N\lIT\m OV 1;


Pborrar (Cpl ;
Recorrido : = false
end
end
else S alt o .. .. o;

if not pvaci a(C p ) then


begin
Co lo cado : = f a l se ;
Pc imalCp, RI ; (P ara dar
repeat
Salto : = Salto-1 ;
Xn :~ R . X + In c x lSalto );
'In := R . Y + Incy[Salto] ;
if ( Xn in R: ) and ('In in Rl ) then
Colocad o : = Tab'ero ' Xn , Vn 1 -- O,
until co~o cado or (Salto = 8) ;
if Co l oc a do then {Anota movim ien to}
begin
Nummov : ~ N um n~ov ~ 1.. ,.
Table r o ( Xn , Y r; ] : -- Nu m~ o v ;
Ll:...no tar( R , Nurn~nov , Sa lto , Xn, Yn ) ;
Pme ter I Cp, R) ;
if Numm ov = N * N then ( ru:a com pl etada!
begin
Re corrido - = t- r "'"" p'_1-
l.

SOlll Cio !leS : = Sol;Jc: iones + 1 ;


wri teln ( ' SOLUCION ': 4 ,1, Sol uciones) ;
:';s cribeLab~ero (;'<'lbJ ero ) ;

end
end
else (N o p~d o coloca ~ s n Num~ov+l a partir de N,l mmC)V \
while not Colocado and not ? vaci a ( Cp ) do
286 Estructura de datos

begin {M arc h a at rs : e s sacado el movimien t o anter i or


par a nu ev a " pr u eba " con otro sal to}
Pcima(Cp , R ) ;
with R do
Tab l ero [ X, Y] : = O;
Sa l to : = R . Salto ; {Es el l t i mo Sa lto)
Pbo rrar (Cp) ;
if not Pv a ci a(Cp ) then
begin
Pcima(Cp , R);
with R do
begin
Xp : = X;
Yp : = Y
end;
while (S a lto < 8) and not Colo ca do do
begin
Salto : = Salto + 1;
Xn := xp + Incx[Salto] ;
Yn : = Yp + I nc y [ Salt o];
if (Xn in Rl) and (Y n in Rl ) then
if Tab l e r o [ Xn , Yn ] = O then
begin
Co lo ca do := true ;
Nummov := R . Nu mmov + 1;
Tab l er o[ Xn, Yn ] : =Nu mmo v;
Ano t ar( R , Nummo v, Sa l t o , Xn , Yn);
Pme t er( Cp , R ) ;
end
end
end ( f i n d e if not Pvac i a )
end { fin d e while not col oca do )
end { f in de if not Pva ci a }
end; (fi n del mien t r as)

Wr iteln ( ' Soluciones encontradas - " Soluc i ones) ;


end.

A continuacin son expuestos problemas tpicos que son resueltos siguiendo la es-
trategia de los algoritmos de vuelta atrs.

9.5.2. Problema de las ocho reinas


El juego de colocar ocho reinas en un tablero de ajedrez sin que se ataquen entre s es un
ejemplo del uso de los mtodos de bsqueda sistemtica y de los algoritmos de vuelta
,
atraso
El problema se plantea de la forma siguiente: dado un tablero de ajedrez (8 x 8 casi-
llas), hay que situar ocho reinas de forma que ninguna reina pueda atacar (<<comer) a
cualquiera de las otras. En, primer lugar recordamos la regla del ajedrez respecto de los
movimientos de la reina. Esta puede moverse a lo largo de la columna, fila y diagonales
donde se encuentra. Una primera conclusin es que cada columna puede contener una y
slo una reina, por lo que la colocacin de la reina i queda restringida a las casillas de la

,
Recursividad: algoritmos recursivos 287

columna i. Por esta coincidencia el parmetro i nos sirve de ndice de columna dentro de
la cual podremos colocarla en los ocho posibles valores de fila.
En cuanto a los tipos de datos para representar las reinas en el tablero, como lo que
nos interesa es detelIuinar en qu fila se sita la reina que est en la columna i , defini-
mos un vector entero. El contenido de una posicin del vector ser 0, o bien el ndice de
fila donde se sita la reina.

, const
N= 8 ; { N mer o d e r ei n a s }
type
Fila = array[l . . N] of i nteger;

En orden a buscar la solucin completa, la tarea bsica que exhaustivamente se prue-


ba es colocar la reina i en las 8 posibles filas. La comprobacin de que dicho ensayo es
vlido tiene que hacerse investigando que en dicha fila y en las dos diagonales no haya
otra reina colocada anteriormente. En cada paso se ampla el nmero de reinas coloca-
das , hasta llegar a la solucin completa, o bien determinar que en un paso no sea posible
colocar la reina. Entonces, en el retroceso se coloca la reina anterior en otra fila vlida
para realizar un nuevo tanteo.

CODIFICACiN
const
N= 8; {Nmero de reinas}
type
Fi las = array[ l .. N] of int e ger;
var
Re i nas: Filas;
Soluc i o n: b oo l ean ;
1: in t eger ;

procedure Co l ocar _ Reinas (r : i n te g er ; v a r S : b o olea n ) ;


var
K: i nteger ;
function Va li do(J : integer) : bool e an ;

{ In spec ci o n a s i la r e i na d e la co l um n a J e s atacada por a l guna relna
colocada anteriorme n te}
var
R : in t eger ;
V : boo l ean ;
begin
V : = true ;
for R : = 1 to J-l do
begin
V : = V and (Reinas[R] <> Rein a s[J]) ;
{No es t . e n la mi s ma f il a }
{No est en alguna de las dos diago n a l es : }
V : = V and ((Re i nas [J ] + J) <> (Reinas [R] + R)) ;
V := V and ((Rei n as[J] - J) < > ( Re i na s [R ] - R))
end;
Val i do := V
288 Estructura de datos

end;
begin
K : = (J ; {In ici.a liza r pos ibl es mo vim ient o s}
repeat
K : ~K + l ;

S : .:. : t illse ;

Reinus [I] {T enta tiv a d e co l ocar re l na 1 en ti l a K,
: = K; a l u ve z
q uelia a n otado m ovi~i e n t o)
if Val ido(I ) then
if T < 8 then 18 Pllede su!;ti tuir se por NI
begin {No comp let ad o e l p roble ma}
Co lo caI' _ Re ina s(I + 1, S I ;
if not S then ( Vuelta atr s)
Reinas[I] : = (J
end
else (L as 8 rein as c ol oc a das )
S : = true
until S or (K = 8)
end;

Observar que en la vuelta atrs se puede omitir borrar la anotacin ya que en la


siguiente iteracin se prueba con otra fila, asignando un nuevo valor a la misma posicin
del vector Reinas. En el bloque principal es escrita la solucin.

begin
Colocar Reinas(l, So lucion) ;
if s ol u ci on then
fa r 1 : - 1 t o 8 do
write(Reinus[l] : 5 )
end.

9.5.3. Solucin no recursiva al problema de las ocho reinas


Al igual que la solucin iterativa del salto del caballo, presentamos la solucin iterativa
de las 8 reinas con una pila para emular las llamadas recursivas. Ahora lo relevante en
cada movimiento es el nmero de fila y de columna, ello es lo que guardamos en la pila.
A continuacin escribimos el interface de la unidad p i 1 aR.

unit P i la R ;
interface
c on st

N = 8;
type
Rang o l .. N ;
7

P tr Pila = AN odo ;
Nodo = record
NI' , Co l: word ;
sg te : Pt r Pila
end
procedure PcI' e ar (var Pila : P trPi l a) ;
function Pva cia ( P ila : Plr P il a) : bool ea n ;
Recursividad: algoritmos recursivos 289

procedure Pmeter(var Pila: PtrPila; Nr, Cql: word);


procedure Pcima(pila: PtrPila; var Nr, Col: word);
procedure Pborrar(var Pila: PtrPila);
procedure Psacar(var Pila: PtrPila; var Nr, Col: word);
{Fin de la seccin de interface}

La codificacin del programa que encuentra una solucin al problema.

program ReinaA_It;
{Sita N reinas sin atacarse en tablero N*N. Da una sola solucin}
uses Crt, PilaR;
type
Tipocol = array [Rango) of boolean;
DiagonalDchalzda = array [2 .. 2 * N) of boolean;
( Fila(nmero de reina) + Columna = cte.}
DiagonallzdaDcha = array [1 - N .. N - 1) of boolean;
{F ila o nmero de reina - columna = cte.}
var
Col , Nf, Nr, i: integer;
Colibre: Tipocol; {NO hay reina en fila j-sima}
Ddch: DiagonalDchalzda; {no hay reina en Diagonal Dcha -Izda }
Dizq: DiagonallzdaDcha; {no hay reina en Diagonal Izda-Dcha}
Cp: Ptrpila;
Colocado : boolean;

procedure Listarpila(Cp: Ptrpila);


begin
while CpA.sgte <> nil do
begin
write(CpA.Nr, '= ' ,Cp A.Col,' ') ;
Cp := CpA.Sgte
end;
writeln
end;

procedure Liberar(var Col : Tipocol; var Ddch: DiagonalDchaIzda;


var Dizq: DiagonalIzdaDcha; Nr, CO: word);
begin
Col[Co) := true;
Ddch [Nr + Co l : = true;
Dizq [Nr - Col : = true
end'

procedure Ocupar( var Col: Tipocol; var Ddch: DiagonalDchalzda;


var Dizq: DiagonalIzdaDcha; Nr, Co: word);
begin
Co l[Co) := false;
Ddch[Nr + Co) : = fal se;
Dizq[Nr - Col : = false
end;

begin
ClrScr;
write( 'Intr oduzca dimensin del tablero: ');
repeat

L
290 Estructura de datos

r eadl n ( Nf )
until Nf < = N;
for i : =1 to Nf do Col ibr e[ i] := t rue ;
for i : =2 to 2 *Nf do Dd c h[i] : = tr ue ;
for i : = 1 - Nf to Nf - 1 do Dizq [ i l : = t rue ;
Pcre a r(Cp) ; Nr := O; Co l : = O;
Pm e t er (C p, Nr , Col ) ;
while (Nr < Nf) and not Pvac i a(C p) do
begin
Nr : = Nr + 1 ; Colo cado : = fals e ;
while not Co locado and (C ol < Nf ) do
begin
Co l := Col + 1 ;
if Co libr e[Col] then
if Ddch[Nr + Col] then
if Diz q[ Nr - Co l] then
begin
Ocupa r (Co l ibr e , Ddc h, Di zq , Nr , Col) ;
Colocado : = t rue;
Pm e t e r (C p , Nr , Co l );
CA l := O
end
end;
if not Col oca d o then
begin
if Cp A. Nr < > O then
begin
Lib e rar(C olib re , Ddch, Diz q, Cp ' .Nr, CpA . Col);
Nr : = CpA .Nr - 1 ;
Col := CpA . Col ;
end;
Pbo rrar (Cp)
end
end;

if pvaci a( Cp) then


wr it e l n ('N O ENCU ENTRO S OLUCION')
else
Li s t a rpila( Cp)
end.

9.5.4. Problema de la mochila

Un esforzado correo desea llevar en su mochila exactamente v kilogramos, se tiene para


elegir un conjunto de objetos de pesos conocidos. Se desea cargar la mochila con un
peso que sea igual al objetivo.
El planteamiento del problema de la mochila: dado un conjunto de pesos pI, p2,
p3, .. pn (enteros positivos), estudiar si existe una seleccin de pesos que totalice exac-
tamente un valor dado como objetivo v . Por ejemplo, si V = 12 Y los pesos son 4 , 3, 6, 2 ,
1, se pueden elegir el primero, el tercero y el cuarto, ya que 4 + 6 + 2 - 12 . La
representacin de los pesos se hace con un vector de nmeros enteros.
-

Recursividad: algoritmos recursivos 291

const
N = ... { m ximo de pesos prev i s t o }
type
Vector = array [ l . . N] of in t ege r;
var
Peso s: Ve ctor;

El algoritmo para solucionar el problema tiene como tarea bsica aadir un peso
nuevo, probar si con ese peso se alcanza la solucin, o se avanza hacia la solucin. Es
una bsqueda sistemtica de la solucin hacia adelante. Si llegamos a una situacin de
impasse, en la que no se consigue el objetivo por que siempre es superado, entonces
se retrocede para eliminar el peso aadido y probar con otro peso para inspeccionar si a
partir de l se consigue el objetivo. Esto es, realizar otra bsqueda sistemtica.
La bolsa donde se meten los pesos viene representada por un tipo conjunto. Al aa-
dir un peso, la anotacin se realiza acumulando el peso y metiendo en la bolsa, el con-
junto, el ndice del peso. Para borrar la anotacin se opera a la inversa.

CODIFICACiN

const
N = . . . , {mx im o de pesos previsto }
type
Vec t or - array[l . . N] of i nteger ;
var
Pesos : Vec tor;
Bo l sa : set of 1 .. N;
So l uc i o no boolean;
V : in teger ; {Obje tivo}
{V : Es el objet i vo }
{Candidato : I nd i ce de l peso a aa dir }
{Cuenta : Sum a parc i a l de pesos }

procedure Moc hi la(V : i n teger ; Ca n didato : i n teger;


Cu e n ta: i n teger ; var S : boo l ea n );
begin
if Cuenta = V then
S := t rue
el se if (C uenta < V) and (Candidato <= N) then
begin
{Es a n o tado el objeto Can didat o y sigue l a b squeda}
Bo l sa : = Bolsa + [Ca n d i dato] ;
Mochi l a(V , Ca ndidato + 1, Cuenta + Pe sos[Cand i dato] , S) ;
if not S then {Es excluido Cand i dato , para s egu i r
ta nt ea n do co n si g ui e n te }
begin
Bo l sa : = Bolsa - [ Candida t o ];
Mochila(V , Ca nd idato + 1 , Cue n ta , S)
end
end
end
292 Estructura de datos

La llamada a Mochila desde el bloque principal transmite el objetivo V, el candi-


dato 1 y la suma de pesos O.

Mochila (V , 1. o, Solue i on) ;

Eliminacin de la recursin en el problema de la mochila


Para eliminar la recursividad introducimos una pila de enteros para almacenar el candi-
dato actual y en otra pila de nmeros reales almacenar la suma parcial de pesos.
Las llamadas recursivas a Mochila se producen en dos puntos, por lo cual el proble-
ma de guardar la direccin de retomo lo solventamos con otra pila de enteros, en la que
almacenamos tres posibles valores:

O. Indica que la llamada a Mochila procede de fuera del procedimiento.


l. Indica que es una llamada recursiva a Mochila, en la cual se incluye Pesos
[Candidato] dentro de la solucin.
2. Indica que es la llamada recursiva a Mochila, consecuencia de la vuelta atrs al
no alcanzarse la solucin completa.

Para realizar el procedimiento no recursivo de Mochila hay que incorporar la unidad


Pilas para nmeros enteros y para nmeros reales.

uses p i laint , Pi l areal ;


procedure Mo ch i l a (V : in tege r; Ca ndi dat o: int ege r; Cu enta : in te ger;
var s : boo l ea n ) ;
var
Pc an d i , P s tat : Pi l i nt ;
Pcuent : P i lreal;
St, C: i n t eger ;
Pso : real ;
begin
S : = f a l se;
Pcr e ar(Pc a ndi) ;
P i la real .P c r ea r (Pcue nt ) ;
Pcrear(Ps t at) ;
Pmeter(O, Pstat) ; {Es as i gnado e l estado inicial}
repeat
if Cue n ta = V then
S : = true
el se if (C uent a < V) and (Ca nd i d at o <= N ) then
begin
{Es ano t ado e l obje t o Cand i dato y sigue l a b squeda}
Bols a : = Bo lsa + [ Can d id a t o ];
Cuenta := Cue n ta + Pesos [Cand i dato] ;
P i l area l. Pmeter(Cue n ta , Peue nt ) ;
Candi d ato := Candi dato + 1;
Pmet er (1 , Pstat) ;
end
el se if (Cuenta> V) and (Cima (Pstat) = O) or
(Cand idato > N) then
Recursividad: algoritmos recursivos 293

begin
Ca n dida t o : = Ca n d i dato - 1;
Pborrar( Pstat ) ;
end
else if Cim a (Pstat) = 1 then
begin {Se ex cluye al c andidato y se vuelve a prob a r}
Bols a : = Bol sa - [Candidato ];
P i la real. Ps a car (Cuenta , Pcu e n t);
Ca ndidato := Ca ndidat o + 1;
Pborr ar (Pstat) ;
Pmeter(2, Pstat)
end
el se if C im a (Pstat) = 2 then
begin
Candi dato : = Ca n d idat o - 1 ;
Pborrar( P stat )
end
until Pv a c ia (Ps t at) or S
end;

{Al h abe r dos unid ad es de p i las las refer e n cias a l as r utinas d e l a


unidad P il a real las cual ifi c amos co n s u nombre . }

9.5.5. PROBLEMA DEL LABERINTO


Se desea simular el juego del laberinto. En el laberinto hay muros por los que no se
puede pasar. El viajero debe moverse desde una posicin inicial hasta la salida del labe-
rinto. El laberinto est representado por una matriz de N x N, los muros son representa-
dos en la matriz por celdas que contienen el carcter 0, los caminos por celdas con el
carcter l. La salida del laberinto viene indicada por la celda que contiene una S. La
entrada al laberinto es nica, sus coordenadas son conocidas.
La representacin de datos es:
const
N = 12 ; { tama o del laberi nto}
Nor t e = 1;
Sur = N ;
Oe s t e = 1;
Es t e = N;
type
La t i tud = Norte .. Su r;
Lo ngitud = Oes te .. Este ;
Labe rin t o = array[ Lat i tud , Lo n g itud] of char o

ALGORITMO

El viajero parte de una casilla inicial. Desde una casilla puede moverse a cuatro posibles
casillas (hacia el Norte, el Oeste, el Sur o el Este). El movimiento estar permitido si en
la nueva casilla no hay un muro. Cada vez que se pasa por una casilla se marca con
un '*' para as saber el camino seguido hasta la salida. Si llegamos a una situacin de
impasse, es decir estamos en una casilla desde la cual ya no podemos avanzar: se
desanota la casilla, se marca la casilla como si fuera un muro para no volver a pasar por
296 Estructura de datos

L [ Af.Lf] := ' S ';


Ex i to := f a l se ;
So l ue l ab e r ( AO , L O, Ex ito) ;
if Ex i t o then
Ve rlab(L)
else
writeln ( , HorrOr n o sa limos del laber in to !!' )
end.

9.5.6. Generacin de las permutaciones de n elementos


La resolucin est basada en la ley de fOlmacin de las permutaciones de n elementos.
Partiendo de las Permutaciones de O elementos se obtienen las Pelmutaciones monarias
tomando l(k) elemento y situndolo en todas las posiciones posibles: p = l. Las Permu-
taciones binarias se obtienen tomando el 2(k) elemento y situndolo en todas las posi-
ciones posibles: p = 2, p = l. En definitiva, en el paso i el elemento i debe colocarse en
las p = i, P = i - 1, p = i - 2, ... , p = 1. Para ello el array A est indexado de O a n,
guardando en la posicin p el ordinal de la permutacin (k) y en la posicin k, ordinal de
la anterior permutacin. El primer valor de p = O. Cuando se alcanza k = n es escrito el

contenido de la permutacin y despus el elemento k es colocado en A[P] para as


colocar el elemento k en posicin anterior. La solucin se plantea recursivamente,
aplicando una variacin a la estrategia de backtracking para as agotar todas las solu-
ciones que ahora se convierten en grupos de n elementos.

CODIFICACiN

program Generadorp erm u t a eio n e s ;


uses e rt;
const
Maxg r a d o = 1 0 ;
B: array [O .. Maxgrado ] of ehar =
( ' X ' ,~ , ' B ' , 'C' , ' D " , ' , ' F', ' G ' , ' H ' , '1', ' J ') ;
type
Apun t ado r = O .. Ma x grado ;
var
A : array [ Apu n tador ] of Apu ntado r;
N : integ er;
X : e har;
procedure proee sopermu t ac i on ;
var
q :Apuntador;
begin
q : = O;
while A [ q ] <> O do
begin
wri te ( B [ A [q]] ) ;

q : =A[ q ];
end;
wr i t e ( , , : 1 0 - N)
end; ,
procedure permu ta( K,N: Apu n tado r ) ; .\



,

,

j
Recursividad: algoritmos recursivos 297

var
p : Apuntador ;
begin
P .. -- O ,.
repeat
A[K ] :=A[pJ;
A[p] .'-K'- ,
if K = N then
procesopermuta c i o n
else

pe r muta(K+1.N) ;
{Ah ora se " co l o ca" en la a n t eri o r , rep r esentad o por A [K ] )
A [ p] : =A [ K] ;
p : = A [ p];
until p = O;
write l n ;
end;

begin
c lr scr ;
repeat
write( 'N u mero de e l eme n t o s a permutar:') ;re ad ln(N);
until N in [l .. Maxgr a d o] ;
write l n( 'Permut aci o n es de ': 50 ,N, 'el e mentos ' );
A [ O] : = O;
Permu t a (l , N);
X := readkey
end.

9.6. PROBLEMA DE LA SELECCiN PTIMA


En los problemas del Salto de caballo, Ocho reinas y Mochila se ha aplicado la estrate-
gia de vuelta atrs para encontrar una nica solucin. Con la misma base, se ha hecho
una ampliacin para encontrar as todas las soluciones. Ahora no se trata de encontrar
una situacin fija o un valor predeterminado, sino de encontrar del conjunto de solucio-
nes la ptima segn unas restricciones definidas.
En trminos reales, este es el problema del viajante que tiene que hacer las maletas
seleccionando entre n artculos, aquellos cuyo valor total sea un mximo (lo ptimo, en
este caso, es el mximo establecido) y su peso no exceda de una cantidad.
Seguimos aplicando la estrategia de vuelta atrs para generar todas las soluciones
posibles, y cada vez que se alcance una solucin guardarla si es mejor que las solucio-
nes anteriores segn la restriccin definida.

if solu cion then


if mej o r ( s o luc i on) then
o pti mo :=soluc io n

La tarea bsica en esta bsqueda sistemtica es investigar si un objeto i es adecuado


incluirlo en la seleccin que se ir acercando a una solucin aceptable, y continuar la
bsqueda con el siguiente objeto. En el caso de que lo que haya que hacer sea excluirlo
298 Estructura de datos

de la seleccin actual, el criterio para seguir con el proceso de seleccin actual es que el
valor total todava alcanzable despus de esta exclusin no sea menor que el valor pti-
mo (mximo) encontrado hasta ahora. Cada tarea realiza las mismas acciones que la
tarea anterior, por lo que puede expresarse recursivamente. Al estar buscando la selec-
cin ptima, hay que probar con todos los objetos del conjunto.
Consideramos que el valor mximo alcanzable inicialmente es la suma de todos los
valores de los objetos que disponemos. Debido a la restriccin del peso, posiblemente el
valor ptimo alcanzado sea menor.

9.6.1. El viajante de comercio


Suponemos que el viajante tiene 10 objetos. La entrada de datos es la informacin aso-
ciada con cada objeto: <Peso, Valor>. El peso mximo que puede ser transportado varia-
r desde el mnimo peso hasta el peso total de los objetos, con un incremento de 3 y un
mximo de 10 salidas.
El valor mximo que pueden alcanzar los objetos es la suma de los valores de cada
uno, est representado por la variable Tva 1 o r. El valor ptimo alcanzado en el proceso
transcurrido est en la variable Mvalor.
Los parmetros del procedimiento recursivo son los necesarios para realizar una nueva
tarea: r, nmero de objetos a probar; Pt, peso de la seleccin actual; Va , valor mximo
alcanzable por la seleccin actual; y Mva 1 o r , que es el valor mximo obtenido en el
proceso transcurrido.

CODIFICACIN
program Optima(inpu t , ou tput);
uses crt;
const
N = 10 ;
type
Indice - 1 .. N;
Objet o - Record
va l: i nteger;
pso : integ er
end;
Li sta = array [Indicel of Objeto ;
Conj = set of Indice;
var
A: Lista;
Psomx, Tpeso,
Tvalor, Mva lor ,
T, K: intege r ;
Ac t, Opt o Conj ;

procedure Obj etos(va r G :Li s t a ; var TV, Tp :int eger) ;


var
K:integer;
begin
writeln;
Recursividad: algoritmos recursivos 299

Tv := O; Tp := o;
for K := 1 to N do
begin
write( 'Objeto', K,'.', 'Peso y Valor:');
readln(G[K] .pso,G[K] .val);
Tv := Tv + G[K] .val;
Tp := Tp + G[K] .pso
end
end;

function Min(A:Lista) :integer;


var
K,M:integer;
begin
M := A[l] .pso;
for K := 2 to N do
if A[K] .pso < M then
M := A[K] .pso;
Min := M
end;

procedure Solucion (S:Conj; P,V:integer);


{Salida del conjunto de objetos}
var
K:integer;
begin
i f S < > [ ] then
begin
wri te (' Seleccion ptima: ') ;
for K := 1 to N do

if K in S then
Wr i t e (' < ' , A [ K] . P s o, ' , ' , A [ K] . val, '>' ) ;
wr i t e 1 n (' P e s o: ' , P, ' Va 1 o r: ' , V)
end
end;

{El procedimiento recurSlVO, Maleta, es el que encuentra la seleccin
ptima}
procedure Maleta (1:indice; Pt,Va:integer;var Mvalor: integer);
var
VaEx:integer;
begin
if Pt + A[1] .pso <= Psomx then {El objeto 1 se incluye}
begin
Act := Act + [1];
if 1 < N then
Maleta (1+l,Pt+A[1] .pso,Va, Mvalor)
elee if Va > Mvalor then {Todos los objetos han sido probados y}
begin {se ha obtenido un nuevo valor ptimo}
Opt : = Act;
Mvalor := Va
end;
Act := Act - [1] {Vuelta atrs para ensayar la exclusin}
end;
{Proceso de exclusin del objeto 1 para seguir la bsqueda
sistemtica con el objeto Y+l}

300 Estructura de datos

Va Ex : = Va - A [ 1 ] . val ;
{VaE x es e l va l or mx i mo q u e pod r a alca n za r la se l ecc i n ac t ua l)
if VaEx > Mvalor then
if 1 < N then
Maleta ( 1+1, Pt , Va Ex, Mv alor)
el Be begin
Opt := Act;
Mvalor : = Va Ex
end;
{s i Va Ex < Mvalor es i ntil seguir ensaya n do ya que no va a
s u p er ar e l va l o r pt im o act u a l : Mval o r}
end;

begin
c l rscr ;
write l n ('Entrada de ' , N , 'Objetos') ;
Obje t os (A , Tval o r , Tpeso) ;
c l rs cr;
wri te ('Peso: ') ;
for K := 1 to N do
wr i t e (A [ K] . P s o : 6 ) ;
write l n ;
write ('v al or : ') ;
for K : = 1 to N do
wr ite (A [ K]. va l: 6) ;
wr it e ln;
{ El p eso mxi mo i r varian d o d esde el mni mo , h as t a al canzar e l
mx i mo o 10 pruebas , cada prueba au menta e l peso e n 3 un i dades}
T := Min (A) ; Psomx : = T ;
repeat
Ac t := [ ]; Op t : = [ 1;
Mvalor : = O;
Maleta (l, O,T va l or , Mvalor ) ;
so lu c ion (Opt,Psomx , Mvalo r ) ;
Psom x := Psomx+3
until (Psomx > Tpeso) or (Pso mx > T+I0 * 3)
end.

9.7. PROBLEMA DE LOS MATRIMONIOS ESTABLES

El planteamiento del problema es el siguiente: dados dos conjuntos A y B, disjuntos y


con igual nmero de elementos, n, hay que encontrar un conjunto de n pares (a,b) , tales
que a pertenece A, b pertenece a B y cumplan ciertas condiciones.
Una concrecin de este planteamiento es el problema de los matrimonios esta-
bles. Ahora A es un conjunto de hombres y B un conjunto de mujeres. A la hora de
elegir pareja, cada hombre y cada mujer tienen distintas preferencias. Se trata de for-
mar parejas, matrimonios estables. De las n parejas, en cuanto exista un hombre y
una mujer que no formen pareja pero que se prefieran frente a sus respectivas parejas,
se dice que la asignacin es inestable ya que tender a una ruptura para buscar la pre-
ferencia comn. Si no existe ninguna pareja inestable se dice que la asignacin es es-
table.
Recursividad: algoritmos recursivos 301

En el problema se hace la abstraccin de que la lista de preferencias no cambia al


hacer una asignacin.
Este planteamiento caracteriza ciertos problemas en los que hay dos conjuntos de
elementos y se ha de hacer una eleccin segn una lista de preferencias. As, pensemos
en el conjunto de ofertas de vacaciones y el conjunto de turistas que quieren elegir una
de ellas; la eleccin de facultad por los chicos de COU ...

ALGORITMO

Una forma de buscar solucin es aplicar la bsqueda sistemtica de los algoritmos de


vuelta atrs. La tarea bsica es encontrar una pareja para un hombre h segn la lista de
preferencias, esta tarea bsica la realiza el procedimiento ensayar:

procedimiento En sayar(H : T ipo Homb r e)


var
R: en t e ro
inicio
Desde R r 1 hasta n hacer
<To ma r pre f ere n c i a R-s ima de homb r e H>
si acept ab le entonces
<Anot ar matri mon io >
si <H no es el l timo hombre> entonces
En sayar(H +l)
sino
<El co njunt o d e mat rim onios e s e st able >
fin_Si
<Cancelar el ma t r i mon i o>
fin_si
fin_Desde
fin

Ahora afrontamos la tarea de representacin de datos. El Tipohombre, Tipomujer


son representados por un subrango entero; por tanto, hacemos la abstraccin de repre-
sentar tanto un hombre como una mujer por un nmero que es el ordinal del rango de
hombres o de mujeres. Para representar las preferencias de los hombres por las mujeres
se utiliza una matriz de mujeres. Recprocamente, las preferencias de las mujeres por los
hombres son representadas por una matriz de hombres.
La solucin del problema ha de ser tal que nos muestre las parejas (hombre-mujer)
que forman la asignacin estable. Dos vectores, uno de las parejas de los hombres y el
otro de parejas de las mujeres, representan la solucin.

const
N = ... ; {N me ro de pa rej as}
ty pe
T ipohombre = 1 .. N;
Tipomuje r = 1 .. N;
Pr efhombre s = array [Tipoh o mbre , 1 .. NJ of T ipomujer;
Pr ef muje re s = array [Ti pomu j er, l .. NJ of Ti pohombr e ;
Par h o mbres= array [Tipohombre J of Ti po mu j e r;

,
1
302 Estructura de datos

Par muje r es = array [ Ti p omu j eres ] of Ti po h o mbre;


var
Phb: Pre fh o mbr es ;
Pmj : Pr e f mujeres ;
V : Parho mb re s ;
F: Pa r mujeres;

La informacin representada por V y F determina la estabilidad de un conjunto de


matrimonios. Este conjunto se construye paso a paso casando hombre-mujer y compro-
bando la estabilidad despus de cada propuesta de matrimonio. Para facilitar la inspec-
cin de las parejas ya forllladas utilizamos un array lgico:

Soltera: array [ Tipomu j er] of boolean;

Solter a [J] a true quiere decir que la mujer J todava no ha encontrado pareja. Para
determinar si un hombre K ha encontrado pareja puede utilizarse otro array similar al de
Soltera, o bien sencillamente si K < H es que K ya encontr pareja (H es el hombre actual
que busca pareja).
Con todas estas consideraciones de tipos de datos ya podemos proponer una solu-
cin ms elaborada:

procedimiento Ensayar(H : T i poHombre)


var
R : e n tero ;
M: Tipomu je r;
inicio
Desde R r 1 hasta N hacer
M r Phb [H, R] {Mujer candidata }
si Soltera[M] y <Estab l e> entonces
V [H ] r M
F[ M ] r H
So l te r a [M ] r False
si H < N entonces
Ensay ar(H+ l)
sino
<A n o t a r, co njunt o ya es es t ab l e>
fin_si
Solter a [ M] r True
fin_si
fin_desde
fin_procedimiento

La accin ms importante que nos falta es determinar la estabilidad que ha sido


expresada como <Estable>. Pues bien, la buscada estabilidad se encuentra por com-
paraciones entre las distintas preferencias. Las preferencias vienen dadas por el rango
de 1 a N. Para facilitar el clculo de la estabilidad son definidas dos matrices:

Rhm : array [ Tipohomb r e ,Ti pomu j er] of 1 .. N ;


Rmh : array [Tipomuje r, Tipohombre ] of 1 .. N;
Recursividad: algoritmos recursivos 303

tal que Rhm [H , M 1 contiene el orden que ocupa, o rango, de la mujer M en la lista de
preferencias del hombre H. De igual forma, Rmh [M, H 1 contiene el orden del hombre H
en la lista de preferencias de la mujer M. Ambas matrices se determinan inicialmente a
partir de las matrices de preferencias.
El predicado <Estable> parte de la hiptesis de que lo normal es la estabilidad y se
buscan posibles fuentes de perturbarla. Recordemos que se est analizando la estabili-
dad de la posible pareja H y M, siendo M la mujer que ocupa la posicin R en la lista de
preferencias de H (M f- Phb [H , R 1 ) . Hay dos posibilidades:

1. Puede haber otra mujer Mm, por la que H tenga ms preferencia que M, y a su
vez Mm prefiera ms a H que a su actual pareja.
De forma simtrica.
2. Puede haber otro hombre Hh, por el que M tenga ms preferencia que a H, y a su
vez ese hombre prefiera ms a M que a su actual pareja.

La posibilidad 1 se dilucida comparando los rangos Rhm [Mm, H J YRmh [Mm, F [Mm J J
para todas las mujeres ms preferidas que M por el hombre H. Es decir, para todas las
Mm f- Phb [H, 1 1 tales que 1 < R . Adems, todas estas mujeres tienen ya pareja,
ya que si alguna estuviera soltera el hombre H la hubiera elegido ya. Esta posibilidad
puede expresarse:

Es t able ~ true
1 ~ 1
mientras (1 < R) Y Est able hacer
Mm ~ Phb [ H,I ]

si no so ltera[Mm] entonces
Estable ~ Rmh [ Mm, H] < Rmh [ Mm, F [Mm] ] {Es e s table s i p r e f iere ms }
fin si {a su act u al pare ja }
fin_mientras

Para analizar la posibilidad 2 razonamos de forma simtrica. Hay que investigar a


todos los hombres Hh por los cuales tiene ms predileccin la mujer M que a su pareja
actual H:

1 ~ 1
Tope ~ Rm h[M,H ]
mientras (1 < Tope) y Estab le hacer
Hh ~ P m j [M ,I]
1 ~ 1 +1
si Hh < H entonces { Hh ya tiene par eja }
Est able ~ Rhm [ Hh, M] > Rhm[ Hh , V[H h]] {Es table s i Hh pr efi ere }
fin si { a su actual p areja . }

La codificacin de estas dos posibles fuentes de inestabilidad la realizamos en una


funcin lgica anidada al procedimiento ensayar.
304 Estructura de datos

CODIFICACiN
program MatrimonioEstable;
uses
crt;
const
N = 9; {Nmer o de parejas a formar}
type
Tipohombre = 1 .. N;
Tipomujer = 1 .. N;
Prefhombres = array [Tipohombre, 1 .. Nl of Tipo mu je r;
prefmujeres = array [Tip o muje r , 1 .. Nl of Tipohombre;
Parhombres = array [Tipohombrel of Tip omujer;

Parmujeres = array [Tipomujerl of Tipohombre;


Flags = array[Tipomujerl of boolean;
Matranghb = array[Tipohombre, TipomujerJ of 1 .. N;
Matrangmj = array[Tipomujer, Tipohombrel of 1 .. N;
var
Phb: Prefhombres;
Pmj: Prefmujeres;
V: Parhombres;
F: Parmujeres;
Soltera: Flags;
Rhm: Matranghb;
Rmh: Matrangmj;
H: Tip o hombre;
M: Tipomujer;
R: integer;

procedure Escribir;
var
H: Tipohombre;
begin
write('Solucin: ');
for H := 1 to N do
write('<H', H, ',M', V [H), '>; ');
writeln
end;

procedure Ensayar(H: Tipohombre);


var

R: lnteger;
M: Tipomujer;
function Estable(H:Tipohombre;M:Tipo mujer;R:integer) :bo o lean;
var
Hh: Tipohombre;
Mm: Tipomujer;
1, Tope: integer;
Es: boolean;
begin
Es := true;
1 := 1;
while (1 < R) and Es do
begin
Mm := Phb[H,11;
1 := 1+1;
Recursividad: algoritmos recursivos 305

if not Sol t er a[Mm) then


Es := Rmh[Mm,H) < Rmh[Mm,F[Mm))
end;
1 : = 1;
To-pe : = Rmh [M, H) ;
while (1 < Tope) and Es do
begin
Hh : = Pmj [M, 1) ;
1 := 1 + 1;
if Hh < H then
Es : = Rhm[ Hh,M) > Rhm[Hh,V[Hh ))
end;
Estable := Es
end;
begin {Ensayar}
I for R := 1 to N do
begin
M := Phb [ H, R];
if So ltera [Ml and Es table( H, M, R) then
begin
, V[H) "" -- M",
F [ M) "" -- H",
SOltera [M) := false;
if H < N then
Ensayar (H + 1)
else {Encontrada una asignaci n estable }
Escrib i r ;
Soltera [M) : = true
end
end
end;
begin (bloque principal)
clr scr ;
(Entrada de rango de preferencias de hombres)
for H := 1 to N do
begin
writeln('Preferen c ias de hombre', H,' segn ran go de 1 a " N);
for R := 1 to N do
begin
read(Phb[H, R)) ;
Rhm[H, Phb[H, R]) : = R
end
end;
( En trada de ra ngo de preferencias de mujeres)
for M : = 1 to N do
begin
wr i te ln('Pr efe ren cias de mujer', M, ' seg n rang o de 1 a " N) ;
for R := 1 to N do
begin
read(Pmj [M, R]);
Rmh[M,Pmj [M, Rl] := R
end
end;
for M := 1 to N do
Soltera [M) : = true;
Ensayar(l)
end.
306 Estructura de datos

RESUMEN
La recursin (recursividad) pellnite resolver problemas cuyas soluciones iterativas son dificiles
de conceptualizar: un procedimiento o funcin que se \lama a s misma. Normalmente, una solu-
cin recursiva es menos eficiente en trminos de tiempo y operaciones suplementarias que entra-
an las \lamadas extra a procedimientos; sin embargo, en numerosas ocasiones el uso de la recur-
sin permite especificar una solucin muy natural y senci\la a problemas que en caso contrario
seran muy difciles de resolver. Por esta razn, la recursividad es una herramienta muy importan-
te y potente para la resolucin de problemas con programacin.
El uso apropiado de la recursividad se debe considerar antes de su utilizacin. Una vez toma-
da la decisin, el programador debe tener mucha precaucin en proporcionar condiciones de ter-
minacin para detener las llamadas recursivas. Es muy fcil entrar en un bucle infinito si no se
incluyen condiciones de terminacin adecuadas.
Algunos lenguajes de programacin no permiten la recursividad. Por consiguiente, un progra-
mador puede desear resolver un problema utilizando tcnicas recursivas mediante el uso de pseu-
docdigo. Incluso, como en el caso de Pascal, que soporta recursividad, el programador puede
tratar de intentar reducir las operaciones y el tiempo auxiliar implicado en el proceso recursivo
simulando la recursividad.

EJERCICIOS

9.1. Suponer que la funcin G est definida recursivamente de la siguiente forma:

1 si x ~ y
G(x, y) =
G(x-y+I)+l SI Y<x

Siendo x,y enteros positivos.


a) Encontrar el valor de G (8,6).
b) Encontrar el valor de G (100,10).
9.2. Sea H(x) una funcin definida recursivamente '<fx > O, siendo x un entero:

1 si x = 1
H(x) =

H(x / 2) + 1 si x> I

a) Encontrar el valor de H(80).


b) Cmo podemos describir lo que hace esta funcin?

9.3. Oefinimos C(n,k) como el nmero de combinaciones de n elementos agrupados de k en k,


es decir, el nmero de los diferentes grupos que se pueden formar con k miembros dado un
conjunto de n miembros para elegir. As, por ejemplo, si n = 4 ({ A,B,C,O}) C( 4,2) = 6 que
sern: (A,B), (A,C), (A,O), (B,C), (B,O), (C,O).
matemticamente C(n,k) podemos definirla:
C(n,I)=n
C(n,n) = I
C(n,k) = C(n - 1, k - 1) + C(n - 1, k) '<fn > k, k > I

,
Recursividad: algoritmos recursivos 307

a) Encontrar el valor de C(8,5).


b) Escribir una funcin recursiva para calcular C(n,k).

9.4. Eliminar la recursividad de la funcin C(n,k). Escribir la funcin C(n,k) de forma iterativa
utilizando una pila para eliminar la recursividad.
9.5. Dada la siguiente funcin recursiva:

function Reves( N: i n teger) : c h a r;


var e: cha r;
begin
r e ad (e) ;
if eo ln then
Rev e s := ' * '
el Be
Rev e s := Reves(l) ;
wr it e(e )
end;

a) Qu hace la funcin ?
b) Hacer un seguimiento con esta llamada: Reves(l).

9.6. Dado el siguiente procedimiento recursivo:

procedure Desco n ocido(N , Despl : i ntege r ) ;


var
K : inte ge r;
begin
if N > O then
begin
Des c onocido( N- l , Des pl +l) ;
for K := 1 to Des pl do
wri te( ' ');
for K : = 1 to Des p l do
wri t e ( ' I ' ) ;
writeln;
Des c onoc i do( N- l, Des p l +l )
end
end;

Hacer un seguimiento del procedimiento para la llamada Desconocido (4, 1).


9.7. Eliminar la recursividad del procedimiento escrito en 9.6. Escribir de nuevo el procedi-
miento Desconocido del ejercicio 9.6 utilizando una pila.
9.8. Realizar una funcin recursiva que calcule la funcin de Ackermann definida de la siguien-
te fOIlIla:

A(m,n) = n+ l si m = O
A(m,n) = A(m-l,l) si n = O
A(m,n) = A(m-I,A(m,n-l si m > O Y n > O

9.9. Escribir la funcin de Ackellnann eliminando la recursividad.


9.10. La resolucin recursiva de las Torres de Hanoi ha sido realizada con dos llamadas recursi-
vas. Volver a escribir el procedimiento de resolucin con una sola lmmada recursiva.
Nota: Sustituir la ltima llamada por un bucle repetir-hasta.
-----------------------------------.

308 Estructura de datos

PROBLEMAS
9.1. En el problema de las 8 reinas se encuentran 92 soluciones diferentes. Hacer los cambios
necesarios en el procedimiento de resolucin para que nos muestre nicamente las solucio-
. , .
nes no slmetncas.
9.2. Escribir un programa que tenga como entrada una secuencia de nmeros enteros positivos
(mediante una variable entera). El programa debe de hallar la suma de los dgitos de cada
entero y encontrar cul es el entero cuya suma de dgitos es mayor. La suma de dgitos ha
de ser con una funcin recursiva.
9.3. Sea A una matriz cuadrada de n x n elementos, el determinante de A podemos definirlo de

manera recursIva:
a) Si n = 1 entonces Deter(A) = al.l'
b) Para n > 1, el determinante es la suma alternada de productos de los elementos de una
fila o columna elegida al azar por sus menores complementarios. A su vez, los menores
complementarios son los detellninantes de orden n-l obtenidos al suprimir la fila y
columna en que se encuentra el elemento.
Podemos expresarlo:
n
Det(A)= L (-ly+J *A[i,j] * Det(Menor(A[i,j])); para cualquier columna}
; = 1

o
n
Det(A)= L (-ly+J *A[i,j] * Det(Menor(A[i,j])); para cualquier fila i
j ~ 1

Se observa que la resolucin del problema sigue la estrategia de los algoritmos divide y
vence.
Escribir un programa que tenga como entrada los elementos de la matriz A, y tenga como
salida la matriz A y el determinante de A. Eligiendo la fila 1 para calcular el determinante.
9.4. Escribir un programa que transforme nmeros enteros en base lOa otro en base B. Siendo
la base B de 8 a 16. La transformacin se ha de realizar siguiendo una estrategia recursiva.
9.S. Escribir un programa para resolver el problema de la sub secuencia creciente ms larga. La
entrada es una secuencia de n nmeros a" a2' a3, ... , a n ; hay que encontrar la subsecuencia
ms larga ail, a2, ... ak tal que a1 < aj2 < a3 ... < ak Y que il < i2 < i3 < ... < ik. El programa
escribir tal subsecuencia.
Por ejemplo, si la entrada es 3, 2, 7, 4, 5, 9, 6, 8, 1, la subsecuencia creciente ms larga
tiene longitud cinco: 2, 4, 5, 6, 8.
9.6. El sistema monetario consta de monedas de valor PI' P2, P3' ... ,Pn (orden creciente) pesetas.
Escribir un programa que tenga como entrada el valor de las n monedas en pesetas, en
orden creciente, y una cantidad X pesetas de cambio. Calcule:
a) El nmero mnimo de monedas que se necesitan para dar el cambio X.
b) Calcule el nmero de formas diferentes de dar el cambio de X pesetas con lap monedas.
Aplicar tcnicas recursivas para resolver el problema.
9.7. Dadas las m primeras del alfabeto, escribir un programa que escriba las diferentes agrupa-
ciones que se pueden formar con n letras (n < m) cada una diferencindose una agrupacin
de otra por el orden que ocupan las letras, o bien por tener alguna letra diferente (en defini-
tiva, formar variaciones Vm,n).
Recursividad: algoritmos recursivos 309

9.8. En un tablero de ajedrez se coloca un alfil en la posicin (xo, Yo) Y un pen en la posicin
(1, ), siendo 1 < = ) < = 8. Se pretende encontrar una ruta para el pen que llegue a la
fila 8 sin ser comido por el alfil. Siendo el nico movimiento permitido para el pen el de
avance desde la posicin (i,) a la posicin (i + 1, ). Si se encuentra que el pen est
amenazado por el alfil en la posicin (i,), entonces debe de retroceder a la fila 1, columna
) + l o) - 1 {(l,) + 1), (1,) - 1)}.
Escribir un programa para resolver el supuesto problema. Hay que tener en cuenta que el
alfil ataca por diagonales.
9.9. Dados n nmeros enteros positivos, encontrar combinacin de ellos que mediante sumas o
restas totalicen exactamente un valor objetivo Z. El programa debe de tener como entrada
los n nmeros y el objetivo Z; la salida ha de ser la combinacin de nmeros con el opera-
dor que le corresponde.
Tener en cuenta que pueden formar parte de la combinacin los n nmeros o parte de
ellos.
9.10. Dados n nmeros, encontrar combinacin con sumas o restas que ms se aproxime a un
objetivo Z. La aproximacin puede ser por defecto o por exceso. La entrada son los n n-
meros y el objetivo y la salida la combinacin ms prxima al objetivo.
9.11. Dados n nmeros encontrar, si existe, la combinacin con los n nmeros que mediante
sumas o restas totalice exactamente el objetivo Z.
9.12. Dados n nmeros, encontrar la combinacin con los n nmeros que mediante sumas o res-
tas ms se aproxime a el objetivo Z.
9.13. Un laberinto podemos emularlo con una matriz n x n en la que los pasos libres estn repre-
sentados por un carcter (el blanco, por ejemplo) y los muros por otro carcter (el # por
ejemplo). Escribir un programa en el que se genere aleatoriamente un laberinto, se pida las
coordenadas de entrada (la fila ser la 1), las coordenadas de salida (la fila ser la n) y
encontrar todas las rutas que nos llevan de la entrada a la salida.
9.14. Realizar las modificaciones necesarias en el problema del laberinto 9.12 para encontrar
la ruta ms corta. Considerando ruta ms corta la que pasa por un menor nmero de ca-
sillas.
9.15. Una regin castellana est formada por n pueblos dispersos. Hay conexiones directas entre
algunos de estos pueblos y entre otros no existe conexin aunque puede haber un camino.
Escribir un programa que tenga como entrada la matriz que representa las conexiones di-
rectas entre pueblos, de tal forma que el elemento M(i,j) de la matriz sea:

o si no hay conexin directa entre pueblo i y pueblo j.


M(i,j) =
d hay conexin entre pueblo i y pueblo) de distancia d.

Tambin tenga como entrada un par de pueblos (x,y) y encuentre un camino entre ambos
pueblos utilizando tcnicas recursivas. La salida ha de ser la ruta que se ha de seguir para ir
de x a Y junto a la distancia de la ruta.
9.16. En el programa escrito en 9.14, hacer las modificaciones necesarias para encontrar todos
los caminos posibles entre el par de pueblos (x,y).
9.17. Referente al problema 9.14, escribir un programa que genere una matriz P de n x n en la
que cada elemento P(i,j) contiene el camino ms corto entre el pueblo i y el pueblo j. Utili-
, . , . .
zar umcamente tecmcas recursIvas.
9.18. El celebre presidiario Seor S quiere fugarse de la crcel de Carabanchel, por el sistema de
alcantarillado, pero tiene dos problemas:


310 Estructura de datos

1) El dimetro de la bola que arrastra es de 50 cm, resulta demasiado grande para pasar
por algunos pasillos.
2) Los pasillos que comunican unas alcantarillas con otras tienen demasiada pendiente y
slo puede circular por ellos en un sentido.
Ha conseguido hacerse con los planos que le indican el dimetro de salida de las al-
cantarillas, as como el dimetro de los pasillos y el sentido de la pendiente que lo
conectan.
Suponiendo que:
1) El Nmero de alcantarillas es N.
2) El Seor S se encuentra inicialmente en la alcantarilla 1 (dentro de la prisin).
3) Todas las alcantarillas (excepto la 1) tienen su salida fuera de la prisin, si bien puede
que sean demasiado estrechas para sacar la bola fuera.
4) Se puede pasar de un pasillo a otro a travs de las alcantarillas estrechas aunque a
travs de dichas alcantarillas no se pueda salir al exterior.
5) Todos los pasillos tienen un dimetro, si bien ste puede ser demasiado estrecho para
poder pasar con la bola.
Escribir un programa que contenga al menos estos procedimientos:
a) Un procedimiento para generar aleatoriamente los dimetros de los tneles del alcanta-
rillado as como los dimetros de salida de las distintas alcantarillas. (Tenga en cuenta
que si se puede ir de la alcantarilla i a la j por el tnel, entonces no se puede ir por el
tnel desde j hasta i.)
b) Un procedimiento de backtraking que resuelva el problema del seor S.
e) Procedimientos para escribir en pantalla el sistema de conexiones as como la posible
solucn encontrada.
,
CAPITULO


o es In arios

10.1. Concepto

de rbol.
10.2. Arboles binarios.

10.3. Arboles de expresin.
10.4. Construccin de un rbol binario.
10.5. Recorrido de un rbol.
10.6. Aplicacin de rboles binarios: evaluacin de expresiones.

10.7. Arbol binario de bsqueda.
10.8. Operaciones con rboles binarios de bsqueda.
RESUMEN.
EJERCICIOS.
PROBLEMAS.
REFERENCIAS BIBLIOGRFICAS.

En este captulo se centra la atencin sobre una estructura de datos, el


rbol, cuyo uso est muy extendido y es muy til en numerosas aplica-
ciones. Se definen formas de esta estructura de datos (rboles genera-
les, rboles binarios y rboles binarios de bsqueda) y cmo se pueden
representar en Pascal, as como el mtodo para su aplicacin en la re-
solucin de una amplia variedad de problemas. Al igual que ha sucedi-
do anteriormente con las listas, los rboles se tratan principalmente
como estructura de datos en lugar de como tipos de datos. Es decir, nos
centraremos principalmente en los algoritmos e implementaciones en
lugar de en definiciones matemticas.
Los rboles junto con los grafos constituyen estructuras de datos no
lineales. Las listas enlazadas tienen grandes ventajas o flexibilidad sobre
la representacin contigua de estructura de datos (los arrays), pero tienen
.
.
[ una gran debilidad: son listas secuenciales; es decir, estn dispuestas de
modo que es necesario moverse a travs de ellas, una posicin cada vez.

311
0,

312 Estructura de datos

Los rboles superan estas desventajas utilizando los mtodos de pun-


teros y listas enlazadas para su implementacin. Las estructuras de datos
organizadas como rboles sern muy valiosas en una gama grande de
aplicaciones, sobre todo problemas de recuperacin de informacin .


10.1. CONCEPTO DE ARBOL

Un rbol (en ingls, tree) es una estructura que organiza sus elementos, denominados
nodos, formando jerarquas. Los cientficos utilizan los rboles generales para represen-
tar relaciones. Fundamentalmente, la relacin clave es la de <<padre-hijo entre los nodos
del rbol. Si existe una arista (rama) dirigida del nodo n al nodo m, entonces n es el
padre de m y m es un hijo de n. En el rbol de la Figura 10.1, los nodos B y C son hijos
del nodoA. Los hijos del mismo padre se llaman hermanos, por ejemplo B y C. Cada nodo
de un rbol tiene al menos un padre, y existe un nico nodo, denominado raz del rbol,
que no tiene padre. El nodo A es el raz del rbol de la Figura 10.1. Un nodo que no tiene
hijos se llama hoja del rbol. Las hojas del rbol de la Figura 10.1 son C, D, E Y F.

. , ' "


.". hola
I
La relacin padre-hijo entre los nodos se generaliza en las relaciones ascendiente ,
(antecesor) y descendiente. En la Figura 10.1 A es un antecesor de D, y por consiguien-
te D es un descendiente de A. Obsrvese que no todos los nodos estn relacionados por
las relaciones ascendente/descendiente: B y C, por ejemplo, no estn relacionados. Sin
embargo, el raz de cualquier rbol es un ascendiente de todos los nodos de ese rbol. Un
subrbol de un rbol es cualquier nodo del rbol junto con todos sus descendientes.
Un subrbol de un nodo n es un subrbol enraizado en un hijo de n. Por ejemplo, la
Figura 10.2 muestra un subrbol de la Figura 10.1. Este subrbol tiene a B como su raz
y es un subrbol del nodo A.

A Padre
A

B, e hijos del nodo A




D, E, F hijos del nodo B
,

D F
B, e hermanos


Figura 10.1. Arbol general.
-

rboles binarios 313

o
Figura 10.2. Un subrbol del rbol de la Figura 10.1.

Debido a la naturaleza jerrquica de los rboles, se puede utilizar para representar en


formacin que sea jerrquica por naturaleza, por ejemplo, diagramas de organizaciones,
rboles genealgicos, rboles de especies animales, etc.

Terminologa complementaria
Adems de los trminos ya citados anteriormente, existen otros tambin de gran impor-
tancia.

Camino Una secuencia de nodos conectados dentro de un rbol.


Longitud del camino Es el nmero de nodos menos uno (r - 1). Si r > 0, se dice que
el camino es propio.
I
Altura del rbol Es el nivel ms alto del rbol. La altura es igual a la longitud del
camino desde el nodo raz a la hoja ms lejana que sea alcanza-
ble desde l. Por ejemplo, la altura del rbol de la Figura 10.3
es 4. Un rbol que contiene slo un raz, tiene de altura l.
Nivel (profundidad) De un rbol (levelo depth), es el nmero de nodos que se
encuentra entre l y la raz. El nodo Luis Carchelejo est en el
.
nivel 3. Por definicin el nmero de niveles de un rbol se
,,- define como el nivel de la hoja ms profunda; as, el nmero de
,,
niveles del rbol de la Figura 10.3 es 4. Observemos que por
definicin, el nmero de niveles de un rbol es igual a la altu-
ra por lo que pueden usarse ambas magnitudes indistintamente.
Grado (aridad) Es el nmero de hijos del nodo. La aridad de un rbol se defi-
ne como el mximo de la aridad de sus nodos.
Hermanos Dos nodos son hermanos si tienen el mismo padre. Se llamarn
hermano izquierdo de n y hermano derecho de n, respectiva-
mente.
Un tipo especial de rbol es el denominado rbol binario y un rbol binario espec-

fico de gran utilidad es el rbol binario de bsqueda.

1 Las definiciones de altura, profundidad y nivel, como se seala en [Franch 93], pg. 220, son contra-
dictorias en algunos textos, que no definen algunos de estos conceptos o los definen slo para un rbol y no
para sus nodos; o bien empiezan a numerar a partir del cero y no del nodo, etc. En nuestro caso y al igual
que hace Franch preferimos numerar a partir del uno para que el rbol vaCo tenga una altura diferente al
rbol con un nico nodo.

314 Estructura de datos

Luis y Juana

Micaela Lucas Mara

Luis
(Carchelejo) Juana Mara

Luis
Graciela Victoria
(Madrid)

Figura 10.3. Arbol genealgico.


,,

10.2. RBOLES BINARIOS


Un rbol binario es un rbol en el que cada nodo no puede tener ms de dos hijos o
descendientes.
En particular, un rbol binario es un conjunto de nodos que es, o bien el conjunto
vaco, o un conjunto que consta de un nodo raz enlazado a dos rboles binarios disjuntos
denominados subrbol izquierdo y subrbol derecho. Cada uno de estos subrboles
es, a su vez, un rbol binario. La Figura 10.4 muestra diversos ejemplos de rboles binarios.

B B C B


D H

(a) (b) (e)


Figura 10.4. Diversos tipos de rboles binarios .

rboles binarios 315

10.2.1. Terminologa
En un rbol binario los hijos se conocen como hijo izquierdo e hijo derecho, lo que
supone automticamente una diferencia. Los dos rboles de la Figura 10.5 no represen-
tan el mismo rbol binario, ya que sus hijos izquierdo y derecho estn en orden inverso.
Un nodo que no tiene hijos se denomina hoja.
Por consiguiente, los nodos H, r, E, F Y J son hojas en el rbol de la Figura 1O.4-b.
Los nodos con descendientes se denominan nodos interiores.
El nodo raz se dice que est en el nivel 1 en el rbol, los nodos B y e estn en el
nivel 2, y los nodos D, E, F Y G estn en el nivel 3. La altura del rbol se define como el
nivel ms alto del rbol. Por consiguiente, la altura del rbol (b) de la Figura 10.4 es 4.
Cualquier nodo sin sucesores se denomina un nodo terminal. Por ejemplo, los no-
dos H, r, E, F, J son todos hojas o nodos terminales, en el rbol 10.4 (b).
En la Figura 10.7, los nodos B, D Y E forman el subrbol izquierdo. De modo similar
C, F y G forlllan el subrbol derecho. Cada uno de estos subrboles es un verdadero
rbol.
Los subrboles izquierdo y derecho de un rbol binario deben ser subconjuntos disjun-
tos de nodos. Esto es, ningn nodo puede estar en ambos subrboles.

1 1

2 3 3 2

Figura 10.5. rboles binarios distintos.

I
D Padre
,
,,
,,
I
,,
,
j,
,

Hijo izquierdo H J Hijo derecho

Figura 10.6. Padre e hijos de un rbol binario.


,

,
.- ...... _ - -------

316 Estructura de datos

Subrbol izquierdo Subrbol derecho


B e

o E F G

Figura 10.7. Subrboles de un rbol binario.

La definicin de rbol conlleva el hecho de que un rbol binario es un tipo de estruc-


tura de datos recursiva. Esto es, cada subrbol se define como un rbol ms simple. La
naturaleza recursiva del rbol binario ayuda a simplificar la operacin con rboles binarios.
Un rbol binario lleno es aquel en el que cada nodo tiene o dos hijos o ninguno si es
una hoja. La Figura 10.8 (a) muestra un rbol binario lleno y, sin embargo, la Fi-
gura 10.8 (b) representa un rbol binario no lleno pero s completo (se define posterior-
mente).

10.2.2. Nivel de un nodo y altura de un rbol


El nivelo profundidad de un nodo se define como una cantidad mayor en uno al nme-
ro de sus ascendientes. As, suponiendo el nivel de nodo n:
Si n es la raz de un rbol T, entonces est en el nivel 1.
Si n no es la raz de T, entonces su nivel es mayor que el nivel de su padre.
Por ejemplo, en la Figura 10.9

A A

B e B e

o E F G o E I

(a) (b)
Figura 10.8. rbol binario: (a) completo; (b) no completo.
, , ,
,

rboles binarios 317

nodo A est en nivel 1

nodo B est en nivel 2


B c
nodo D est en nivel 3

D E F G

Figura 10.9. rbol binario con diferentes niveles.

I
La altura de un rbol es el nmero de nodos en el camino ms largo desde la raz
a una hoja; dicho de otro modo, la altura de un rbol es el nmero de niveles distintos.
As, en un rbol general T, en trminos de los niveles de sus nodos se define como

sigue:

Si T es vaco, entonces la altura es O.


Si T no es vaco, entonces su altura es igual al nivel mximo de sus nodos.

Los rboles de la Figura 10.10 tienen por altura 3, 4 Y 6.

c_

(a) (b) (e)

Figura 10.10. rboles binarios con los mismos nodos pero alturas diferentes.
318 Estructura de datos

Definicin recursiva de altura


Si T est vaco, su altura es O
Si T no es un rbol binario vaco, entonces debido a que T es de la forma

La altura de T se puede definir como:

altura (T) = 1 + max [altura (TI)' altura (TD ) ]


,
10.2.3. Arboles binario, lleno y completo
Un rbol binario lleno de altura h tiene todas sus hojas a nivel h y todos los nodos que
estn a nivel menor que h tiene cada uno dos hijos. La Figura 10.11 representa un rbol
binario lleno de altura 3.
, Se puede dar una definicin recursiva de rbol binario lleno:

Si T est vaco, entonces T es un rbol binario lleno de altura O.


Si no est vaco y tiene altura h > 0, entonces T es un rbol binario lleno si los
subrboles de la raz son ambos rboles binarios llenos de altura h - 1.
;

Un rbol binario completo de altura h es un rbol binario que est relJeno a partir
del nivel h - 1, con el nivel h relleno de izquierda a derecha (Figura 10.12). Ms formal-
mente, un rbol binario de altura h es completo si:

Todos los nodos de nivel h - 2 Y superiores tienen dos hijos cada uno.
Cuando un nodo tiene un descendiente derecho a nivel h, todas las hojas de su
subrbol izquierdo estn a nivel h .


Figura 10.11. Arbol binario lleno de altura 3.
rboles binarios 319

Figura 10. 12. rbol binario completo.

Un rbol binario es completamente (totalmente) equilibrado si los subrboles izquierdo


y derecho de cada nodo tienen la misma altura. .

(d)

(a) (b) (e)

,
Figura 10.13. Arbol binario: (a) equilibrado, (b) completamente equilibrado;
(e) y (d) rboles no equilibrados.
320 Estructura de datos

10.2.4. Recorrido de un rbol binario


El proceso u operacin de acceder o visitar a todos los nodos (datos) de un rbol se
conoce normalmente como recorrido de un rbol. El rbol puede ser recorrido en va-
rios rdenes. Los tres recorridos ms tpicos se clasifican de acuerdo al momento en que
se visita su raz en relacin con la visita a sus subrboles. '

, .

, .- - -
", '"
, ,.',,;', . 1
-_._.- -': '
. .:... _.- ,
:,. ::_---,--- -

.': .. :': ,". , .... .. . >

recorrido preorden recorrido enorden recorrido postorden


l. Visitar el raz l. Ir a subrbol izquierdo l. Ir a subrbol izquierdo l
,
2. Ir a subrbol izquierdo 2. Visitar el raz 2. Ir a subrbol derecho ,
1
",
3. Ir a subrbol derecho 3. Ir a subrbol derecho 3. Visitar el raz

,,

En el rbol de la Figura 10.14 los posibles recorridos pueden ser:
,
1

Recorrido preorden visita los nodos en el orden GDBACEFKHJIML. ,

I Recorrido enorden visita los nodos en el orden ABCDEFGIJHKLM.


Recorrido postorden visita los nodos en el orden ACBFEDIJHLMKG.

10.3. RBOLES DE EXPRESiN


Los rboles binarios se utilizan para representar expresiones en memoria; esencialmente,
en compiladores de lenguaje de programacin. La Figura 10.15 muestra un rbol binario
de expresiones para la expresin aritmtica (a + b) * c.

o K

B E H M

J
L
A e F


Figura 10.14. Arbol binario.

I
Arboles binarios 321

+ e

A B

Figura 10.15. rbol binario de expresiones que representa (A + B) C.

Obsrvese que los parntesis no se almacenan en el rbol pero estn implicados en la


forma del rbol. Si se supone que todos los operadores tienen dos operandos, se puede
representar una expresin por un rbol binario cuya raz contiene un operador y cuyos
subrboles izquierdo y derecho son los operandos izquierdo y derecho, respectivamente,
cada operando puede ser una letra (x , Y, A, B, etc.) o una subexpresin representada como
un subrbol. En la Figura 10.16 se puede ver cmo el operador que est en la raz es *,
su subrbol izquierdo representa la subexpresin (x + y ) y su subrbol derecho repre-
senta la subexpresin (A- B). El nodo raz del subrbol izquierdo contiene el opera-
dor (+) de la subexpresin izquierda y el nodo raz del subrbol derecho contiene el
operador (-) de la subexpresin derecha. Todos los operandos letras se almacenan en
nodos hojas.
Utilizando el razonamiento anterior, se puede escribir la expresin almacenada como
(x + Y) * (A-B)
en donde se han insertado parntesis alrededor de subexpresiones del rbol. En la Fi-
gura 10.17 aparece el rbol de la expresin [x + (Y * Z)] * (A- B).

EJEMPLO 10.1
Deducir las expresiones que representan los siguientes rboles binarios

A e

y B A

z
(a) (e)

(b)
322 Estructura de datos

+ -

x y A B

,
Figura 10.16. Arbol de expresin (x+y) * (A - B) .

Solucin
a) X* (Y / - Z )
b) A + [( B *-(C+D )]
e) [A* ( X+Y) J *C

EJEMPLO 10.2
Dibujar la representacin en rbol binario de cada una de las siguientes expresiones

a) X *Y / [ (A+B) * C ]
b) (X*Y l A) + ( B* C)

Solucin

e B e

A B y

(a) (b)

, ,
10.4. CONSTRUCCION DE UN ARBOL BINARIO
Los rboles binarios se construyen de igual forma que las listas enlazadas, utilizando
diferentes elementos con la misma estructura bsica. Esta estructura bsica es un nodo

_ _ _ o __ ~ ~ . _~ _ _ __
, ... "
Arboles binarios 323

+ -

x A B

y z
,
Figura 10.17. Arbol de expresin [x+ ( y*Z) 1* (A-B).

con un espacio de almacenamiento para datos y enlaces para sus hijos izquierdo y
derecho. Existe una diferencia clara con las listas y es el enlace de los nodos; esto se
debe a que el rbol es bidimensional, tiene una estructura de registro ms compleja
y tiene muchos punteros ni 1 frente a uno solo que aparece al final de una lista en-
lazada.
Con este formato cada nodo tiene tres elementos: datos, un puntero izquierdo y un
puntero derecho. Los punteros son otros nodos que llevan a declaraciones muy similares
a las de una lista enlazada.

type
Pt rAr bo l = ANod o Arbol

No doArb ol = record
Da to s:NombreTipo;
Izda, Dch a: PtrA rb o l; ( p unter os a hi j os )
end; (Nod o Ar b o l )

Aadir una hoja

Dada esta definicin, un rbol se puede construir mediante llamadas sucesivas a new,
cada una de las cuales asigna un nodo nuevo al rbol.
La implementacin de un rbol binario comienza disponiendo al principio de una
variable puntero externo T que apunta a la raz del rbol. Si el rbol est vaco, T es
nil. La Figura 10.18 ilustra esta implementacin. La definicin recursiva de un rbol
binario conduce a que cada rbol binario no vaco conste de un subrbol izquierdo y un
subrbol derecho, cada uno de los cuales es un rbol binario. AS, si T apunta a la raz de
un rbol binario, entonces T " . 1 z do apunta a la raz del subrbol izquierdo y T " . De ho
apunta a la raz del subrbol derecho.
324 Estructura de datos

Nombre

Izdo. Ocho .

Figura 10.18. Implementacin de un rbol binario.

El procedimiento para crear una hoja de un rbol y una funcin que comprueba si un
nodo es una hoja se muestran a continuacin:

procedure NuevaHoj a (var Nue v o lt e mP t r : P t r Arbo l ; Num : Nombre Ti po) ;


begin
ne w (NuevoltemPt r ) ;
Nuev o lte mP t rA .Da t os : = Num;
Nuevolt emPt rA . lzdo := n i l ,'
Nu evo lt emP trA . Dcho := n i l;
end {NuevaHoja}

function Es Hoja (unNodo : Pt rArbol) : boolean ;


begin
if unNod o = n i l then
Es Hoja : = fa l se ;
elBe
EsHo j a : =(unNo do A.lz do - n il ) and (unNo d oA.Dc ho = nil) ;
end; {Es Hoja }

,
10.5. RECORRIDO DE UN ARBOL
Para visualizar o consultar los datos almacenados en un rbol se necesita recorrer el
rbol o visitar los nodos del mismo. Al contrario que las listas enlazadas, los rboles
binarios no tienen realmente un primer valor, un segundo valor, tercer valor, etc. Se pue-
de afirmar que el raz viene el primero, pero quin viene a continuacin? Existen di fe-
,
rboles binarios 325

rentes mtodos de recorrido de rbol, como ya se coment en el apartado 10.2. La mayo-


ra de las aplicaciones binarias son bastante sensibles al orden en el que se visitan los
nodos, de forma que ser preciso elegir cuidadosamente el tipo de recorrido.
El recorrido de un rbol supone visitar cada nodo slo una vez. Las tres etapas
bsicas en el recorrido de un rbol binario recursivamente son:

l. Visitar el nodo (N)


2. Recorrer el subrbol izquierdo (I)
3. Recorrer el subrbol derecho (D)

Segn sea la estrategia a seguir, los recorridos se conocen como enorden (inorder),
preorden (preorder) y postorden (postorder)



preorden (nodo-izdo-dcho) (NID)
enorden (izdo-nodo-dcho) (IND)
postorden (izdo-dcho-nodo) (IDN)

10.5.1. Recorrido enorden


Si el rbol no est vaco, el mtodo implica los siguientes pasos:
I
l. Recorrer el subrbol izquierdo (1). !,
2. Visitar el nodo raz (N). 1


3. Recorrer el subrbol derecho (D).

El algoritmo correspondiente es

En o rden(A)

Si el ar b o l n o e st a v a c ~ o entonces
inicio
Recorrer el su ba r bol izqu ier d o
visitar el n odo raiz
Re corre r el subarbo l d er echo
fin

En el rbol de la Figura 10.19, los nodos se han numerado en el orden en que son
visitados durante el recorrido enorden. El primer subrbol recorrido es el subrbol iz-
quierdo del nodo raz (rbol cuyo nodo contiene la letra B. Este subrbol consta de los
nodos B, D Y E Y es a su vez otro rbol con el nodo B como raz, por lo que siguiendo el
orden IND , se visita primero D, a continuacin B (nodo o raz) y por ltimo E (derecha).
Despus de la visita a este subrbol izquierdo se visita .el nodo raz A y por ltimo se
visita el subrbol derecho que consta de los nodos C, F y G. A continuacin, siguiendo el
orden I ND para el subrbol derecho, se visita primero F, despus C (nodo o raz) y por
ltimo G. Por consiguiente, el orden del recorrido de la Figura 10.19 es D-B-E-A-F-C-G.
326 Estructura de datos

A
Visita de los nodos: D, S, E, A, F, e, G
4

S e
2 6

D E F G

1 3 5 7

Figura 10.19. Recorrido enorden de un rbol binario.

10.5.2. Recorrido preorden


El recorrido preorden (NID) conlleva los siguientes pasos:
l. Visitar el raz (N).
2. Recorrer el subrbol izquierdo (1).
3. Recorrer el subrbol derecho (D).

El algoritmo recursivo correspondiente es:


si T n o es va c i o entonces
inicio
ver los dato s e n el r a iz de T
preorden (sub arbo l iz q uie rdo del rai z d e T)
preorden (sub ar b o l de re c ho del raiz d e T)
fin

Si utilizamos el recorrido preorden del rbol de la Figura 10.20 se visita primero el


raz (nodo A). A continuacin se visita el subrbol A, que consta de los nodos B, O Y E.
Dado que el subrbol es a su vez un rbol, se visitan los nodos utilizando el orden NIO.
Por consiguiente, se visita primero el nodo B, despus O (izquierdo) y por ltimo E
(derecho).
A continuacin se visita subrbol derecho de A, que es un rbol que contiene los
nodos C, F y G. De nuevo siguiendo el orden NIO, se visita primero el nodo C, a conti-
nuacin F (izquierdo) y por ltimo G (derecho). En consecuencia, el orden del recorrido
preorden para el rbol de la Figura 10.20 es A-B-O-E-C-F-G.

10.5.3. Recorrido postorden


El recorrido postorden (IDN) realiza los pasos siguientes:
l. Recorrer el subrbol izquierdo (1).

2. Recorrer el subrbol derecho (D).


3. Visitar el raz (N).
rboles binarios 327

A
Visita los nodos : A-B-D-E-C-F-G
1

B C

2 5

o E F G

3 4 6 7

Figura 10.20. Recorrido preorden de un rbol binario.

El algoritmo recursivo es

si A n o es ta y ac io entonces

~n~c~o

Postorde n ( s ubarbol iz qu i e rdo del ra iz de A)


Posto rde n (suba r bol derecho d el raiz de A)
Vi sua l i zar l os dato s de l r a i z de A
fin

Si se utiliza el recorrido postorden del rbol de la Figura 10.21, se visita primero el


subrbol izquierdo A. Este subrbol consta de los nodos B, D Y E Y siguiendo el orden
IDN, se visitar primero D (izquierdo), luego E (derecho) y por ltimo B (nodo). A con-
tinuacin se visita el subrbol derecho A que consta de los nodos C, F y G. Siguiendo el
orden 1 DN para este rbol , se visita primero F (izquierdo), despus G (derecho) y por
ltimo C (nodo). Finalmente se visita el raz A (nodo). AS , el orden del recorrido postor-
den del rbol de la Figura 10.21 es D-E-B - F -G-C- A .

A
Visita los nodos D-E-B-F-G-C-A
7

B C

3 6

o E F G

1 2 4 5

Figura 10.21. Recorrido postorden de un rbol binario.


.."..... , ... _-------

328 Estructura de datos

EJEMPLO 10.3
Deducir los tres recorridos del rbol binario siguiente:

E z

A G p

Solucin
Preorden :MEAGZPQ (NID)
Enorden :AEGMPQZ ( IND)
Postorden :AGEQPZM ( IDN)

I 10.5.4. Implementacin de los algoritmos de recorrido


Los mtodos utnizados para recorrer un rbol binario son recursivos y por lo tanto se
emplearn procedimientos recursivos para implementar los recorridos. Un rbol se re-
presenta utilizando las siguientes sentencias Pascal:
I


const LongMax = 30 (longitud mxima del nombre)

type NombreTipo = string [LongMaxl ;

ptrTipo = ~nodoT ipo;

nod o Tipo - record


Nombre:nombreTipo;
Hijolzdo:ptrTipo; (puntero a Hijo izquierdo )
HijoDcho:ptrTipo (puntero a Hij o derech o )
end;
Tip oArbo lBin = ptrTipo;

var A : TipoArbolBin; ( puntero a raz del rbol)


rboles binarios 329

Por ejemplo el procedimiento EnOrden puede ser:


procedure EnOrden (A : TipoArbolBin);
begin
if A < > nil then {rbol no esta vaco}
begin
EnOrden (AA.Hij o lzdo); {operacin I}
WriteLn (A A.No mbre); {operacin N}
EnOrden (A A. HijoDcho); {operacin D}
end;
end;

La implementacin de los recorridos preorden y postorden se realiza siguiendo el


esquema algortmico de los apartados 10.5.2 y 10.5.3, respectivamente.


10.6. APLICACiN DE RBOLES BINARIOS:
EVALUACiN DE EXPRESIONES

Una expresin aritmtica est formada por operandos y operadores aritmticos. As, la
.,
expreSlOn
R =(A+B)*D+A*B / D
R est escrita de la forma habitual, el operador en medio de los operando, se conoce

como notacin infija. Recordemos que ya hemos realizado la aplicacin de evaluar una
expresin utilizando nicamente el T AD pila. Ahora va a ser utilizada tanto las pilas
como el T AD rbol binario para la evaluacin. La pila ser utilizada para pasar la expre-
sin de infija a postfija. La expresin en postfija ser almacenada en el rbol para que la
evaluacin se realice utilizando el rbol binario. En primer lugar, recordamos la priori-
dad de operadores, de mayor a menor:
,.
ParenteslS ()


Potencla

A

Multipl / divisin
* I /
Suma / Resta
+, -

A igualdad de precedencia son evaluados de izquierda a derecha.

10.6.1. Notacin postfija: notacin polaca


La forma habitual de escribir operaciones aritmticas es situando el operador entre sus
dos operandos, la llamada notacin infija. Esta forma de notacin obliga en muchas oca-
siones a utilizar parntesis para indicar el orden de evaluacin.
A*B / (A+C) A*B / A+ C

Representan distintas expresiones al no poner parntesis. Igual ocurre con las expre-

SlOnes:


330 Estructura de datos

La notacin en la que el operador se coloca delante de los dos operandos, notacin


prefija, se conoce como notacin polaca (en honor del matemtico polaco que la estudi).

A*B / (A+C) (infija) ~ A*B / +AC ~ *AB / +AC ~ / *AB+AC(polaca)


A*B / A+C (infija) ~ *AB/A+C ~ / *ABA+C ~ + / *ABAC (polaca)
(A-B) ~C +D (infija ) ~ -AB~C+D ~ ~-ABC+D ~ +~-ABCD (polaca)

Podemos observar que no es necesario la utilizacin de parntesis al escribir la


expresin en notacin polaca. Es la propiedad fundamental de la notacin polaca, el
orden en que se van a realizar las operaciones est determinado por las posiciones de los
operadores y los operandos en la expresin.
Hay ms formas de escribir las operaciones. As, la notacin postfija o polaca inver-
sa coloca el operador a continuacin de sus dos operandos.

A*B /( A+C) (infija) ~ A*B / AC+ ~ AB* / AC+ ~ AB*AC+ / (polaca inversa)
A*B / A+C (infija) ~ AB* /A+C ~ AB*A /+C AB*A/ C+ (polaca inversa)
(A-B) ~ C+D (infija) ~ AB - ~ C+D AB-C ~+D ~ AB-C~D+ (polaca inversa)

10.6.2. rbol de expresin


.
.

Una vez que se tiene la expresin en postfija la formacin del rbol binario es fcil: se
crean dos nodos del rbol con respectivos operandos que se enlazan como rama izquier-
da y rama derecha del nodo operador. As, la expresin A * B - C * D + H se transforma en
postfija: AB*CD*-H+ y el rbol de la expresin:

.

+

I -
,
.
H
..
i
.
.
,
* *

A B e D

Pasos a seguir
A la hora de evaluar una expresin aritmtica en notacin infija se siguen estos pasos:
l. Transformar la expresin de infija a postfija.
2. Formar a partir de la expresin en postfija el rbol de expresin.
3. Evaluar la expresin utilizando el rbol.

:.
!
..
!

.
rboles binarios 331

En el algoritmo para resolver el primer paso se utiliza una pila de caracteres. Para el
segundo paso se utiliza otra pila y el rbol de caracteres. Y en el tercer paso un vector
con los valores numricos de los operandos que es utilizado para evaluar la expresin en
el rbol.

10.6.3. Transformacin de expresin infija a postfija


.

Partimos de una expresin en notacin infija que tiene operandos, operadores y puede
tener parntesis. Los operandos vienen representados por letras, los operadores van a ser:

A (potenciacin), *, /, +, _ .

La transformacin se realiza utilizando una pila en la que se almacenan los operado-


res y los parntesis izquierdos. Esta transformacin puede verse en el captulo de Pilas,
apartado 7.4, Evaluacin de expresiones mediante Pilas.

10.6.4. Creacin de un rbol a partir de la expresin en postfija


El rbol se forma de tal manera que en la raz se encuentra el operador, en el subrbol
izquierdo y derecho los operandos. En una pila se guardan las direcciones de los nodos
que contienen a los operandos. Cuando se va a formar el nodo de un operador, se saca
de la pila los dos ltimos nodos metidos para formar el nodo operador enlazando la
rama izquierda y la derecha con las direcciones de los nodos que se han sacado de la
pila.
La unidad que encapsula el TAD pila necesario para guardar las direcciones de los
nodos del rbol, tambin define los tipos necesarios para manejar el rbol. Esto es as
porque el campo Info de los elementos de la pila es PtrA (puntero a nodos del rbol).
A continuacin se escribe la interfaz de la unidad pila. La seccin de definicin est ya
escrita anteriormente.

unit Pilaptr;
interface
type
PtrA = ANodoAb;
NodoAb = record
e : char;
Izqdo,
Drcho : PtrA
end;
Plaptr = ANodopt;
Nodopt = record
Info: PtrA;
,,
Sgte: Plaptr
end;
,;,
~.

'O"
332 Estructura de datos

function pvacia(P; Plaptr ); boolean;


procedure Pcrear(var P; Plaptr );
procedure Pmeter(D; PtrA; var P; Plaptr);
procedure Psacar(var D; PtrA; var P; Plaptr);
function Pcima (P:Plapt r); PtrA; {devuelve el elemento cima de la pila}
procedure Pborrar(var P: Plaptr);
implementation

end.

El siguiente procedimiento genera el rbol de expresin a partir del vector de regis-


tros que contiene la expresin en postfija.

procedure ArbolExpresion(var Ar;Tag; J:integer; var R;PtrA);


var {el tipo Tag est definido en la unidad ExpPost}
1: integer;
P: Pilaptr;
Al, A2, A3: PtrA;
procedure Crearnod o( 1z: PtrA; 1nf:char; Dr:PtrA; var A:PtrA);
begin
, new(A) ;
, AA.C ;= 1nf;
i i
AA.1zqdo ;= 1z;
AA.Drcho := Dr
endl
begin
Pcrear(P);
for 1:= 1 to J do
if not Ar[I] .Oprdor then
begin
Crearnodo(nil, Ar[1].C, nil, A3);

Pmeter(A3, P)
end
elBe begin
Psacar(A2, P);
I Psacar(Al, P);
Crearnodo(Al, Ar[1] .C, A2, A3);
Pmeter(A3, P)
end;
Psacar (A3, P); {Devuelv e el rbol con la expresin}

R:= A3
end;

10.6.5. Evaluacin de la expresin en postfija


La primera accin que se va a realizar es dar valores numricos a los operandos. Una
vez que tenemos los valores de los operandos, la expresin es evaluada. El algoritmo de
evaluacin recorre el rbol con la expresin en postorden. De esta forma se evala pri-
mer operando (rama izquierda), segundo operando (rama derecha) y segn el operador
(raz) se obtiene el resultado.
Es en la unidad ExpPost donde est definido el tipo de los Oprdos para as poder
,

rboles binarios 335

queda, debido a que se pueden buscar en ellos un trmino utilizando un algoritmo de


bsqueda binaria similar al empleado en arrays.
Un rbol binario de bsqueda es aquel que dado un nodo, todos los datos del sub-
rbol izquierdo son menores que los datos de ese nodo, mientras que todos los datos del
subrbol derecho son mayores que los datos del nodo. Por consiguiente, este rbol no es
un rbol binario de bsqueda,

9 5

ya que 9 no es menor que 4. Sin embargo, el siguiente rbol s es binario de bsqueda.

4 9

EJEMPLO 10.4

Arbol binario de bsqueda

55 4 menor que 30
30 menor que 55
41 mayor que 30
75 mayor que 55
30 75 85 mayor que 75 r
I,

,
4 41 85 ,
,

,
,,
,

i'
336 Estructura de datos

10.7.1. Creacin de un rbol binario


Supongamos que se desea almacenar los nmeros

8 3 1 20 10 5 4

en un rbol binario de bsqueda. Siguiendo la regla, dado un nodo en el rbol todos los
datos a su izquierda deben ser menores que todos los datos del nodo actual, mientras que
todos los datos a la derecha deben ser mayores que dichos datos. Inicialmente el rbol
est vaco y se desea insertar el 8. La nica eleccin es almacenar el 8 en el raz:

A continuacin viene el 3. Ya que 3 es menor que 8, el 3 debe ir en el subrbol


izquierdo

A continuacin se ha de insertar 1, que es menor que 8 y que 3, por consiguiente ir


a la izquierda y debajo de 3.

El siguiente nmero es 20, mayor que 8, lo que implica debe ir a la derecha de 8 .

rboles binarios 337

3 20

Cada nuevo elemento se inserta como una hoja del rbol. Los restantes elementos se

! pueden situar fcilmente.


,

3 20
8

1 10

3 20
8

1 5 10
3 20

1 5 10

4
338 Estructura de datos

Una propiedad de los rboles binarios de bsqueda es que no son nicos para los

datos dados .

EJEMPLO 10.5

Construir un rbol binario para almacenar los datos 12, 8, 7, 16 Y 11.

Solucin

12

8 16

7 11

PROBLEMA 10.1 2

Este programa genera un rbol binario de nmeros enteros con un nmero aleatorio de
nodos y en un rango de valores tambin aleatorio. Se utiliza un procedimiento recursivo
para contar el nmero de nodos del rbol, otro procedimiento para mostrar los nodos
ordenados ascendentemente y un procedimiento de altas para insertar cada nuevo n-
mero generado en su correspondiente nodo.

! Diagrama de estructura

i PROGRAMA
,
! NMERODENODOS

PROCEDIMIENTO FUNCiN PROCEDIMIENTO


ALTAS NODOS INORDEN

2 Este problema ha sido extrado de la obra Pascal y Turbo Pascal: Un enfoque prctico, de Luis Joya-
nes, Ignacio Zahonero y ngel Hermoso, McGraw-Hill, 1995, y con permiso de los autores.
Arboles binarios 339

CODIFICACiN
program NumeroDeNodos;
{Este programa genera un rbol binario de nmeros enteros, y
posteriormente muestra y cuenta el nmero de nodos}
uses
Crt;
const
MaxNumNodos = 30;
MaximoValor - 100;
type ,
RangoNodos = o, ,MaxNumNodos - 1 ;
TipoClave = l .. Maximovalor;
Punter o = ANodoArbol;
NodoArbol - record
Clave : TipoClave;
Izdo ,
Ocho : Puntero
end;

var
Raiz : Puntero;
NodosGenerados,
NodosContados,
Indi ce : RangoNodos;
Val o r : TipoClave;
funtion Nodos (P : Punt ero) : RangoNodos;
{Funcin recursiva para contar el nmero de nodos del rbol. El nmero de
nodo s es la suma del nmero de nodos de cada uno de sus subrboles
izquierdo y derecho ms el nodo raz}
begin
if P = nil then
Nod os := O
else
Nodos : = 1 + Nodos (PA.lzdo) + Nodos (PA .Dcho)
end;
procedure InOrden (P : Puntero);
begin
if P < > nil then
begin
InOrden (PA .Izd o) ;
Write (p A.C lave : 5);
Inorden (PA.Dcho)
end
end;

procedure Altas (var Root : Puntero; Valor : TipoClave);


(Inserta el nuevo valor generado, como nodo del rbol)
var
Padre,
Actual,
NodoAlt a : Puntero;
begin
new (NodoAlta);
NodoAltaA.Clave := Va lor;
NodoAltaA.lzdo := nil; (el nuevo nodo es el nodo hoja)
340 Estructura de datos

NodoAltaA.Dcho := nil;
Padre := nil;
Actual := Root;
while Actual <> nil do
begin
Padre := Actual;
if ActualA.Clave >= Valor then
Actual := ActualA.Izdo
elee
Actual := ActualA.Dcho
end;
if Padre = nil then {se situar como raiz}
Root := NodoAlta
elee
if padreA.Clave >= Valor then
PadreA.Izdo := NodoAlta {se sita a la izquierda}
elee
padreA.Dcho := NodoAlta {se sita a la derecha}
end;

begin
ClrScr;
Randomize;
NodosGenerados := Random (MaxNumNodos);
Raiz : = nil;
Writeln (' conjunto de nodos generados al azar': 52); ,,
for Indice := 1 to NodosGenerados do
begin
Valor := Random (maximoValor) + 1;
Write (valor:5);
Altas (Raiz o valor) {insercin del nodo en el rbol}
end;
WriteLn;
WriteLn;
NodosContados := Nodos (Raiz);
WriteLn( 'recorrido InOrden. Nodos encontrados':65);
InOrden (Raiz); i
WriteLn; I,
WriteLn; ,
]
WriteLn ('Numero de nodos generados: 'o NodosGenerados); 1
,,
;
WriteLn ('Numero de nodos contados: 'o NodosContados) ,
i,
end. ,

I
1
,
!

10.8. OPERACIONES EN RBOLES BINARIOS DE BSQUEDA 1


I
i

'1
,
De lo expuesto hasta ahora se deduce que los rboles binarios tienen naturaleza recursi- I
I

va y en consecuencia las operaciones sobre los rboles son recursivas, si bien siempre i

, ,,

tenemos la opcin de realizarlas de forma iterativa. Estas operaciones son: ,


i

, ,I

Bsqueda de un nodo. ']

Insercin de un nodo. !,
,,

Recorrido de un rbol.
Supresin de un nodo.
,
,,
,

I
i,
,,

I
,,
i
1
j
,

Arboles binarios 341

10.8.1. Bsqueda

La bsqueda de un nodo comienza en el nodo raz y sigue estos pasos:

l. La clave buscada se compara con la clave del nodo raz.


2. Si las claves son iguales, la bsqueda se detiene, o si el subrbol est vaco.
3. Si la clave buscada es mayor que la clave raz, la bsqueda se reanuda en el
subrbol derecho. Si la clave buscada es menor que la clave raz, la bsqueda se
reanuda con el subrbol izquierdo.

La funcin de bsqueda de una clave devuelve la direccin del nodo que contiene a
la clave, o bien ni 1 en caso de encontrarse en el rbol.
funct10n busqueda (R: Ptr; x: TipoInfo): Ptr;
var Esta: boolean;
beg1n
Esta:=false;
wh1le not Esta and (R < >nil) do
1f RA.elemento=X then
Esta:=true
el Be 1f RA.elemento >X then
R:= R A. izquierdo
elBe
R:= RA.derecho;
busqueda := R
end;

Se deja al lector la implementacin recursiva como ejercicio prctico.


10.8.2. Insercin I

La operacin de insercin de un nodo es una extensin de la operacin de bsqueda. Los ,



pasos a segUIr son: ,I

l. Asignar memoria para una nueva estructura nodo.


2. Buscar en el rbol para encontrar la posicin de insercin del nuevo nodo, que
se colocar como nodo hoja.
3. Enlazar el nuevo nodo al rbol.

La implementacin de la operacin insertar una nueva clave en un rbol de bsqueda


, se realiza, en primer lugar, de founa recursiva. Siempre se inserta como nodo hoja; la

posicin de insercin se determina siguiendo el camino de bsqueda: izquierda para


claves menores, derecha para claves mayores. Hay veces que no se permiten claves repe-
tidas; en nuestro caso se permitir y se inserta por la derecha.
procedure Insertar (var R: Ptr; X: TipoInfo);
beg1n
1f R - nil then
R: - CrearNodo (X)
342 Estructura de datos

elee if X< RA . eleme nto then


I nsert ar (R A. izqui er do . X)
elee if X>=RA.elemento then
Insertar(RA .d erec h o . X}
end;

El mecanismo de enlace del nodo creado con el nodo antecedente se explica tenien-
do presente el significado de paso de parmetros por referencia (var).
La funcin Cr earNo d o reserva memoria y devuelve su direccin.

function CrearNodo (x : TipoInfo) : Pt r ;


var T: Ptr;
begin
new (T) ;
.
T A.e l eme n to . - x
T A.izqu i e r do := nil; T A. derec h o : = ni l ;
CrearNodo : =T
end;

El procedimiento I n ser tar tambin puede plantearse de manera iterativa, como



, se muestra a contmuaClOn:

procedure I nserta r (var R : Ptr; X : TipoInf o ) ;


var Q; P : Ptr;
begin
P := R; Q:= R;
while P<> nil do
begin
Q: = P ; {Q tiene l a direccin d el nodo ant e cedente}
if X< pA. e l emento then P:=PA .izquie r do
elee P:= p A: derec ho;
end;
!
P := CrearNodo(X} ;

if Q = n i l then R : = P {Se crea e l n odo r az }


,
elee if X<QA : e l emento then QA . izquierdo : = P

elee if X< =QA . eleme nt o then QA .der echo : = P


end;

10.8.3. Eliminacin
La operacin de eliminacin de un nodo es tambin una extensin de la operacin de
bsqueda, si bien es ms compleja que la insercin debido a que el nodo a suprimir
puede ser cualquiera y la operacin de supresin debe mantener la estructura de rbol
binario de bsqueda despus de la eliminacin de datos. Los pasos a seguir son:
l. Buscar en el rbol para encontrar la posicin de nodo a eliminar.
2. Reajustar los punteros de sus antecesores si el nodo a suprimir tiene menos de
dos hijos, o subir a la posicin que ste ocupa el nodo descendiente con la clave
inmediatamente superior o inferior con objeto de mantener la estructura de rbol
binario.

rboles binarios 343

La eliminacin de una clave y su correspondiente nodo, presenta dos casos clara-


mente diferenciados. En primer lugar, si es un nodo hoja o tiene un nico descendiente,
resulta una tarea fcil, ya que lo nico que hay que hacer es asignar al enlace desde
el nodo padre (segn el camino de bsqueda) el descendiente del nodo a eliminar (o
bien, ni 1). En segundo lugar, que el nodo tenga los dos descendientes. Para mantener la
estructura de rbol de bsqueda tenemos dos alternativas, reemplazar la clave a eliminar
por la mayor de las claves menores, o bien reemplazar por la menor de las claves mayo-
res. Se elige la primera alternativa, lo que supone bajan> por la derecha en la rama
izquierda del nodo a eliminar hasta llegar al nodo hoja, que ser el que est ms a la
derecha dentro del subrbol izquierdo de la clave a borrar.

EJEMPLO 10.6 En el rbol de la figura se quiere eliminar la clave 34. El nodo ms a la


derecha de su rama izquierda es 28. Se reemplaza y por ltimo se elimina
el nodo hoja 28.

100
25 6

En la codificacin, el procedimiento anidado Reemplazar realiza la tarea explica-


da anteriormente. La codificacin recursiva es la que se ajusta al planteamiento recursi-
vo de la operacin, y as se implementa:
procedure Eliminar (var R : Pt r; X: Tip o Info) ;
var Q: Ptr ;
procedure Reemplazar (var N: Ptr);
begin
if N~ . derecho <> nil then
Reempl aza r (NA.de rec ho) ( " ba ja" por rama de rech a)
el se begin
Q~.ele m e n to : = N ~ .el e men to ; (reemp l aza i n f o rmacin)
Q : = N;
N := N~.izquierdo
end
end;
344 Estructura de datos

begin
if R=n i l then wr i te ln ( ' No es t l a c l ave' )
elBe if X<R ~ . e le mento then
El i mi na r (R ~. izq uier do , X)
elBe if X>R ~ . e l emento then
El i mi n ar (R~.derec h o, X)
el Be begin
Q : = R;
if Q ~ . de r ec h o = ni l then {No t i ene d os des c end i e n tes}
R : = Q~.i zq u i erd o
el Be if Q~.i z quie rd o = n i l then
R : = Q ~ .de r ec h o
el Be
Ree mpl az a r (Q ~ .i zqu i e rd o) ;
d i s pose(Q)
end
end;

10.8.4. Recorrido de un rbol


Existen dos tipos de recorrido de los nodos de un rbol: el recorrido en anchura y el
recorrido en profundidad. En el recorrido en anchura se visitan los nodos por niveles.
Para ello se utiliza una estructura auxiliar tipo cola en la que despus de mostrar el
contenido de un nodo, empezando por el nodo raz, se almacenan los punteros corres-
pondientes a sus hijos izquierdo y derecho. De esta forma si recorremos los nodos de un
nivel, mientras mostramos su contenido, almacenamos en la cola los punteros a todos los
nodos del nivel siguiente.
El recorrido en profundidad se realiza por uno de los tres mtodos recursivos: preorden,
enorden y postorden. El primer mtodo consiste en visitar el nodo raz, su rbol izquier-
do y su rbol derecho, por este orden. El recorrido enorden visita el rbol izquierdo, a
continuacin el nodo raz y finalmente el rbol derecho. El recorrido postorden consiste
en visitar primero el rbol izquierdo, a continuacin el derecho y finalmente el raz.

preorden Raz Izdo Dcho


en orden Izdo Raz Dcho
postorden Izdo Dcho Raz

procedure preorde n (p : ptr) ;


begin
if p <> nil then
begin
write (p~ . elemen to : 6) ;
,
I pr eor den (p ~. izqu ie rd o ) ;
preo r den (p~ . derecho)
I
end
end;

procedure e n_or de n (p : ptr);


begin
if p <> nil then
rboles binarios 345

begin
en_orden (p~.izquierdo) ;
Wri te (p ~ . e l emen t o : 6) ;
e n_or den (p~ . de r echo)
end
end;

procedure postorden (p : ptr);


begin
if p <> ni1 then
begin
po sto rde n (p ~ .izq ui erdo);
po s torde n (p ~ . de r ec ho) ;
wri te (p~ . el e me n to : 6);
end;
end;

10.8.5. Determinacin de la altura de un rbol


La altura de un rbol depender del criterio que se siga para definir dicho concepto. As, si
en el caso de un rbol que tiene nodo raz, se considera que su altura es 1, la altura del rbol
de la Figura lO.22a es 2, y la altura del rbol de la Figura lO.22b es 4. Por ltimo, si la
altura de un rbol con un nodo es 1, la altura de un rbol vaco (el puntero es ni 1) es O.

7 2 15

2 8
1 2

(a)

(b)
6


Figura 10.22. Arboles binarios de diferente altura.

Nota

La altura de un rbol es 1 ms que la mayor de las alturas de sus subrboles iz-


quierdo y derecho.
346 Estructura~de datos

La funcin recursiva Al t ur a encuentra la altura de un rbol


type Nodo Punt e r o = Apa dr e ;
Padr e = record
i nfo : i n t e ger ;
I zdo , Dc ho : Nodo Puntero
end;

function Alt u r a (T : Nodo Punte ro) : Int ege r;


i {Det e rmina l a a ltur a d e un rbo l}
function Ma x (A, B : in te ger ) : In t eger ;
begin
if A > B then
Ma x : = A
elee
Ma x : = B
end; {Max}

begin {Altura }

if T = nil then
Al t ura : = O
elee
Altura:=l+Max(Altura(T A.lzdo) , Al t ura(T A.Dc h o))
end; {A l t ura }

RESUMEN
En este captulo se introdujo y desarroll la estructura de datos dinmica rbol. Esta estructura,
muy potente, se puede utilizar en una gran variedad de aplicaciones de programacin.

x
x padre o raz ,

y hijo izquierdo de x
z hijo derecho de x
,

y z

La estructura rbol ms utilizada normalmente es el rbol binario. Un rbol binario es un ,


rbol en el que cada nodo tiene como mximo dos hijos, llamados subrbol izquierdo y subrbol
derecho. e

I En un rbol binario, cada elemento tiene cero, uno o dos hijos. El nodo raz no tiene un padre,
~
I
pero s cada elemento restante tiene un padre. X es un antecesor o ascendente del elemento Y.
La altura de un rbol binario es el nmero de ramas entre el raz y la hoja ms lejana. Si el
,
,,
,
rbol A es vaco, la altura es O. La altura del rbol siguiente es 6. El nivelo profundidad de un
,, elemento es un concepto similar al de altura. En el rbol siguiente el nivel de 30 es 4 y el nivel ,

,
, de 36 es 6. Un nivel de un elemento se conoce tambin como profundidad.
,
, Un rbol binario no vaco est equilibrado totalmente si sus subrboles izquierdo y derecho

tienen la misma altura y ambos son o bien vacos o totalmente equilibrados.

- -- - - - J
rboles binarios 347

60
-
37
75

25

62
15 30

69
28 32

36

Los rboles binarios presentan dos tipos caractersticos: rboles binarios de bsqueda y r-
boles binarios de expresiones. Los rboles binarios de bsqueda se utilizan fundamentalmente
para mantener una coleccin ordenada de datos y los rboles binarios de expresiones para almace-

nar expresIOnes.

EJERCICIOS
10.1. Considrese el rbol siguiente:
a) Cul es su altura?
b) Est el rbol equilibrado? Por qu?
e) Listar todos los nodos hoja.
d) Cul es el predecesor inmediato (padre) del nodo U?
e) Listar los hijos del nodo R.
j) Listar los sucesores del nodo R.

,1

s
T v

w
x
348 Estructura de datos

10.2. Explicar por qu cada una de las siguientes estructuras no es un rbol binario:

A A

B e B B e

D E F E D
D
.

10.3. Para cada una de las siguientes listas de letras:

1. M,Y,T,E,R
2. R,E,M,Y,T
3. T,Y,M,E,R
4. C,O,R,N,F,L,A,K,E,S

a) Dibujar el rbol binario de bsqueda que se construye cuando las letras se insertan en
el orden dado.
b) Realizar recorridos enorden, preorden y postorden del rbol y mostrar la secuencia de
letras que resultan en cada caso.

10.4. Para los rboles del ejercicio 10.1, recorrer cada rbol utilizando los rdenes siguientes:
NDI, DNI, DIN.
10.5. Dibujar los rboles binarios que representan las siguientes expresiones:
a) (A+B) I (C-O)
b) A+B+C / 0
e) A- (B- (C-D) I (E+F))
d) (A+B) * ((C+D) / (E+F))
e) (A-B) / ((C*D) - (E / F))

10.6. El recorrido preorden de un cierto rbol binario produce


ADFGHKLPQRWZ

y en recorrido enorden produce


GFHKDLAWRQPZ

Dibujar el rbol binario.

10.7. Escribir una funcin recursiva que cuente las hojas de un rbol binario.
10.8. Escribir un programa que procese un rbol binario cuyos nodos contengan caracteres y a
partir del siguiente men de opciones:
'- - ----------------.----------------------------------------_ ...

rboles binarios 349

1 (seguido de un carcter) : Insertar un carcter


B (seguido de un carcter) : Buscar un carcter
RE
Recorrido en orden
RP
Recorrido en preorden
RT
Recorrido postorden
SA
Salir
10.9. Escribir una funcin que tome un rbol como entrada y devuelva el nmero de hijos del
rbol.
10.10. Escribir una funcin booleana a la que se le pase un puntero a un rbol binario y devuel-
va verdadero (true) si el rbol es completo y falso (fa/se) en caso contrario.
10.11. Disear una funcin recursiva que devuelva un puntero a un elemento en un rbol bina-
rio de bsqueda.
10.12. Disear una funcin iterativa que encuentre un elemento en un rbol binario de bs-
queda.

PROBLEMAS
10.1. Crear un archivo de datos en el que cada lnea contenga la siguiente informacin:
Columnas 1-20 Nombre
21-31 Nmero de la Seguridad Social
32-78 Direccin
Escribir un programa que lea cada registro de datos de un rbol, de modo que cuando el
rbol se recorra utilizando recorrido en orden, los nmeros de la seguridad social se orde-
nen en orden ascendente. Imprimir una cabecera DATOS DE EMPLEADOS ORDENA-

DOS POR NUMERO SEGURIDAD SOCIAL. A continuacin se han de imprimir los tres
datos utilizando el siguiente formato de salida:
Columnas 1-11 Nmero de la Seguridad Social
25-44 Nombre
58-104 Direccin
10.2. Escribir un programa que lea un texto de longitud indeterminada y que produzca como
resultado la lista de todas las palabras diferentes contenidas en el texto, as como su fre-
cuencia de aparicin.
10.3. Se dispone de un rbol binario de elementos de tipo integer. Escribir funciones que cal-
culen:
a) La suma de sus elementos.
b) La suma de sus elementos que son mltiplos de 3 .

10.4. Escribir una funcin booleana IDENTICOS que pellnita decir si dos rboles binarios son
iguales.
10.5. Escribir un programa que tenga como entrada de datos el archivo generado en el proble-
ma 10.1; de forma interactiva permita:

l. Crear un rbol binario de bsqueda T tomando como clave el nmero de la Seguridad



Social.

350 Estructura de datos

2. Aadir nuevos registros al rbol T.


3. Eliminar un registro dada la clave,
4. FIN (lo que supone almacenar el rbol en el archivo original.
10.6. Disear un programa interactivo que permita dar altas, bajas, listar, etc., en un rbol
binario de bsqueda.
10.7. Construir un procedimiento recursivo para encontrar una determinada clave en un rbol
binario de bsqueda.
10.8. Calcular el nmero de hojas en un rbol binario.
10.9. Disear procedimientos no recursivos que listen los nodos de un rbol en inorden, preor-
den y postorden.
10.10. Dados dos rboles binarios de bsqueda indicar mediante un programa si los rboles
tienen o no elementos comunes. ,
10.11. Dado un rbol binario de bsqueda construir su rbol espejo. (Arbol espejo es el que se
construye a partir de uno dado, convirtiendo el subrbol izquierdo en subrbol derecho y
viceversa.)
10.12. Un rbol binario de bsqueda puede implementarse con un array. La representacin no
, enlazada correspondiente consiste en que para cualquier nodo del rbol almacenado en
la posicin 1 del array, su hijo 'izquierdo se encuentra en la posicin 2*1 y su hijo derecho
en la posicin 21 + 1. Disear a partir de esta representacin los correspondientes proce-
dimientos y funciones para gestionar interactivamente un rbol de nmeros enteros. (Co-
mente el inconveniente de esta representacin de cara al mximo y mnimo nmero de
nodos que pueden almacenarse.)
10.13. Una matriz de N elementos almacena cadenas de caracteres. Utilizando un rbol bina-
rio de bsqueda como estructura auxiliar ordene ascendentemente la cadena de carac-
teres.
10.14. Dado un rbol binario de bsqueda disee un procedimiento que liste los nodos del rbol
ordenados descendentemente.
10.15. En tres rboles binarios de bsqueda (ORO, PLATA, COBRE) estn representados los
medallistas de cada una de las pruebas de una reunin atltica. Cada nodo tiene la infor-
macin: nombre de la prueba, nombre del participante y nacionalidad. El rbol ORO
almacena los atletas ganadores de dicha medalla, y as respectivamente con los rboles
PLATA y COBRE. El criterio de ordenacin de los rboles ha sido el nombre del atleta.
Escribir los procedimientos/funciones necesarias para resolver este supuesto:
Dado el nombre de un atleta y su nacionalidad, del cual no se sabe si tiene medalla,
encontrar un equipo de atletas de su mismo pas, incluyendo al mismo que tenga una
suma de puntos comprendida entre N y M. Hay que tener en cuenta que una medalla de
oro son 10 puntos, plata 5 puntos y cobre 2 puntos.

,
REFERENCIAS BIBLlOGRAFICAS

Aho, Alfred v., y Ullman, Jeffrey D.: Foundations ofComputer Science, Computer Science Press,
1992.
,
Cormen, Thomas H.; Leiserson Charles, E. , y Rivert Ronal, L.: lntroduction fo Algorithms, The
,
, Mit Press, McGraw-Hill, 1992.
,
Carrasco, Hellman y Veroff: Data Structures and problem solving with Turbo Pascal, The Benja-
min/Cummings, 1993.

I
!

!

,;
,

I - - - - -- - - - - -- - - - - - - - - - - - - - -
rboles binarios 351

Collins, William J.: Data structures. An Object-Oriented Approach, Addison-Wesley, 1992.


Franch Gutierrez, Xavier: Estructura de datos. Especificacin, Diseo e implementacin, Barce-
lona, Edicions UPC, 1994.
Hale, Guy l, y Easton, Richard J.: Applied Data Structures Using Pascal, Massachusetts, Heath,
1987.
Horowitz, Ellis, y Sartaj, Sahni: Data Structures in Pascal, Third edition, New York, Computer
Science Press, 1990.
Joyanes AguiJar, Luis: Fundamentos de programacin, 2." edicin, Madrid, McGraw-Hill, 1996.
Joyanes, L.; Zahonero, l., y Hermoso, A.: Pascal y Turbo Pascal. Un enfoque prctico, Madrid,
McGraw-Hill, 1995.
Krase, Robert L.: Data Structures and program design, Prentice-Hall, 1994.
Koffman, Elliot B., y Maxim, Bruce R.: Software Design and Data Structures in Turbo Pascal,
Addison-WesJey, 1994.
, Salmon, William J.: Structures and abstractions, Irwin, 1991.
Tenembaum Aaron, M., y Angenstein Moshe: Data structures using Pascal, Prentice-Hall, 1986.
,
CAPITULO


UII
. '. ' .. . , J '. , ','", ' , ,,, .. "
..
, "J ,',", .

CONTENIDO

11.1. Eficiencia
, de la bsqueda en un rbol binario.
11.2. Arbol binario equilibrado (AVL).
11.3. Creacin de un rbol equilibrado de N claves.
11.4. Insercin en rboles equilibrados. Rotaciones.
11.5. Eliminacin de un nodo en un rbol equilibrado.
11.6. Programa para manejar un rbol equilibrado.
RESUMEN.
EJERCICIOS.
PROBLEMAS.

En el Captulo 10 se introdujo el concepto de rbol binario. Se utiliza


un rbol binario de bsqueda para almacenar datos organizados jerr-
quicamente. Sin embargo, en muchas ocasiones, las inserciones y eli-
minaciones de elementos en el rbol no ocurren en un orden predeci-
ble; es decir, los datos no estn organizados jerrquicamente.
En este captulo se estudian tipos de rboles adicionales: los rbo-
les equilibrados o rboles AVL, como tambin se les conoce, que ayu-
dan eficientemente a resolver estas situaciones.

El concepto de rbol equilibrado as como los algoritmos de mani-

pulacin son el motivo central de este captulo. Los mtodos que des-
,

criben este tipo de rboles fueron descritos en 1962 por los matemti-

cos rusos G. M. Adelson-Velskii y E. M. Landis.
,
,
,

11.1. EFICIENCIA DE LA BSQUEDA EN UN RBOL BINARIO


,

La eficiencia para una bsqueda de una clave en un rbol binario de bsqueda vara

entre O (n) y O ( 1 og (n) ) , dependiendo de la estructura que presente el rbol.


1
."
Si los elementos se aaden en el rbol mediante el algoritmo de insercin expuesto
en el captulo anterior, la estructura resultante del rbol depender del orden en que sean

353
354 Estructura de datos

aadidos. As, si todos los elementos se insertan en orden creciente o decreciente, el


rbol va a tener todas la ramas izquierda o derecha, respectivamente, vacas. Entonces,
la bsqueda en dicho rbol ser totalmente secuencial.
R R

Figura 11.1. Bsqueda en un rbol binario.

Sin embargo, si la mitad de los elementos insertados despus de otro con clave K
tienen claves menores de K y la otra mitad claves mayores de K, se obtiene un rbol
equilibrado (tambin llamado balanceado), en el cual son suficientes un mximo de
Lag 2 (n) comparaciones para obtener un elemento.
Como resumen, en los rboles de bsqueda el nmero promedio de comparaciones
que debe de realizarse para localizar a una determinada clave es N/ 2. Esta cifra en el
rendimiento de la bsqueda resulta ser poco eficiente.
Para mejorar el rendimiento en la bsqueda surgen los rboles equilibrados.

,
11.2. ARBOL BINARIO EQUILIBRADO (AVL)
La altura o profundidad de un rbol binario es el nivel mximo de sus hojas. La altura de
un rbol nulo se considera cero.
Un rbol equilibrado es un rbol binario en el cual las alturas de los dos subrboles
para cada nodo nunca difieren en ms de una unidad. A los rboles equilibrados tambin
se les llama rboles AVL en honor de Adelson- Velskii-Landis que fueron los primeros
en proponer y desarrollar este tipo abstracto de datos.
La Figura 11.2 nos muestra un rbol AVL.
R

......,0
L


Figura 11.2. Arbol binario equilibrado (AVL).
rboles equilibrados 355

El factor de equilibrio o balance de un nodo se define como la altura del subrbol


derecho menos la altura del subrbol izquierdo correspondiente. El factor de equilibrio
de cada nodo en un rbol equilibrado ser 1, -1 o O. La Figura 11.2 nos muestra un rbol
equilibrado con el factor de equilibrio de cada nodo.

, ,
11.3. CREACION DE UN ARBOL EQUILIBRADO DE N CLAVES
Considerando la formacin de los rboles balanceados, se parecen mucho a la secuencia
de los nmeros de Fibonacci:

a(n) = a(n-2) + a(n-l)

De igual forma, un rbol de Fibonacci (rbol equilibrado) puede definirse:

1. Un rbol vaco es el rbol de Fibonacci de altura O.


2. Un nodo nico es un rbol de Fibonacci de altura 1.
3. A h . Y Ah_2 son rboles de Fibonacci de alturas h-I y h-2 entonces
Ah = < A h., x, A h_2 > es rbol de Fibonacci de altura h.

El nmero de nodos Ah viene dado por la sencilla relacin recurrente:

No = O
N = 1
Nh = N h . + 1 + N h. 2

Para conseguir un rbol AVL con un nmero dado, N, de nodos hay que distribuir
equitativamente los nodos a la izquierda y a la derecha de un nodo dado. En definitiva,
es seguir la relacin de recurrencia anterior, que podemos expresar recursivamente:

1. Crear nodo raz.


2. Generar el subrbol izquierdo con n = nl2 nodos del nodo raz utilizando la
misma estrategia.
3. Generar el subrbol derecho con nd = n-n-l nodos del nodo raz utilizando
la misma estrategia.

El programa GeneraBalanceado implementa la creacin de un rbol equilibra-


do de n claves.

program GeneraBal a n c eado( inp ut , ou t put};


us es crt ;
type
Ptrae= ANodo ;
Nod o =record
Cla ve :in teg er;
Izdo ,D c h o :P trar
end;
var
356 Estructura de datos

R :P trae ;
N :i n te ger ;

function Arb olEq (N:in tege r) : Ptrae ;


( f u n c i n para generar e l rbol equi l i brado de c l ave s . Devu e l ve
puntero a l nodo r a z )
var
Nu evo : Ptr ae ;
Niz; Ndr : i nt eger ;
begin
if N=O then
Arbol Eq: =n i l
el se begin
Ni z :=N di v 2 ;
Ndr : =N - Ni z - l;
ne w (N ue v o) ;
with Nu ev o do A
begin
wri t e ( ' Clave :' ) readl n (Clave) ;
I zdo : =A rbo le q (Niz) ;
Drc h:= Arbol eq (De r )
end;
Arboleq : =Nuevo
end
end;

procedure Di bujara r bol(R : Ptrae ; H: intege r) ;


{Di buja l os no do s d e l rbol . H n os perm i te e sta b l e ce r separacin e n tre
l os nodos}
var
I : in t eg e r;
begin
if R<> n i l then
, be g in

,, Di buja r arbol(R A . I z do ,H+ 1 ) ;


f o r 1 := 1 to H d o
write( " ) ;
wri te ln( RA. C lave ) ;
Dibuja r arbol( R A . Drc ho,H + l )
end
end;

begin {Ge ne raBala nc e ado }


c l rscr ;
wri te('N mer o d e n odos de l rbo l ? : '); readln(N) ;
R : =Ar bo l eq (N) ;
c lrs c r ;
Dibuja ra r b o l ( R,O )
end. (G eneraBa l a n cea do}

11.4. INSERCiN EN RBOLES EQUILIBRADOS: ROTACIONES


Para determinar si un rbol est equilibrado debe de manejarse informacin relativa al
balanceo o factor de equilibrio de cada nodo del rbol. Por esta razn aadimos al tipo
de datos que representa cada nodo un campo ms: el fa ctor de equilibrio (Fe).
358 Estructura de datos

factor de equilibrio de los restantes nodos, debido a que dicho factor queda como el que
tena antes de la insercin, pues el efecto de la reestructuracin hace que no aumente la
altura.
Las violaciones del factor de equilibrio de un nodo pueden darse de cuatro maneras
distintas. El reequilibrio o reestructuracin se realizan con un desplazamiento particular
de los nodos implicados, rotando los nodos. Hay rotacin derecha (D) de un nodo y
rotacin izquierda de un nodo (I).
Los cuatro casos de violacin del balance de un nodo los mostramos en las siguien-
tes figuras, as como la reestructuracin que equilibra el rbol:

a) El rbol original
....... -1

B o

Ahora se inserta el nodo A (siguiendo el camino de bsqueda) y cambia el factor de


equilibrio.

,, """' -2

e
-1

A o

En el nodo e se ha roto el criterio de equilibrio, la reestructuracin del rbol consis-


te en una rotacin izquierda, izquierda (rotacin I I).

b) El rbol original

A
,
.......0

I B

Ahora se inserta el nodo e, cambia el factor de equilibrio.


,

....... 0
rboles equilibrados 359

En el nodo A se ha roto el criterio de equilibrio, la reestructuracin del rbol consis-


te en una rotacin derecha, derecha (rotacin DD).

c) El rbol original

........ 0

Ahora se inserta el nodo B, cambia el factor de equilibrio .

........ -1

En el nodo A se ha roto el criterio de equilibrio, la reestructuracin del rbol consis-


te en una rotacin derecha, izquierda (rotacin DI).

d) El rbol original

""""'-1
e

Ahora se inserta el nodo B (siguiendo el camino de bsqueda) y cambia el factor de


equilibrio.

,......., -2

B o

En el nodo e se ha roto el criterio de equilibrio, la reestructuracin del rbol consis-


te en una rotacin izquierda, derecha (rotacin ID).

A
360 Estructura de datos

Restructurar el rbol implica mover, rotar los nodos del mismo. Las rotaciones pue-
den considerarse simples o compuestas. La rotacin simple involucra a dos nodos,
la rotacin compuesta involucra a tres nodos. Las rotaciones simples se realizan, o
bien por las ramas DD o 1 1. Las rotaciones compuestas se realizan por las ramas DI
o ID .

11.4.3. Formacin de un rbol equilibrado


A continuacin se simulan las inserciones de nodos en un rbol de bsqueda equilibra-
do, partiendo del rbol vaco. Por comodidad se supone que el campo clave es entero. El
factor de equilibrio actual de un nodo y el nuevo al aadir un nodo se representan como
superndices de los nodos. Los punteros n, nl y n2 referencian al nodo que viola la
condicin de equilibrio y a los descendientes en el camino de bsqueda.

Insercin de las claves 68 - 4 5 - 29 :

o -1

,,-.. o
68
45 o
29 o

Una vez insertado el nodo con la clave 29, al regresar por el camino de bsqueda
cambia los factores de equilibrio, as el del nodo 45 pasa a -1, Y en el nodo 68 se
pasa a -2. Se ha roto el criterio de equilibrio y debe de reestructurarse. Al ser
los factores de equilibrio -1 y -2 debe de realizarse una rotacin de los nodos JI
para rehacer el equilibrio. Los movimientos de los punteros para realizar esta ro-
tacin 11

n A.lzqdo f-- nI A .Dr c ho


nlA.Drcho f-- n
n f-- nI

Realizada la rotacin, los factores de equilibrio sern siempre O en las rotaciones


simples. El rbol queda de la forma siguiente:

,,-.. o
45

29 o
rboles equilibrados 361

Insercin de las claves 75 y 90

........ 01
45
_12
29 o 29 o 68 .... n

-o ......... 01
75 .... n1

90 o

Una vez insertado el nodo con la clave 90, a la derecha del nodo 75, y regresar por
el camino de bsqueda para as calcular los nuevos factores de equilibrio, se ob-
serva que dicho factor queda incrementado en 1 pues la insercin ha sido por la
derecha. En el nodo con clave 68 queda roto el equilibrio. Para reestructurar se
realiza una rotacin DD. Los movimientos de los punteros para realizar esta rota-

clOn DD:

n A. Drcho nl A
. Iz qd o
nl A.Iz qdo n
n nI

Una vez realizada la rotacin, los factores de equilibrio de los nodos implicados
ser O, como ocurre en todas las rotaciones simples, el rbol queda como sigue:

........ 1
45

-o
68 o

Insercin de la clave 70

........ 12
45 .... n
.........0-1
75 .... n1

......... 0
n2

Para insertar el nodo con la clave 70 se sigue el camino: derecha de 45, izquierda
de 75 y se inserta por la derecha del nodo 68. Al regresar por el camino de bs-
362 Estructura de datos

queda, los factores de equilibrio se incrementan en 1 si se fue por la rama dere-


cha, se decrementa en 1 si se fue por la rama izquierda. En el nodo 45 el balanceo
se ha roto. La rotacin de los nodos para reestablecer el equilibrio es DI. Los
movimientos de los punteros para realizar esta rotacin DI

nl A .Izqdo f- n2 A .Drcho
n2 A .Drch o f- ni
n A.Drcho f- n2 A .Izqdo
n2 A .Izqdo f- n
n f- n2

Los factores de equilibrio de los nodos implicados en la rotacin depende del

valor antes de la insercin del nodo referenciado por n2 segn esta tabla:
,

si

nA. Fe f- O O -1
ni FeA f- 1 O O
n2 .Fe
A
f- O O O

, Con esta rotacin el rbol quedara

Insercin de la clave 34

n --. 45 -1-2

90

El camino seguido para insertar el nodo con clave 34 ha seguido el camino de


izquierda de 68, izquierda de 45, derecha de 29. Al regresar por el camino de
bsqueda, el factor de equilibrio del nodo 29 se incrementa en 1 por seguir el
camino de la rama derecha, el del nodo 45 se decrementa en 1 por seguir la rama
.
I izquierda y pasa a ser -2, se ha roto el criterio de equilibrio. La rotacin de los
,
nodos para reestablecer el equilibrio es 1 D.

I
rboles equilibrados 363

Los movimientos de los punteros para realizar esta rotacin 1D

n1 A . Drcho ~ n 2 A . lzqdo
n2 . lzqdo
A
~ n1
nA . lzqdo n2 A . Drcho
n 2 A . Drc ho ~ n
n ~ n2

Los factores de equilibrio de los nodos implicados en la rotacin depende del


valor antes de la insercin del nodo referenciado por n2, segn esta tabla:

si n2 A
. Fe= O n2 A .F e= 1
n A.F e ~ 1 O O
n 1 . Fe
A
~ o O -1
n 2 Fe
A
~ O O O

Con esta rotacin el rbol quedara

11.4.4. Procedimiento de insercin con balanceo


En el procedimiento I nsert a _ba l ancead o se realizan las operaciones descritas
anteriormente.
En primer lugar el recorrido baja por el camino de bsqueda hasta insertar el nuevo
nodo como hoja del rbol. Una vez insertado, activa un indicador (flag) si ha crecido en
altura para regresar por el camino de bsqueda, determinar los nuevos factores de equi-
librio y si procede equilibrar.

function Arb olvacio( R: P t rae ): bool ean;


begin
Arbo l vac i o := R= nil
end;

function Crea r (X : T i p o info) : Ptrae ;


var
Nuevo : Pt r ae ;

begin
new(Nuevo) ;
with Nuevo A do

,
364 Estructura de datos

begin
Inf o : =x;
Izqd o :=nil;
Drc h o := n i l ;
Fe := O
end;
Crear : =Nuevo
end;

procedure Rota c i o n_d d (var N: P trae ; N1: P t rae);


begin
N A .D rcho := N1 A . lzqdo ;
N1 A . lzq do:=N;
if Nl~.Fe= 1 then
begin
{S i la r otacin es p o r una in serc i n sie mpre se cu mple la
cond ici n }
N ~ .Fe:=O;

Nl ~ .Fe:=O

end
elee begin
NA. Fe:= 1;
N1 A .F e := - 1
end;
N: =N1 ;
end;

procedure Rota c i on _ di (var N: Ptrae; N1: Ptrae) ;


{ es una Rot aci n d o ble, impl ica e l moy o de dos n o d os}
var
N2:Ptrae ;
begin
N2 :=NI A .Izqdo ;
NA . Drc ho:=N2 A . l zqdo;
N2 A.l zqdo :=N;
N1 A .lzqdo:=N2 A .Dr cho ;
N2 A . Drc ho:=N 1 ;
if (N2 A .Fe=1 ) then
NA.Fe:=-l
elee
NA . Fe:=O ;
if (N2 A .Fe= - 1) then
N1 A .F e :=1
elee
N1 A .Fe:=O;
N2 A .F e : = O;
N:=N2 ;
end;

procedure Rotacion _ ii( var N : Ptrae ; N1: Ptrae) ;


begin
NA.lz qdo := N1 A . Drc ho;
N1 A .Drcho := N ;
if N1 A .Fe= - 1 then
begin
{Si l a r o ta cin es p o r una inserc i n siempre se cu mple l a co n dicin}

rboles equilibrados 365

NA.Fe:= O;
NI A .Fe:=O
end
el Be begin
NA.Fe: = -1;
NI A.F e: = 1
end;
N:=N l ;
end;

procedure Rotacion_id(var N:Ptrae; NI:Ptrae);


{es una Rotacin doble, implica el mov. de dos nodos}
var
N2 : Ptrae;
begin
N2:= NI A.Drcho;
NA.lzqdo:= N2 A.Drcho;
N2 A .Drcho:= N;
NIA.Drcho:= N2 A .lzqdo;
N2 A.lzqdo:= NI;
if (N2 A .Fe = l) then
NIA.Fe:= - l
el Be
NI A .Fe:=O;
if (N2 A .Fe =-1) then
NA. Fe:=l
elBe
NA .F e:=O;
N2 A .Fe:=O;
N:= N2;
end;

procedure insertar_balanceado (var R: Ptr a e;


var hh: boolean; x:Tipoinfo);
{hh : act iv a do cuando ha crec i do en altura}
var
NI :Ptrae;
begin
if Arbolvacio(R) then
{se ha llegado a un nodo hoja, se crea un nuevo nodo}
begin
R:= crear(x);
,
hh: =true {La altura del rb ol cuya raJ.z es el anc estro ha crecido}
end
el se
if (x < RA.lnfo) then
begin
insertar_balanceado(RA.lzqdo, hh, x);
if (hh) then
{Hay que decrementar en 1 al Fe porq u e se
insert por rama izquierda}
case RA.Fe of
1: begin
RA.Fe:=O;
." ' hh:=false
end;
366 Estructura de datos

o: R A.F e := - l;
-1: begin (hay que reestru c tur a r ya que

pasar a a va le r -2.Es un desequilibrio I zda)


N1 : =RA . lzqdo ;
{tipos de Rotacin}
if (N1 A . Fe = -1) then
(De n uevo desequilibri o I zda . Por lo que: Rota cin ii)
Ro t ac i on_ ii(R, NI)
elee {Rotacion id}
Rotac i o n_id(R,N1) ;
hh:=false
end
end

elee if (x > RA.l n f o ) then


begin
insertar balanceado(RA .Drcho, hh, x);
if (hh) then
{Al Fe hay que incrementa rlo en I porqu e l a
insercin fue p o r rama derecha}
caee RA.Fe of
-1: begin {se r ee quilibra el solo}
RA .Fe: =O;
hh: =fa l se
end;
O: RA.Fe: = 1;
1: begin ( Hay que reequilibrar. El
desequilibri o es por Derecha)
,, NI:=R A. Drcho ;
,
;

( t ipos de Rotacin)
A
if (N1 .F e = 1) then {Rotacin dd}
Rot ac i o n_dd(R, NI)
elee (Rotac in d i)
Rotacion_di(R,N1) ;
hh := false;
end
end
end
elee begin ( x = RA. l nf o )
write ln ('No est p r ev ist o i nse rt a r claves repe t i das ' ) ;
hh:=false
end
,, end;
,

!;

, ,

11.5. ELlMINACION DE UN NODO EN UN ARBOL EQUILIBRADO

La operacin de eliminacin consiste en suprimir un nodo con cierta clave de un rbol


equilibrado. Evidentemente, el rbol resultante debe de seguir siendo un rbol equili-
brado (/h Ri - h Rd/ < = 1).
El algoritmo de eliminacin sigue la misma estrategia que el algoritmo de supresin
en rboles de bsqueda. Hay que aadirle las operaciones de restauracin del equilibrio

rboles equilibrados 367

utilizadas en el algoritmo de insercin en rboles balanceados (rotacin de nodos sim-


pIes) (dd, i i ) o dobles (d i, id). Se distinguen los siguientes casos:

l. El nodo a suprimir es un nodo hoja, o con un nico descendiente. Entonces,


simplemente se suprime, o bien se sustituye por su descendiente.
2. El nodo a eliminar tiene dos subrboles. En este caso se busca el nodo ms a la
derecha del subrbol izquierdo, y se sustituye.

Una vez eliminado el nodo siguiendo los criterios establecidos anteriormente, se re-
gresa por el camino de bsqueda calculando los nuevos factores de equilibrio (Fe) de los
nodos visitados. Si en alguno de los nodos se viola el criterio de equilibrio, debe de
restaurarse el equilibrio.
En el algoritmo de insercin, una vez que era efectuada una rotacin el proceso ter-
minaba ya que los nodos antecedentes mantenan el mismo factor de equilibrio. En la
eliminacin debe de continuar el proceso puesto que se puede producir ms de una rota-
cin en el retroceso realizado por el camino de bsqueda, pudiendo llegar hasta la raz
del rbol.
En los procedimientos se utiliza el argumento boolean hh, ser activado cuando la
altura del subrbol disminuya debido a que se haya eliminado un nodo, o bien porque al
reestructurar haya quedado reducida la altura del subrbol.

,........ -1

-1

69

En el rbol de la figura va a ser eliminado el nodo con la clave 42: al ser un nodo
hoja el borrado es simple, se suplime el nodo. Al volver por el camino de bsqueda para
determinar los Fe, resulta que el Fe del nodo con clave 39 pasara a ser -2 ya que ha
decrementado la altura de la rama derecha, es violado el criterio de equilibrio. Hay que
reestructurar el rbol de raz 39.

-1 -2
Rotacin i i porque
39 ~n nA.Fe ~ (-1-1) Y n 1 A .Fe <= o

n1

11
Estructura de datos

El rbol resultante es:

,,-...-1
55

-1

Ahora se elimina el nodo con la clave 21. Al tener dos ramas, toma el nodo ms a la
derecha de la rama izquierda que es el de clave 11. Al volver por el camino de bsqueda
para calcular los Fe, el factor de equilibrio del nodo 11 pasara a ser 2 y por tanto hay
reestructurar el rbol de raz 11.

Rotacin di porque
12 n A. Fe ~ (1 +1) y n1 A . Fe < o

26 . - n2

El rbol resultante es:

En estos dos ejemplos se observa que despus de realizar la eliminacin de un nodo,


y cuando se regresa por el camino de bsqueda, el factor de equilibrio del nodo visi-
tado disminuye en 1 si la eliminacin se hizo por su rama derecha y se incrementa
en 1 si la eliminacin se hizo por su rama izquierda. Consideremos ahora este rbol
equilibrado:

I

Arboles equilibrados 369

,.....1
65

.........1
58

73

Se elimina el nodo de clave 25. Como es un nodo hoja se suprime. La supresin se


hace por la rama izquierda, por lo que la altura de la rama derecha correspondiente aumen-
ta en 1, Y lo mismo ocurre con el factor de equilibrio. Los factores de equilibrio quedan:

.........12 Rotacin dd porque


43 ..... n
n A .Fe ~ 1+1
n lA . Fe > = o

El rbol resultante es:


,-.:.1 2
65

Al seguir regresando por el camino de bsqueda, el nodo raz debe de incrementar su


Fe con lo que pasara a +2, por consiguiente hay que restaurar el rbol, la rotacin es
derecha-izquierda ya que
"...;.1 2
65 ..... n
....... -1
70 ..... n1
1

..... n2


370 Estructura de datos

El nuevo rbol queda as es:

67

62 73 86

En el algoritmo de supresin se introducen dos procedimientos simtricos de equili-


brado: Equ i 1 i br ar 1 se invoca cuando la altura de la rama izquierda ha disminuido y
Equ ili br a r2 se invocar cuando la altura de la rama derecha haya disminuido.
En el procedimiento Equ i 1 i br a r 1 al disminuir la altura de la rama izquierda, el
factor de equilibrio se incrementa en l. Por lo que de violarse el factor de equilibrio la
rotacin que se produce es del tipo derecha-derecha, o derecha-izquierda.

procedure Eq uili br arl (var N:P tra e ; var hh : boolean) ;


{hh : a ct ivad o cu an do ha dism i nuido en alt ur a l a rama i zqu ierd a
d el n o do N}
var
NI : Ptr ae;
begin
case NA. Fe of
- 1 : NA. Fe: = O;
O: begin
NA . Fe : = 1 ;
hh := fa lse
end;

1 : begin {Hay que re s taurar el eq ui l ibrio }


Nl := NA. Dr cho ;
{Es determinado e l t ipo de r otacin}
if N1 A . Fe > = O then
begin
if N1 A.F e= O then
h h: = f al se; {No dismin u ye de n uevo l a altura }
Ro ta cio n dd(N , Nl )
end
else
Rota ci on di(N , Nl )
end
end
end;

En el procedimiento Equilibrar2 al disminuir la altura de la rama derecha, el


factor de equilibrio queda decrementado en l. De producirse una violacin del criterio
de equilibrio, la rotacin ser del tipo izquierda-izquierda, o izquierda-derecha.

~-- - - - - -- - - - - ------------ - - - -
rboles equilibrados 371

procedure Equilibrar2(var N: Ptrae; var hh: boolean);


(hh : activado cuand o ha disminuido e n alt ur a la rama derecha del n odo N)
var
NI :Ptr ae ;
begin
case NA.Fe of
1 : NA.Fe:= O;
O: begin
NA.Fe:= -1;
hh: = fal s e
end;
-1: begin ( Hay que restaurar el equilibrio)
N1:= NA.lzqdo ;
(Es d et erm in ado el tipo de rotaci n )
if NIA.Fe <= O then
begin
if NI A.Fe= O then
hh: = fal se ;
Ro tacion_ii(N, NI)
end
else
Rotacion_id(N, NI)
end
end
end;

A continuacin son escritos los procedimientos de borrar_balanceado y el


procedimiento anidado boro El algoritmo que sigue es el mismo que el de borrado en los
rboles de bsqueda sin criterio de equilibrio. La principal diferencia est en que en el
momento que una rama disminuye en altura es llamado el procedimiento respectivo de
equilibrar.

procedure borrar_balanceado(var R:Ptrae;var hh:bo o 1ean;x: Tipoinfo);

var
q:Ptrae;
procedure bor(var d: Ptr ae ; var hh: boolean);
begin
if dA.Drcho<>nil then 1
begin
bor(dA.Drcho, hh);
if hh then (Ha disminuido rama derecha)
Equilibra r2 (d, hh)
end
else begin
q A.lno:=
. f dA.ln f o ;
q:=d;
d: =d A.l zqdo;
hh:= true
end
end;
,
begin
if not ArbolVacio(R) then
if x < RA. in fo then
372 Estructura de datos

begin
bor r ar _ bal an ceado(R A. Izqdo, hh, x);
if h h then
Equi l ibr ar l(R , hh)
end
else if x>R A.in fo then
begin
bo rra r _ balanceado(R A. Drcho , hh , x ) ;
if h h then
Equil i brar2(R , h h)
end
else begin {Ha sido e n c o n trado el n od o}
q:=R;
if q A.D r cho= nil then
begin
R := q A.lzqdo ;
h h : = true {D is mi n uy e la altura}
end
else if q A. l z q do =n il then
begin
R: =q A. Drc h o ;
h h : = true
end
el se begin
bo r( qA . lzqdo, hh ) ;
if h h then
Equi l i b r arl (R, h h)
end;
d is pos e (q) ;
end
end;

, ,
11.6. MANIPULACION DE UN ARBOL EQUILIBRADO

Agrupamos todas las operaciones relativas a los rboles equilibrados en la unidad U_ av 1.


De esta forma realizamos el TAD rbol binario equilibrado. Slo presentamos la seccin
de i nt er fa ce , interfaz (en definitiva la parte pblica).
El campo de informacin se supone por comodidad que es entero. Incorporamos la
realizacin de la operacin b usc di r y mo s tra r. La operacin b usc d ir devuelve
la direccin del nodo que contiene el campo de informacin X . El procedimiento mo s -
t r a r visualiza el rbol, girado 90 grados a la izquierda respecto a la forma habitual que
se tiene de verlo en papel.

unit u Av l ;
interface
type
T i poinfo = integer ;
Ptr a e = ANod o ae ;
Nodoae = record
Info : Tipoinfo;
Fe : -1. .1 ;
-

376 Estructura de datos

RESU N

Un rbol AVL o equilibrado es un rbol binario de bsqueda en el que las alturas de los subrbo-
les izquierdo y derecho del raz difieren a lo sumo en uno y en los que los subrboles izquierdo y
derecho son, a su vez, rboles equilibrados.


Arboles equilibrados "



Insercin de un nodo. Se puede insertar un nuevo nodo en un rbol equilibrado utilizando en ,
primer lugar el algoritmo de insercin de rbol binario, comparando la clave del nuevo nodo !
con el raz e insertando el nuevo nodo en el subrbol izquierdo o derecho apropiado. i
,
Supresin de un nodo. La supresin de un nodo x de un rbol equilibrado requiere las mismas
ideas bsicas, incluyendo rotaciones simples y dobles, que se utilizan por insercin. ~
,
Arbol de Fibonacci. Es un rbol equilibrado que se define as:
1
,
l. Un rbol vaco es el rbol de Fibonacci de altura O. j

2. Un nodo nico es un rbol de Fibonacci de altura l.


3. A h. l Y A h.2 son rboles de Fibonacci de alturas h-l y h-2, entonces, A h=< Ah . l , x, A h2 >
es un rbol de Fibonacci de altura h.

1
1

1
I, i
1

l
1

!
1
I
,
Arboles equilibrados 377

EJERCICIOS
11.1. Dibuje el rbol AVL T que resulta de insertar las claves 14,6, 24,35,59, 17,21,32,4, 7,
15, 22 partiendo de un rbol vaCo.
11.2. Dada la secuencia de claves enteras: 100,29, 71,82,48, 39, 101,22, 46, 17, 3,20, 25, 10.
Dibujar el rbol avl correspondiente. Eliminar claves consecutivamente hasta encontrar un
desequilibrio cuya restauracin sea del tipo rotacin simple, rotacin compuesta.
11.3. En el rbol T resultante del ejercicio 11.1 realiza eliminaciones consecutivas de claves y
reequilibrios, si fueran necesarios, hasta encontrar una rotacin compuesta.
11.4. Tenemos que el rbol equilibrado B est vaCo. Encontrar una secuencia de n claves que al
ser insertadas siguiendo el procedimiento descrito en el captulo, se realicen al menos una
vez las distintas rotaciones: 11, DD, ID, DI. Cul es el valor mnimo de n para una secuen-
cia del tipo descrito?
11.5. Encontrar un rbol equilibrado con n claves de tal forma que despus al eliminarlas se
realicen las cuatro rotaciones para restablecer el equilibrio.
11.6. a) Cul es el nmero mnimo de nodos en un rbol equilibrado de altura lO? b) Generali-
zando, cul es el nmero mnimo de nodos de un rbol equilibrado de altura n?
11.7. El procedimiento de insertar una clave en un rbol equilibrado est escrito de manera re-
cursiva. Escribir el procedimiento de insertar en un rbol equilibrado de forma iterativa.
11.8. Escribir el procedimiento de borrar una clave en un rbol equilibrado de forma iterativa.

PROBLEMAS
11.1. Se quiere leer un archivo de texto y almacenar en memoria todas las palabras de dicho
texto y su frecuencia. La estructura de datos va a ser tal que permita realizar una bsqueda
en un tiempo O(logn), sin que dependa de la entrada de datos, por lo que se requiere utili-
zar un rbol av!. El archivo de texto se llama carta.dat, se pide almacenar dicho texto en
memoria, utilizando la estructura de rbol indicada anteriormente. Posteriormente se ha de
realizar un procedimiento, que dada una palabra nos indique el nmero de veces que apa-
rece en el texto.
11.2. En un archivo de texto se encuentran los nombres completos de los alumnos del taller de
teatro de la universidad. Escribir un programa que lea el archivo y forme un rbol binario
de bsqueda con respecto a la clave apellido. Una vez formado el rbol binario de bsque-
da, formar con sus nodos un rbol de fibonacci Tn.
11.3. Los n pueblos del distrito judicial Lupianense estn dispuestos en un archivo. Cada regis-
tro del archivo tiene el nombre del pueblo y el nmero de sus habitantes. Escribir un pro-
grama para disponer en memoria los pueblos de la comarca de la siguiente forllla: en un

vector almacenamos el nmero de pueblos, cada elemento del vector tiene el nombre del
pueblo y la raz de un rbol AVL con los nombres de los habitantes de cada pueblo. Al no

estar los habitantes almacenados en el archivo se tienen que pedir por entrada directa al

usuano.
Nota: Como es conocido el nmero de nodos de cada rbol AVL, aplicar la construccifm
de rbol de fibonacci.
11.4. Al problema 11.3 se desea aadir la posibilidad de manejar la estructura. As , aadir la
opcin de cambiar el nombre de una persona de un determinado pueblo; habr que tener
en cuenta que esto puede suponer que ya no sea un rbol de bsqueda, por ello ser nece-
378 Estructura de datos

sario eliminar el nodo y despus crear otro nuevo con la modificacin introducida. Tam-
bin queremos que tenga la opcin de que dado el pueblo A y el pueblo B, se elimine el
pueblo A aadiendo sus habitantes al pueblo B; en cuyo caso hay que liberar la memoria
ocupada por los habitantes de A.
11.5. Un archivo F contiene los nombres que formaban un rbol binario de bsqueda equi-
librado R, y que fueron grabados en F en el transcurso de un recorrido en anchura de R.
Escribir un programa que realice las siguientes tareas: a) Leer el archivo F para recons-
truir el rbol R. b) Buscar un nombre determinado en R, en caso de encuentro mostrar la
secuencia de nombres contenidos entre la raz de R y el nodo donde figura el nombre
buscado.
11.6. Una empresa de servicios tiene tres departamentos, comercial (1), explotacin (2) y comu-
nicaciones (3). Cada empleado est adscrito a uno de ellos. Se ha realizado un redistribu-
cin del personal entre ambos departamentos. El archivo EMPRESA contiene en cada re-
gistro los campos Nmero-Idt, Origen, Destino. El campo Origen toma los
valores 1, 2, 3 dependiendo del departamento inicial al que pertenece el empleado. El
campo Destino toma los mismos valores, dependiendo del nuevo departamento asignado
al empleado. El archivo no est ordenado. Escribir un programa que almacene los registros
del archivo EMPRESA en tres rboles AVL, uno por cada departamento origen, y realice el
intercambio de registros en los rboles segn el campo destino .


,
CAPITULO

,,
o es
-- ..- - - - 0 ,- '
.. . _ ..
" . . .. ,.

CONTENIDO

12.1. Definicin de un rbol 8.


12.2. Representacin de un rbol 8 de orden m.
12.3. Proceso de creacin en un rbol 8.
12.4. 8squeda de una clave en un rbol 8.
12.5. Algoritmo de insercin en un rbol 8 de orden m.
12.6. Recorrido en un rbol 8 de orden m.
12.7. Eliminacin de una clave en un rbol 8 de orden m.
12.8. TAO rbol 8 de orden m.
12.9. Realizacin de un rbol 8 en memoria externa.
RESUMEN.
EJERCICIOS.
PR08LEMAS.

Los rboles B se utilizan para la creacin de bases de datos. As, una


forma de implementar los ndices de una base de datos relacional es a
travs de un rbol B.
Otra aplicacin dada a los rboles B es en la gestin del sistema de
archivos del sistema operativo OS/2, con el fin de aumentar la eficacia
en la bsqueda de archivos por los subdirectorios.
Tambin se conocen aplicaciones de los rboles B en sistemas de
comprensin de datos. Bastantes algoritmos de comprensin utilizan
,

,
rboles B para la bsqueda por clave de datos comprimidos.

,
,
,

I 12.1. DEFINICiN DE UN RBOL B

Es costumbre denominar a los nodos de un rbol B, pgina. Cada nodo, cada pgina, es
una unidad a la que se accede en bloque.
Las estructuras de datos que representan un rbol B de orden m tienen las siguientes
, .
caractenstlcas:

379
380 Estructura de datos

Todas las pginas hoja estn en el mismo nivel.


Todos las pginas internas, menos la raz, tienen a lo sumo m ramas (no vacas) y
como mnimo m/2 (redondeando al mximo entero) ramas.
El nmero de claves en cada pgina interna es uno menos que el nmero de sus
ramas, y estas claves dividen las de las ramas a manera de un rbol de bsqueda.
La raz tiene como mximo m ramas, puede llegar a tener hasta 2 y ninguna si el
rbol consta de la raz solamente.
Los rboles B ms utilizados cuando se manejan datos en memoria principal son los
de orden 5; un orden mayor aumenta considerablemente la complejidad de los algorit-
mos y un orden menor disminuye la eficacia de la localizacin de claves.
En la Figura 12.1 se muestra un rbol B de orden 5, donde las claves son las letras
del alfabeto.

I L S X
....... .......

A e D J K M o Q R T U Y Z

Figura 12.1. rbol de orden 5.

En el rbol B de la figura hay 3 niveles. Todas las pginas contienen 2, 3 o 4 elemen-


tos. La raz es la excepcin, tiene un solo elemento. Todas las pginas que son hojas
estn en el nivel ms bajo del rbol, en la figura en el nivel 3.
Las claves mantienen una ordenacin de izquierda a derecha dentro de cada pgina.
Estas claves dividen a los nodos descendientes a la manera de un rbol de bsqueda,
claves de nodo izquierdo menores, claves de nodo derecho mayores. Esta organizacin
supone una extensin natural de los rboles binarios de bsqueda. El mtodo a seguir
para localizar una clave en el rbol B va a seguir un camino de bsqueda.

12.2. REPRESENTACiN DE UN RBOL B DE ORDEN m


Para representar una pgina o nodo del rbol B tenemos que pensar en almacenar las
claves y almacenar las direcciones de las ramas que cuelgan de los nodos. Para ello se
utilizan dos vectores, y un campo adicional que en todo momento contenga el nmero de
claves de la pgina.
Las declaraciones siguientes se refieren a un rbol B de orden 5.
const
Max= 4; {Nmer o mximo de c l a ves de una pg ina. max = m-l,siend o m el
orden del rbOl }
Min= 2 ; {Nmero mn i mo de c la ves en u n n odo distinto de la raz;
mi n = l!2m -l}
rboles B 381

type
Ti poclave= I

Ptrb= ~ Pagina;
posicion = O.. Max;
Pag ina = record
Cuenta : O .. max;
Claves: array [1 .. max] of Tipoclave;
Ramas: array [Posi c i on] of Ptrb;
end;

La razn de indexar Ramas desde O est en que cada pgina tiene un nmero de
ramas igual al de claves ms 1, Y que es la forma ms fcil de acceder a la rama ms a la
izquierda.

12.3. PROCESO DE CREACiN EN UN RBOL B


La condicin de que todas la hojas de un rbol B se encuentren en el mismo nivel
impone el comportamiento caracterstico de los rboles B: crecen hacia arriba, cre-
cen en la raz.
El mtodo que se sigue para aadir un nueva clave en un rbol B es el siguiente:

Primero se busca si la clave a insertar est ya en el rbol, para 10 cual se sigue el


camino de bsqueda.
En el caso de que la clave no est en el rbol, la bsqueda termina en un nodo
hoja. Entonces la nueva clave se inserta en el nodo hoja. Ms bien, se intenta
insertar en el nodo hoja como a continuacin estudiamos.
De no estar lleno el nodo hoja, la insercin es posible en dicho nodo y termina la
insercin de la clave.
El comportamiento caracterstico de los rboles B se pone de manifiesto ahora.
De estar la hoja llena, la insercin no es posible en dicho nodo, entonces se
divide el nodo (incluyendo virtualmente la clave nueva) en dos nodos en el mis-
mo nivel del rbol, excepto la clave mediana que no se incluye en ninguno de
los dos nodos, sino que sube en el rbol por el camino de bsqueda para a su vez
insertarla en el nodo antecedente. Es por esto por 10 que se dice que el rbol
crece hacia arriba. En esta ascensin de claves medianas puede ocurrir que
llegue al nodo raz, entonces sta se divide en dos nodos y la clave enviada
hacia arriba se convierte en una nueva raz. Esta es la forma de que el rbol B
crezca en altura.

Un seguimiento de creacin de un rbol B de orden 5 con las claves enteros sin


signo. Al ser de orden 5 el nmero mximo de claves en cada nodo ser 4. Las claves que
se van a insertar:

6 11 5 4 8 9 12 21 14 10 19 28 3 17 32 15 16 26 27
382 Estructura de datos

Con las cuatro primeras se completa el primer nodo (recordar que tambin es lla-
mado pgina), eso s, ordenadas crecientemente a la manera de rbol de bsqueda.

4 5 6 11

La clave siguiente, 8, encuentra el nodo ya lleno. La clave mediana de las cinco


claves es 6. El nodo lleno se divide en dos, excepto la clave mediana que sube
. ,
y se convierte en nueva ralz:

L.
4 5 8 11

Las siguientes claves, 9, 12, se insertan siguiendo el criterio de bsqueda, en el


nodo rama derecha de la raz por ser ambas claves mayores que 6:

4 5 8 9 11 1 2

La clave 21 sigue por el camino de bsqueda, derecha del nodo raz. El nodo
donde debe de insertarse est lleno, se parte en dos nodos, y la clave mediana 11
asciende por el camino de bsqueda para ser insertada en el nodo raz:

6 11

4 5 8 9 12 21

Las siguientes claves, 14, 10, 19, son insertadas en los nodos de las ramas que
se corresponden con el camino de bsqueda:

6 11

4 5 8 9 10 12 1 4 19 21

Al insertar la clave 28 de nuevo se va a producir el proceso de divisin del nodo


derecho del ltimo nivel y ascensin por el camino de bsqueda de la clave me-
diana 19:
rboles B 383

6 11 19

4 5 8 9 10 12 14 2 1 28

Continuando con la insercin, las claves 3 1 7 32 15 son insertadas en los


nodos hoja siguiendo el camino de bsqueda:

6 11 1 9
~ ...

3 4 5 8 9 10 12 14 1 5 17 21 28 32

Al llegar la clave 16, baja por el camino de bsqueda (rama derecha de clave
11 en nodo raz). El nodo donde va a ser insertado est lleno. Se produce la divi-
sin en dos del nodo y la ascensin de la clave mediana 15:

6 11 1 5 19

3 45 8 9 10 12 14 16 17 21 28 32

Por ltimo, al insertar las claves 26 Y 27, primero se llena el nodo ms a la dere-
cha del ltimo nivel con la clave 2 6. Con la clave 27, que sigue el mismo camino
de bsqueda, ocurre que provoca que se divida en dos el nodo y ascienda al nodo
padre la clave mediana 27. Ahora bien, ocurre que el nodo padre tambin est
lleno por 10 que tambin se divide en dos, sube la clave mediana 15, pero como el
nodo dividido es la raz, con esta clave se forma un nuevo nodo raz: el rbol ha
crecido en altura. El rbol crece hacia arriba, hacia la raz.

15
lo ...
, r
6 11 19 27

345 8 9 10 1 2 14 16 17 2 1 26 28 32

En esta formacin de rbol B que hemos ido realizando podemos observar estos dos
hechos relevantes:

Una divisin de un nodo, prepara a la ~tructura para inserciones simples de nue-


vas claves.

l
384 Estructura de datos

Siempre es la clave mediana la que sube al nodo antecedente. La mediana no


tiene por qu coincidir con la clave que se est insertando. Por lo que podemos
afirmar que no importa el orden en que lleguen las claves en el balanceo del rbol.

12.4. BSQUEDA DE UNA CLAVE EN UN RBOL B


En los algoritmos de insercin se hace uso de la operacin de bsqueda; por ello se
expone a continuacin el algoritmo de bsqueda de una clave en un rbol B.
El algoritmo sigue la misma estrategia que la bsqueda en un rbol binario de bs-
queda. Salvo que en los rboles B cuando estamos posicionados en una pgina (nodo)
hay que inspeccionar las claves de que consta. La inspeccin da como resultado la posi-
cin de la clave, o bien el camino a seguir en la bsqueda.
La operacin es realizada por un procedimiento que tiene como entrada la raz del
rbol B y la clave a localizar. Devuelve un valor lgico (true si encuentra la clave), la
direccin de la pgina que contiene a la clave y la posicin dentro del nodo. El examen
de cada pgina se realiza en el procedimiento auxiliar Busca rnodo.
procedure Buscarnodo (C l a v e : Tipoclave ; P : Ptr b;
var Enco n t rado : boo l ea n; var K: Pos ic i on ) ;
( Exa min a l a pgi n a r efere ncia da po r P. De no enco n t r a rse , K ser el
n dice de l a ra ma p o r dond e ' ' ba j ar ' ' )
begin
if Cl ave < P~ . c la v es [l l then
begin
Encon trad o : = false;
K : =O (Rama por donde descen der)
end
el se begin
{Exami na claves de l a pgina }
K : = p A. Cuenta ; {Nmero de c l av e s de la pgina}
while (Clave< P ~ . c l a ve s [kl) and (K> 1) do
K := K- 1 ;
En con t rado : = (Clave = P~ . C l aves [ K l )
end
end;

El procedimiento Bu sc ar controla el proceso de bsqueda:


procedure Bus c ar (Clav e : T ipocl ave; Ra iz: Pt r b ;
var Encontrad o : boolean ;var N:Ptrb; var Pos : Pos i cion );
begin
if Ar bolvaci o(Raiz) then
Encon t rado : = fa l se
else begin
Buscar no do(Cl av e, Raiz , Encon t rado , Pos) ;
if En co n t r ado then
N : = Raiz {Dire cc i n d e l a pg i na}
else (Pos e s e l nd i ce de la rama)
Buscar(C l av e , Ra i z A. Ra mas [ Posl , En co n trado, N, Pos)
end
end;
rboles B 385

12.5. ALGORITMO DE INSERCiN EN UN RBOL B


DE ORDEN m
La insercin de una nueva clave en un rbol B es relativamente simple, como ocurre en
la bsqueda. Si hay que insertar una clave en una pgina (nodo) que no est llena (nme-
ro de claves < m-l), el proceso de insercin involucra a esa pgina nicamente. Slo si
la pgina est llena la insercin afecta a la estructura del rbol. La insercin de la clave
mediana en la pgina antecesora puede a su vez causar el desbordamiento de la misma,
con el resultado de propagarse el proceso de particin, pudiendo llegar a la raz. Esta es
la nica forma de aumentar la altura del rbol B.
Una formulacin recursiva va a ser la adecuada para reflejar el proceso de propaga-
cin en la divisin de las pginas, debido a que se realiza en el sentido inverso por el
camino de bsqueda.
El diagrama de bloques del proceso de insercin se muestra en la Figura 12.2

el Raz

Inserta

t
EmpujaArriba t Mdna
Empujar

Rama?

vacla

Si
Mdna XR
R,
R Mdna
BuscarNodo MeterHoja DividirNodo

Figura 12.2. Diagrama de bloques del proceso de insercin.

El procedimiento de insercin recibe la clave nueva y la raz del rbol B. Este proce-
dimiento pasa control al procedimiento empujar que baja por el camino de bsqueda
determinado por Buscarnodo, hasta llegar a un nodo hoja. El procedimiento Me-
terHoj a realiza la accin de aadir la clave en el nodo. Si el nodo tiene ya el mximo
de claves, es llamado el procedimiento dividimodo para que a partir del nodo lleno se
formen dos nodos y ascienda la clave mediana.
rboles B 387

procedure Empujar(Cl:Tipo clave ;R:Ptrb;var EmpujaArriba: boo l ea n;


var Md na : Tipoc l ave; var Xr: Pt r b) ;
var
K : Posicion ;
Esta : bool ean; {Detecta que la clav e ya est en el nodo}
begin
if Arbolvacio(R) then
begin {Term ina la recurs i n, estamos en rama vaca}
EmpujaArr iba: = true;
Mdna : = el;
Xr : = nil
end
else begin
Buscarnodo(C l , R, Esta, K) ; {K: rama por donde seg u i r}
if Es t a then
begin
writeln (el, ' No permitido claves repet i das ' ) ;
halt ( 1)
end;
Empujar(e l,RA .Ramas [ K] ,EmpujaArriba, Mdna, Xr) ;
if EmpujaArriba then
if RA .eu en t a < Max then {No est lleno el nodo}
begin
EmpujaArriba : = fa l se; {Proceso t ermina }
MeterHoja(Mdna, Xr, R, K) ; { I nsertar l a c lave Mdna en e l nodo
R, posicin K+ 1 }
end
else begin {Nod o llen o}
Emp u jaArriba : = t rue;
Div idi rnodo(Mdna, Xr, R, K, Mdna, Xr)
end
end
end;

Procedimiento MeterHoj a
A este procedimiento se llama cuando ya se ha determinado que hay hueco para aadir
a la pgina una nueva clave. Se le pasa como argumentos la clave, la direccin de la
pgina (nodo), la direccin de la rama con el nodo sucesor, y la posicin a partir de la
cual se inserta.

procedure MeterHoja (X :T ipoc l ave ;Xder, P:Pt rb; K:Posic i on) ;


var
1: Posic ion;
begin
with PA do
begin
for 1: = Cuenta downto K+1 do
begin {Son desp lazadas c l aves / ramas para ins e r tar X}
Claves [1 +1 ] : = Claves [1] ;
Rama s [ 1 + 1] : = Rama S [ 1 ]
end;

..
388 Estructura de datos

Claves [K+l J : = X;
Ramas[K+IJ:= Xder;
Cuenta:= Cuenta+l
end
end;

Procedimiento de divisin de un nodo lleno


El nodo donde hay que insertar la clave x y la rama correspondiente est lleno. A nivel
lgico es dividido el nodo en dos nodos y la clave mediana enviada hacia arriba para una
reinsercin posterior. Para ello lo que se hace es crear un nuevo nodo donde se llevan las
claves mayores de la clave mediana, dejando en el nodo original las claves menores.
Primero se determina la posicin que ocupa la clave mediana, teniendo en cuenta la
posicin central del nodo y la posicin donde debera de insertarse la nueva clave. A
continuacin se divide el nodo, se inserta la nueva clave en el nodo que le corresponde y
por ltimo se extrae la clave mediana.

procedure DividirNodo(X:Tipoclave;Xder,P:Ptrb;K:Posicion;
var Mda: Tipoclave; var Mder:Ptrb);
var
I, Posmda: Posicion;
begin
if K <= Min then {Min es la posicin central}
{La clave se situa a la izquierda}
Posmda:= Min
else
Posmda:= Min+l;
new(Mder) ; { Nuevo nodo }
with PAdo
begin
for I:= Posmda+l to Max do
begin
Mder A . Claves [I-PosmdaJ : =Claves [IJ ; {Es desplazada la mitad
derecha al nuevo nodo,la clave mediana se queda en nodo
izquierda}
MderA.Ramas[I- PosmdaJ:= Ramas[IJ i
end; ,
,j,
!
MderA.Cuenta:= Max- Posmda; {Claves en el nuevo nodo} ,
'j
j
Cuenta:=Posmda;{Claves que quedan en nodo izquierda} "

,,
I
{Insercin de clave X y su rama derecha} ..
if K<= Min then
Meterhoja(X,Xder,P,K) {inserta en nodo izquierda}
el se
Meterhoja(X, Xder, Mder, K-Posmda);
,,
,i,
{extrae mediana. del nodo izquierdo} ,:1
Mda:= Claves [CuentaJ ; i

MderA.Ramas[OJ:= Ramas [CuentaJ ; {Ramao del nuevo nodo es la rama de .,i,
i
la mediana} !
Cuenta:= Cuenta-l {Disminuye ya que se quita la mediana} l,
end I

end; I i

,,I

I
, ,

,I
!

j
!

Arboles B 389

12.6. RECORRIDO EN UN RBOL B DE ORDEN m


El recorrido en un rbol B consiste en visitar todos los nodos del rbol , y para cada nodo
todas las claves de que consta. Con una pequea variacin de los recorridos de un rbol
binario, se puede aplicar al de un rbol B.
Se presenta a continuacin el recorrido que visita las claves en orden creciente, es un
recorrido en inorden. En primer lugar, la versin recursiva:
procedure InordenB(R : Ptrb ) ;
var
l : integer;
begin
it not Arbo l vacio(R) then
begin
I n ordenB( RA. Rama s[ Ol) ;
tor l:= 1 to RA . Cu en t a do
begin
wr i t e 1 n (R A . C 1 av e s [ 1 1 ) ;
lnord e nB (R A.Rama s[I] )
end
end
end;

La versin no recursiva utiliza una pila para almacenar la direccin del nodo y el
ndice de la rama.
procedure Inord en B (R : P trb) ;
var
1 :in t eg er ;
P : Pt rb;
Pila : p trpla ;
begin
Pcrear(Pila) ;
P := R ;
repeat
l := O;
while not Arb olvac io(P ) do
begin
Pmeter(P , I, Pila ) ;
P : = PA .R amas[ Il
end;
if not Pvacia(pila) then
begin
Psa c ar( P, l, Pil a ) ;
1: = 1+ 1;
if l <= pA . Cuenta then
begin
wr i te l n(PA . Clavesl I l ) ; { P r oce so d e l a clavel
if 1 < pA .C uenta then
Pme te r ( P , 1, Pi 1 a) ;
P: = P A.Ramas [ I ]
end
end
until Pvac ia( Pi la) an d Ar bolvacio(P)
end ;
390 Estructura de datos

, ,
12.7. ELlMINACION DE UNA CLAVE EN UN ARBOL B
DE ORDEN m
Al igual que las inserciones de una clave siempre se hacen en una pgina hoja, las elimi-
naciones siempre se harn en una pgina hoja. Es evidente que una clave no tiene por
qu estar en un nodo hoja, para eIlo se aplica la siguiente caracterstica de los rboles B:
si una clave no est en una hoja, su clave predecesora o sucesora (predecesora o suceso-
ra en el orden natural) estar en un nodo hoja.

. 45
..
16 26 79 172

5 9 15 18 22 24 29 3 2 4 8 57 82 126 192 2 32

Una primera consecuencia es que si la clave a eliminar no est en una hoja, se pondr
I
a la clave predecesora en la posicin ocupada por la clave eliminada y se suprimir la
clave en la hoja. As se observa la figura con el rbol B de orden 5.
Se quiere eliminar la clave 1 6, esta clave no est en una hoja; el sucesor inmediato
de 16 , que es 1 8, se pone en la posicin de 1 6 y luego 1 8 se suprime en el nodo hoja en
que se encuentra:

. 45
..
18 26 79 172

5 9 15 22 2 4 29 32 48 57 82 126 1 92 23 2

Esta supresin que acaba de realizarse es el ms fcil , es el caso en el que la hoja


donde se va a eliminar contiene un nmero de claves mayor que el mnimo de claves que
puede haber en un nodo, una vez eliminada no hay que hacer una accin posterior.
En el caso de que la hoja donde se vaya a eliminar la clave tenga el nmero mnimo
de claves, al eliminar una clave se va a quedar con menos claves que el mnimo exigido
,, por nodo. Claro est que hay que realizar una operacin de movimiento de claves para

que el rbol siga siendo un rbol B: se procede a examinar las hojas inmediatamente
adyacentes al nodo con el mismo antecedente. Si una de estas hojas tiene ms del nme-
ro mnimo de claves, puede moverse una de eIlas para as restablecer el mnimo de clave.
Para que las claves del rbol sigan dividiendo a las claves de sus nodos descendientes a
la manera de rbol de bsqueda, el movimiento de claves consiste en subir una clave al

, _,~_ o.
rboles B 391

nodo padre para que a su vez descienda de ste otra clave al nodo que se quiere restaurar.
As queda restaurado el nodo y sigue siendo un rbol B.
En el rbol resultante de la eliminacin anterior se elimina ahora la clave 2 4. El
nodo que la contiene tiene dos claves, entonces se elimina la clave y se analiza los nodos
contiguos del mismo antecedente. Resulta que en el nodo izquierda tiene tres claves, por
lo que asciende la clave 1 5 al nodo padre, y a su vez de ste desciende la clave 1 8 para
ser insertada en el nodo a restaurar. El rbol resultante:

L
45
..
.,
15 26 79 1 72

5 9 18 22 29 32 48 57 82 1 26 192 232

An queda otro caso ms complejo que los dos anteriores. Al eliminarla clave 22
del nodo hoja, ste se queda con una menos que el mnimo y las dos hojas contiguas
tienen nicamente el mnimo de claves. La estrategia a seguir en este caso: se toma la
hoja a eliminar, su contigua y la clave mediana de ambas, procedente del nodo antece-
dente, y se combinan como un nuevo nodo hoja. Claro est que esta combinacin puede
dejar al nodo antecedente con un nmero de claves menor que el mnimo, entonces el
proceso se propaga hacia arriba, hacia la raz. En el caso lmite, la ltima clave ser
extrada de la raz y luego disminuir la altura del rbol B.
Partiendo del ltimo rbol B, ahora queremos eliminar la clave 22. El nodo donde se
encuentra se queda con una sola clave, y los nodos adyacentes tienen justamente el m-
nimo de claves. La siguiente combinacin restaura al nodo:

1 5 26

5 9 18

El rbol que resulta inmediatamente despus del proceso:


L
45
..
r
26 79 17 2

5 9 1 5 18 29 3 2 48 57 82 12 6 192 23 2

Este proceso ha dejado al nodo antecedente con una sola clave, menos que el mnimo
necesario. El proceso se propaga al nivel anterior, producindose esta combinacin:
392 Estructura de datos

45

26 79 17 2

El rbol B que resulta

26 45 79 122

5 9 15 18 29 3 2 4 8 57 82 12 6 192 232

ha disminuido la altura del rbol, el proceso de combinacin de dos nodos ha alcanzado


a la raz.

Diagrama de bloques del proceso de eliminacin


El proceso empieza con la llamada al procedimiento E l iminar, ste pasa control a
El i min a rR e g ist r o que es el encargado de controlar todo el proceso.

CI Raz
Eliminar

CI.
,,
Raz t Encontrar
EliminarRegistro

Act

K K K
K

Encontrar
BuscarNodo Quitar Sucesor r--R-e-s-ta....
b-Ie-ce-r- Restaura el nodo
act t Ramas [K]}
Act
{Elimina la clave {Reemplaza
en nodo hoja} clave por la
que le sucede}
K

Mover Mover
Combina
derecha izquierda

Figura 12.3. Diagramas de bloques del proceso de eliminacin.


rboles B 393

Procedimiento Eliminar

El procedimiento E l i minar tiene la misma estructura que I nse rtar. Tiene como
misin principal devolver la nueva raz si la raz inicial se ha quedado sin claves.

procedure Elimi n a r (el : Tipoclave ; var Rai z : Pt r b) ;


var
Encontrado : boolean;
P: Ptrb;
begin
Eli minarRegist r o(e l, Raiz , Encontra d o};
if not Enco n trado then
wr i te l n( 'E rror :l a clave n o est en e l rbo l ')
elae if Ra iz A. euenta= O then {La ra z se ha quedado vaca }
begin {Se liber a el nodo y se obtie ne la nueva ra z }
P := Rai z;
Raiz : = RaizA.R amas[O];
dispose (P)
end
end;

Procedimiento EliminarRegistro
Este procedimiento controla el proceso de borrado de una clave. Primero busca el nodo
donde se encuentra la clave a eliminar. Si el nodo es una hoja, llama a la rutina que
elimina. De no ser hoja, es hallado el inmediato sucesor de la clave, se coloca en el nodo
donde se encuentra la clave; despus se suprime la clave sucesor en el nodo hoja.
La forma ms fcil de expresar este proceso es la recursiva; al retornar la llamada
recursiva debe de comprobar si hay un nmero de claves suficientes, mayor o igual que
el mnimo necesario (2 en el caso de rbol B de orden 5), de no ser as hay que mover
claves al nodo para alcanzar el nmero necesario de claves.
procedure Eli minarRegistro(el : T i poc l ave ; R : Ptrb;
var En con t rado : boo l ean) ;
var
K: Posic i o n;
begin
if Arbolvac io (R) then
Encon trado:= false {Se ha l l e gado "d ebajo " de una h oj a, la c l ave no
est e n el rbo l }
elae with R A do
begin
Buscarno d o(el, R, Enc on trado , K) ;
if Encontrado then
if Ra mas [ K-l ]= n i l then {L as r amas estn i n d e xadas desde n dice O
a Max, por 10 que este n odo es h oja}
Qu ita r (R, K)
elae begin {No e s ho ja}
Sucesor(R , K); {Reemp l aza e l aves [ K)por su sucesor}
Elimi n arRegistr o(C l a ves [ K] , Ra mas[K ] , Encontrado) ; {Elim i na la
c lave suceso r a e n su nodo}
394 Estructura de datos

if not Encontrado then {Es una inconsistencia, la clave debe de


estar en el nodo}
begin
writeln( 'Error en el proceso');
Halt (1)
end
end
elBe {No ha sido localizada la clave}
EliminarRegistro(Cl, Ramas[K] , Encontrado);
{Las llamadas recursivas devuelven control a este punto del
procedimiento: se comprueba que el nodo hijo mantenga un nmero de
claves igual o mayor que el mnimo necesario}
if Ramas[K]< > nil then {Condicin de que no sea hoja}
if Ramas[K]A.Cuenta< Min then
Restablecer(R, K)
end
end;

Procedimiento Qui tar


Esta rutina recibe la direccin del nodo y la posicin de la clave a eliminar. Elimina la
clave junto a la rama que le corresponde .
.
procedure Quitar(P: Ptrb; K: Posicion);
var
J: Posicion;
begin
with pA do
begin
for J:= K+l to Cuenta do
begin
. "
Claves [J-1] : = Claves [J]; {Desplaza una pOSlClon a la izquierda, con
ello es eliminada la clave}
Ramas [J-l] : = Ramas [J]
end;
Cuenta:= Cuenta- 1
end
end;

Procedimiento Sucesor
En esta rutina se busca la clave inmediatamente sucesor de la clave K, que por la propie-
dad de los rboles B est en una hoja, y sta reemplaza a la clave K.
procedure Sucesor(P: Ptrb; K: Posicion);
var
Q: Ptrb;
begin
Q:= pA.Ramas[K];
while QA.Ramas[O]<> nil do
Q:= QA.Ramas[O];
{Q referencia a un nodo hoja}
PA.Claves[K]:= QA.Claves[l]
end;

,
rboles B 395

Procedimiento Restablecer
En este procedimiento se realizan las acciones ms complejas del proceso. Restaura
el nodo p Ra ma s [K) el cual se ha quedado con un nmero de claves menor que el
A
, .
mmlmo.
El procedimiento siempre toma una clave a partir del hermano de la izquierda (cla-
ves menores), slo utiliza al hermano derecho cuando no hay hermano izquierdo. Puede
ocurrir que no pueda tomar claves y entonces llamar a Combin a para formar un nodo
con dos nodos.

procedure Resta blecer(P : Pt rb ; K: Posi cio n ) ;


{P t i ene l a direccin del nodo ant e cede n te de l nodo P A. Ram a s[K] que s e
ha quedado co n me n o s claves que e l m nimo}
begin
if K > O then
{T i ene " he rma no " i zqui erdo}
if P A. Ramas[ K- l]A .Cuent a> Mi n then
{Tiene ms cl aves que e l mn i mo y por ta n to pu ed e
desplazarse una clave}
Mover Drcha(P , K)
elee
Comb i na(P , K)
elee
{S l o t i e ne " her ma n o " der ec h o}
if P A . Ramas[l] A. Cuent a > Min then
{Tiene ms c l aves que e l mnimo}

Mover l zqda(P , 1 )
elee
Combin a(P , 1)
end;

Procedimiento MoverDerecha
Este procedimiento mueve una clave del nodo antecedente ( p) al nodo que se est res-
taurando. A su vez, asciende la clave mayor del hermano izquierdo al nodo antecedente.

procedure MoverDrc h a(P : Pt rb ; K: posic i o n );


{En este proced im iento se de j a "hu eco " en el n odo pA. Ra mas [ K] A que es
el nodo qu e tiene me no s claves qu e el m nimo n ecesa ri o , i n serta l a
clave k del nodo ant eced ent e y a su v ez asc iend e l a c lave mayor( l a
ms a l a der echa)del he rmano iz quie rdo}
var
J : Posic i o n ;
begin
with PA . Ramas [ K]A do {es e l nodo con menos claves que e l mnimo }
begin
for J := Cuenta downto 1 do
begin
c l aves [J+1 ] : = c l aves [ J ] ;
Ra mas [ J +1 ] : = Ramas [ J ];
end;
396 Estructura de datos

Cu e n ta:= Cue n ta+ l ;


Ra mas [l ] : = Ramas[O] ;
Clav es [l] : = PA . Cl a ves [ K] { "ba ja " la clave del no d o padre }
end;
{Ahora " sub e " la cla v e desde el herm a n o izq ui erdo al nodo padre, para
ree mplazar la que an t es baj }

with pA.Ram a s [K - l ] A do {Herman o i zqu ierdo}


begin
pA . Claves [K ] : = Cla ve s [Cu enta] ;
P A. Ramas[K ]A .R amas [ O] : = Ramas [Cu e nta] ;
Cuent a := Cuenta -l
end
end ;

Procedimiento MoverIzquierda

Realiza la misma accin que el procedimiento Moverderecha , salvo que ahora la clave
que asciende al nodo antecedente es la clave menor (izquierda) del nodo a restaurar.

procedure MoverI zqda I P : P t r b ; K : Pos i cion) ;


( Desci e n de l a c l ave KIl) del nod o padr e P al hijo izq u i erda y la
insert a e n l a pos icin ms alta , de esta forma se res t ab lece el mnimo
de clav es . Despus sube la clave 1 d el h ermano de r echo . }
var
J : Posic i o n;
begin
with p A. Rama s[K- l ]A do { es el nodo con men os claves que el mnimo}
begin
Cue nta:= Cu e n ta + l ;
Claves [Cu e nt a ] : = PA . Claves [K] ;
Ramas[Cuent a ]: = pA .R a mas[ K]A.Ram as[O ]
end;
with PA . Ramas[ K]A do {Her ma no dere cho}
begin
P A. Cl aves [ K] : = Claves[l] ; { S u be al n o do pad r e l a clave 1 de l
h erm a no d er echo , sustituye a la qu e ba j}
Ramas [ O] : = Ramas [1] ;
Cuent a:= Cuenta -l ;
for J:= 1 to Cuenta do
begin
Claves [J] : = Claves [J+l ];
Ramas[ J] : = Ra mas [ J +l]
end
end
end;

Procedimiento Combina

En este procedimiento se forman un solo nodo con dos nodos. Combina el nodo que est
en la rama K con el que est en la rama K - 1 Y la clave mediana de ambos que se encuen-
tra en el nodo antecedente. Una vez finalizado el proceso, libera el nodo obsoleto.

- - - -- -- -
rboles B 397

procedure Combi na(p : Ptrb ; K: Posicion);


{Forma un nuevo n odo con el her ma no izquierdo , la media n a e n tre e l no do
p r o bl ema y su h ermano i zqu ier d o si t uada en el nodo p ad re , y l as clav es
del n odo prob l ema . Es liberado e l nodo pr ob lema}
var
J: p o sicio n;
Q : Ptrb;
begin
Q : = P A. Ram a s[K ] ;
with p A. Ra mas [ K- l ] A do {Herma no iz quier d o}
begin
Cuenta : = Cu e n ta + l ;
Claves [ Cuent a ] : = p A . C l a v es [K] ; { " b aja" c lav e me di ana d esde el no do
pa d re }
Ramas [ Cuenta ] : = QA. Ra ma s [ O] ;
for J := 1 to QA.C ue nta do
begin
Cu e n ta : = Cuenta+l ;
Cl av es [ Cue nta] : = QA. Cl aves [J ] ;
Ramas[Cuenta] := QA.Ramas[J] ;
end
end;

{So n rea j ustadas las claves y ra mas de l nodo padre debido a q u e


an t es descendi l a clave k}
with pA do
begin
for J := K to Cuenta-l do
begin
C l av es [ J ] : = C l aves [ J +l];
Ramas [J] : = Ramas [ J+ l ]

end;
Cuenta : = Cuenta - l
end;
dis p ose( Q)
end;

,
12.8. TAO ARBOL B DE ORDEN m

Hasta ahora se ha descrito un rbol B, cmo representar al rbol B de orden m y qu


operaciones son definidas sobre la estructura; es decir, se ha definido el tipo abstracto
de datos rbol B. A continuacin se escribe la unidad rbol B, aunque slo la seccin
de in t erfa c e; la seccin imp l e me n ta t i o n ha sido escrita paso a paso en los
apartados anteriores.

unit Ar b o lB ;
interface
const
Or de n -- S ,,
Ma x - Or d en - l ; {Nm e ro m x imo d e c la v e s en un nodo }
Min = (O r den-l ) d i v 2; {Nme ro mn i mo d e cla v es e n un n od o di st into
de la ra z}
398 Estructura de datos

type
Tipoclave - in tege r;
Ptrb = APag in a ;
posicion = O .. Max;
Pagina= record
Cu enta: O ., max;
Claves: array [1 .. maxJ of Tip oclave ;
Ramas: array [PosicionJ of Ptr b ;
end;

procedure Buscarnodo (C la ve : Tipoc la ve ; P : P t rb;


var En con trado : bool ean; var K: Posici o n);
procedure Bus car (Cla ve: T ipocla ve; Raiz: Pt rb;
var Enc o ntrado: boolean ;
var N: Ptrb; var Pos : Posicio n );
procedure Inserta (Cl: Tipoc l ave; var Raiz : Ptrb);
procedure Empujar (C l : Tipoclave; R: Ptrb;
var EmpujaAr ri ba : boolean ;
var Mdn a : Tipoclave; var Xr: Ptrb);
procedure Mete rHoja(X : Tip oclave ; Xder, P: Ptrb; K: Posicion);
procedure DividirNodo(X : Tipoc lave; Xder. P: Ptrb;
K : Posicion; var Mda: Tipoc lave ;
var Mder: Pt rb) ;
procedure Mos trarB (R : Pt rb); {Es el recorr i do en i norden}
function Arbolvacio(R: Ptrb) : bool ean;

{Operacio nes para el proce so de borrado de una clave}


procedure E l iminar (Cl : Tipoclave ; var Raiz: Ptrb);
procedure Elim inar Registro (Cl : Tipoc l ave; R : Ptrb;
var Enc o ntrado: boo l ean);
procedure Restablecer(P: Ptrb; K: Posicion);
procedure Quit ar(P : Ptrb; K: Posi cion);
procedure Su cesor(P : Ptrb; K: Pos ici on) ;
procedure Moverlzqda(P: Ptrb; K: Posicion ) ;
procedure MoverDrcha(P: Ptr b; K: Posicion);
procedure Co mb ina(P : Ptrb; K : Pos i cion) ;
implementation

begin
end.

Esta unidad se emplea a ttulo de ejemplo para crear un rbol B de orden 5, conside-
rando el tipo de las claves entero.
Las claves son generadas aleatoriamente para evitar problemas, antes de insertar la
,,

clave se examina si ya est en el rbol. Tambin se realizan operaciones de eliminacin


de claves en el rbol creado.

,
CODIFICACION
program Procesa_arbolB(input,output);
uses crt , Arbo l b;
const
Mx=9999;
Arboles B 399

var
Rb: P trb ;
C l: intege r;
Op,N : integer;
procedure Menu( var Opc : int eg er);
begin
clrscr;
gotoxy(10,2 ) ; wr it e1n(' 1 . I n se rtar n claves') ;
goto x y(10 , 4); wr i teln(' 2 . Ins er tar 1 cla ve');
gotoxy(10,6); write l n ( ' 3 . E li minar c la ve') ;
gotoxy(10 , 8) ; write1n( '4. Listar clav e s') ;
g oto xy (10 , 10) ;wri t el n( '5. Fin p roc eso ' );
repeat
go t oxy (10,13) ; wr i teln (' Op ci n ?: ');
readln(Op c)
un ti 1 Op c in [1. . 5 1 ;
end;
procedure Annade_C l aves (var Rb:P t rb;N:integer);
var
K:O .. 1 00 ;
X:int ege r;
P:Posi c i on ;
Es ta : boo1ean;
Nd:Pt rb ;
begin
K: = O;
write ( ' C la ves in s ert ad as: ' ) ;
repeat
X: = r an dom (Mx) ;
Buscar(X,Rb,Esta,Nd,P) ;
if not Es ta then
begin
I n serta(X , Rb) ;
w rit e( X ,' '};
K :=K +l ;
end
unti1 K=N;
writel n;
end;
begin {B loque pri n cipal}
Rb : =nil;
Ra ndomize;
repeat
Menu (Op) ;
case Op of
1 : begin
cl r scr; go to xy (4,5) ;
write ( ' Cant as c l ave s: ? : ' ) ; read ln (N) ;
Annade _c lav es ( Rb,N)
end;
2 : An na de_c l aves(Rb, 1 ) ;
3 : begin
write('Clave que se desea e li mi na r:?');readln( C l);
E l iminar( Cl , Rb)
end;
400 Estructura de datos

4: Mo s trarB(Rb)
end;
repeat until readkey i n [ #0 .. #2551
until Op=5
end.

, ,
12.9. REALlZACION DE UN ARBOL B EN MEMORIA EXTERNA

En los apartados anteriores se ha definido la estructura rbol B, su representacin en


memoria y las operaciones para insertar claves y eliminar. Ahora bien, esta estructura
para que realmente sea til debe de estar almacenada en un archivo externo y ser mane-
jada accediendo al archivo.
Los procesos de bsqueda, insercin, eliminacin y recorrido van a ser los mismos,
salvo un cambio muy importante en la representacin y es que ya no se utilizan variables
dinmicas, los enlaces no sern punteros sino nmero de registros en los que se almace-
na el nodo o pgina descendiente. .
Para crear un nuevo nodo (pgina) hay que buscar un hueco en el archivo, repre-
sentado por un nmero de registro, posicionar el pointer del archivo en ese hueco y
escribir el nodo. De igual forma, cada vez que se modifica un nodo por un cambio en las
claves hay que escribir el registro en la posicin del archivo correspondiente.
En esta realizacin de rboles B las ramas van a ser nmero de registro. La funcin
Huecos concede el nmero de registro donde almacenar un nodo. Para ello se sigue la
siguiente estrategia:

De la pila de registros liberados, se saca el elemento cima.


Si la pila est vaca, se obtiene el siguiente registro libre de la memoria externa.

El proceso de liberacin de nodos supone almacenar en la pila de registros libres el


nodo que se libera. Los procedimientos de insercin y eliminacin son los mismos que
en la realizacin con estructuras dinmicas, salvo las modificaciones que supone no uti-
lizar punteros sino nmeros de registro. Son utilizados dos archivos, el que almacena el
rbol propiamente dicho (llamado F i c hab) y otro para almacenar el nmero de regis-
tro del nodo raz y la pila de registros libres (llamado Fh u e c o s). Es inmediato pensar
que hay que grabar el nmero de registro de la raz para que a partir de l pueda acceder-
se a toda la estructura.
Los tipos de datos para realizar a un rbol B de orden 5 en memoria externa:
,,

const
Orden= 5;
Max=Orden-l; {Nme r o m xim o de c laves en un nodo}
Min=(Orden-l) div 2 ; {Nmero mnimo de claves en un nodo d i stinto de l a
raz}
type
Tipoclave=
I

Apuntador= in teg e r;
rboles 8 401

po sicio n = O .. Max;
Pagina= record
Cuenta : O .. Max;
Claves : array [ 1 .. Max] of Tipoclave ;
Ramas: array [Posi c i on] of Apuntador
end;
Fi c hero = file of Pagina;
Flibre = file of integer;

Para adaptarse a la nueva manera de direccionar los nodos y para grabar o cargar la
estructura son necesarias estas nuevas rutinas.

Funcin Hueco
,
Devuelve la posicin del siguiente registro libre. Este puede venir de la pila de registros
liberados, o bien el registro siguiente al ltimo concedido.

function Hueco (Pila : Tpila; var F: Archivo) :integer;


begin
if not Pvacia (Pila ) then
Hueco:= Psa c ar(Pi l a)
else
Hueco:= fil esize(F)
end;

Procedimiento Inicial
Ser el primer procedimiento en ser llamado. Asigna archivos y vuelca en la pila los
nmero de registros liberados. Devuelve la raz del rbol B.

procedure Inicializa (var F : Archivo; var Fh: F l i bre;


var R:in t eger ; var Pila: Tpi l a);
var
I : Apuntador;
begin

Pc rear (Pila) ;
assign(F, 'datosab.da t ');
assign(Fh , 'hue cos . dat ' );
{$i - }
reset (Fh) ;
if ioresult < > O then

begin
rewrite(Fh) ;
rewrite(F) ;
R:= Yacio { c onstante predefi n ida, parametr i za rbol vaco}
end
else begin
rese t (F) ;
if eof (Fh) then
R : = Yac io
402 Estructura de datos

else

read (Fh , R) {El pr ime r r egist ro es l a r a l Z del rb o l Bl
end;
{$ i + l
while not eo f (F h ) do
begin
r ea d (F h , 1 ) ;
Pme te r (Pila, I )
end
end;

Procedimiento de Finalizar
Este procedimiento ser el ltimo en llamarse. En l se escribe como primer registro el
nmero de registro de la raz del rbol. A continuacin, los registros liberados que estn

en la pila.
procedure f in (var Fh: Fl ibr e ; var F: Arch iv o ;
R : Apunt ad or; var Pi l a : Tpi la );
var
H: Apuntado r ;
begin
re set(Fh );
writ e( Fh , R) ;
while not Pvaci a(P i l a) do
begin
wr i t e (F h , Ci ma (Pi la) ;
Pb o rra r (Pi la )
end;
close(Fh) ;
cl ose( F )
end;

Procedimiento de liberar un nodo


Simplemente mete en la pila de registros libres el nmero de registro donde est el nodo
a ser liberado.

procedure L ibe r ar (P: Apu nt ador ; var Pi l a : Tpila) ;
begin
Pmeter( P il a , P) ;
end;

Operacin de recorrido del rbol B


Recorre el rbol B que se encuentra en el disco. Pasa por cada una de las claves y son
escritas en pantalla.
procedure recorrer ( R : Ap un tad or ; var F : Archivo) ;
var
1 : Po s i c i on ;
Pg : Pagi n a;
rboles B 403

begin
if R <> v a cio then
begin
seek( F ,R);
read(F , Pg) ;
recorrer(Pg . Ra mas[O ] ,F ) ;
for 1 := 1 to Pg. Cuenta do
begin
write(Pg . Cl aves [ 1 ], ' ');
recor rer (Pg . Ramas[I] ,F )
end
end
end;

Unidad con las operaciones de rbol B en archivo

A continuacin se muestra la unidad para realizar el tipo abstracto de datos rbol B en archivo.
A las rutinas anteriores , se aaden las ya escritas para el proceso de insercin y el
proceso de borrado de claves. Presentan pequeas diferencias debido fundamentalmente
a la no utilizacin de punteros para acceder a un nodo o pgina.
Ahora este acceso se realiza con:

see k ( F, R) ;
read (F , Pg) ;

Siendo F el archivo , R el nmero de registro y Pg el nodo.

Unidad para realizar el TAO rbol B de orden 5 en un archivo


unit ArbolB;
interface
uses Pi l aP u n;
const
Vaci o = 29999 ; {Mar ca que ind i ca registro vac o}
I Or den = 5 ;
i Max= Orde n- 1 ; {Nmero m x imo de claves en un n odo}
Min = (Ord en -l) div 2 ; {"N me r o m nim o de cl aves e n u n nod o disti nto de
la raz}
I
I type
Tipoclave = i ntege r; {P or comodidad en la s pruebas adop ta mos este t i po
de c la ve}
posicion= o .. Max;
Pagina = record
Cu e n ta : O .. Max;
Cl aves : array [1 .. Ma x ] of T ipoclav e ;
Ramas : array [p os icion] of Apun t ador
end;
Archivo = file of Pagina;
Flibre= file of Apun t ador ;
var
Pila: Tpi l a;
function Hue co (var Pla :Tpi l a; var F : Arch iv o) : Apuntador;
---- - -"

404 Estructura de datos

procedure Inicializa (var F : Archivo; var Fh : Flibre ; .

var R : integer); .

;
procedure F in (var Fh : Fl i br e;var F: Archivo ; R: Apunt a dor) ;
procedure Li be r a r (P:Ap un t ad o r ; var Pila : Tpil a );
'
procedure Recorre r (R: Apu n tador; var F: a r chivo) ; -
.
.

procedure Buscarnodo (Clave : Tip o cl a ve ; P : Pagina ;


var En con tr ado : b oole an; var K: Po sic i o n ) ;
procedure Bu scar (C l ave : T ipoclave ; R: Apu ntador ;
var Encontrado : boo l ean ; var Pos : Posicion ;
var P: Apu nt ador ; var F: Ar chi vo) ;
function Arbolvac i o(R : Apuntado r ) : boolean ;
{Oper a ciones especf i cas para el proceso de in sercin}
procedure In se r t a (Cl :Ti poc lave ; var R : Ap unt ad or ;
var F: Archivo) ;
procedure Empu j a r( Cl : T i poc l ave ; R : Apu nt ador ;
var Empu jaAr ri ba : bo o l e an;
var Mdna : Ti p oc l ave ; var Xr : Apuntado r;
var F: Arch i vo) ;
procedure Di vidi rN o d o( X: T i po cl ave ; Xder : Apun tad or ;
var P: Pag i n a; K: Pos i ci o n ;
, var Mda : Tipoc l ave ;var Xd : Ap u n t ado r;
var F: Archi v o) ; o
"
procedure Me te rHoj a(X : T ipoc la ve ; Xd er : Apu n tad o r;
var P : Pagina ; K: Posicion);
{Oper a c i ones par a el proceso de bo r rado de una c l ave}
procedure Eli minar (Cl : T i po cl ave ; var Raiz: Ap u n ta dor;
var F: Ar c h ivo) ;
j
"
procedure Eli min a Reg i s t ro (C l: T i poclave ;var P : Apuntador;
, o

var Encon tr ado: bo ole a n;var F: Ar ch ivo);

I
t
procedure Restablecer (P : Apuntador ; K:Posic i on ;var F : Arc hi vo) ;
procedure Qu it ar ( P : Ap un tador ; K : Posic i o n;" var F:Archivo) ;
I procedure Su ceso r (P : Apun tado r; K: Po si cio n; var F: Ar ch ivo) ;
:
I procedure Moverder echa( P:Apu n tador ; K: Pos i c i on ;var F : Archivo);
!-
o

!I procedure Mover i zq u ie r da(P : Apun tador ; K: Posic i o n;var F: Arc hi vo) ;


"
"
procedure Comb i n a (P : Ap un tado r; K: Po sicio n; var F:A r chi vo) ;
implementation

function Ar bo lvac i o(R : Ap u nt a dor) :b oo l ea n;


begin
Ar b olvacio := R=vac i o
end;

function Hu e co (var P l a : Tpi l a ;var F: Arc hi vo) : Apu n tado r ;


var
H:Apun ta do r ;
begin
if not Pvac i a( Pl a) then
Ps acar (H, Pl a)
else
H: = f ilesize( F ) ;
Hu ec o: = H
end;

procedure I nicializa (var F: Archivo ; var Fh : F l ibre ;


var R :i nteg er ) ;
var

406 Estructura de datos


seek(F, R);
read (F, Pg);
recorrer(Pg.Ra mas[O ) ,F);
for I:=1 to Pg.Cuenta do
begin
write(Pg.C1aves [I),' ');
recorrer(Pg.Ramas[I), F)
end
end
end;

procedure buscarnodo (C l ave:Tipoc l ave; P : Pag i na;


var Enc o ntrado: boo l ean; var K: Posic i on) ;
begin
if Clave < P.Claves[l] then

begin
Encontrado:=false;
K:=O
end
elBe begin
K:= P.Cu enta ;
while (Clave < P.Claves[k)) and (k >l) do
k:=k-1;
Encontrado: = (Clave = P.C l aves[k ) )
end
end;

, procedure buscar (Clave: Tipoc l ave ; R: Apuntador;


,
,
,
,
var Encontrado :boolean;
var Pos: Posicion ; var P: Apuntador;
var F: Archivo) ;
var
Pg :Pagina;
begin
Encontrado:=false;
,
while not Encontrado and (R <> vaClO ) do
begin
seek(F,R) ;
read(F,Pg) ;
buscarnodo(Clave, Pg, En c ontrado , Pos) ;
if Encontrado then
P: = R
elBe
R:= Pg.Ramas[Pos)
end
end;

procedure Inserta (Cl:Tipoclave; var R : Apuntado r ;var F : Archivo);


var
P: Pagina;
,

Sube: boolean;
Mdna: Tipoclave;

N, Xr: Apuntador;
begin
Empujar(Cl,R,Sube,Mdna,Xr,F) ;

, if Sube then

,,
- - - _ . - _._-

rboles B 407

begin
P.Cuenta:=l;
P . C 1 ave s [1] : = Mdna;
P.Ramas [0] := R;
P . Ramas [1] : = Xr;
N:= Hueco (Pila, F);
seek(F , N);
wr i t e (F, P);
R:= N
end
end;

procedure Empujar ( Cl: Tip o clave ; R: Apuntador;


var Empu j aArri b a : boolean ;
var Mdna: Tip o clave; var Xr:Apuntador;
var F: Archivo);
var
K : Posicion;
Pg: Pagina ;
Esta : boolean;
begin
if R= vacio tben
begin
Empu j aArriba:=true;
Mdna: =C l;
Xr:=vacio

end
else begin
s eek(F ,R) ;
read(F ,Pg) ;
buscarnodo(Cl,Pg,Esta,K) ;
if Esta tben
begin
write l n ( ' Clave ya e xi s te. Revisar c d i go');
ha lt (1)
end
else begin
Empujar ( C l ,pg.ramas [ K] ,EmpujaArriba , Md n a,Xr,F);
if EmpujaArriba then .
if Pg .C uenta < Max then
begin
EmpujaArriba:=false;

Meterhoja(Mdna,Xr,Pg,K) ;
seek(F,R) ;
write(F,Pg)
end
else begin
Empu j aArriba : =true;Di vi dirNodo(Mdna,Xr , Pg,K,Mdna,Xr,F) ;
seek( F ,R);
wri t e(F,Pg)
end
end
end
end;
408 Estructura de datos

procedure Div i di r Nodo(X : T ip oc l ave ; Xd er : Apuntador ;


var P : Pag i na ; K : Pos i cion;
var Md a : T i pocl a ve ;var Xd : Ap u n tador ;
var F : Arch i vo) ;
var
Mde : Pagina;
j , i ,pos:integ e r;
begin
if K< = Min then
pos := Mi n
else
pos := Mi n+l ;
xd : = Hueco( P ila ,F ) ;
for i:= pos+1 to Ma x do
begin
Mde . C la ves [ i - pos J : =P . Claves [ i J;
Mde . Ra ma s [i- pos J : = P . Ramas [i J
end
Mde . Cuenta:= Ma x- pos ;
P . Cu e nta:=pos;
if K< = Min then
Met e r hoja ( X,X der , P , K)
el se
Mete rho ja(X , Xd e r , Mde , K- pos) ;
Mda : = P . C l aves [P . CuentaJ ;
Mde . Ramas [ Ol:= P.R a mas [ P . Cue n t al;
P . Cue n ta := P . Cue n ta - 1 ;
,,,

see k ( F ,X d ) ;
write(F , Md e) ;
,

end
,I

procedure MeterH oja(X : T i poc l a ve; Xder: Apu n tador ;


var P : Pagina; K : Posic i on) ;
var
i:in tege r;
begin i

for i := P. Cuenta downto K+1 do
begin
P . C 1 a v e s [ i + 1 J : = P . C 1 a ves [ i J ;

P . Ramas[i + 1 J : = P . Ra mas[iJ
end
P . Cl a v es[k+l1 . - X,
P. Ra mas [k+l1 : = Xder ;
P . Cu e nta:= P. Cue n ta + l
end;

procedure Eli mi n ar (C l: T i poc l ave ; var Raiz : Apuntador;


var F : Archivo) ;
var
Aux : Apun t ador ;
--
Enco n tr a do : boole a n; .1
Pg : Pag i n a; 1
1
1


rboles B 409

begin
EliminaRegistro(Cl,Raiz,Encontrado,F) ;
if not Encontrado then
writeln( 'No Encontrada la clave a eliminar')
else begin
seek(F,Raiz) ;
read(F,Pg) ;
if Pg.Cuenta = O then
begin
Aux:= Raiz;
Raiz:= Pg.Ramas[O];
Liberar(Aux,Pila)
end
end
end;

procedure EliminaRegistro (Cl:Tipoclave;var P:Apuntador;


var Encontrado:boolean;var F: Archivo);
var
K: Posicion;
Aux,Pg: Pagina;
begin
if P= vacio then
Encontrado:=false
else begin
seek(F,P);
read (F, Pg) ;
with Pg do
begin
buscarnodo(Cl,Pg,Encontrado,K) ;
if not Encontrado then
EliminaRegistro (Cl,Ramas[K] ,Encontrado,F)
else if Ramas[O]= vacio then
Quitar(P,K,F)
el se begin
Sucesor(P,K,F) ;
seek(F,P); {De nuevo se lee porque ha cambiado}
read (F, Pg) ;
EliminaRegistro(claves[K] ,Ramas[K], Encontrado,F)
end;

if Ramas[K]< > vacio then


begin
seek(F,Ramas[K]) ;
read (F, Pg) ;
if Cuenta< Min then
Restablecer(P,K,F)
end
end
end
end;

procedure Restablecer (P: Apuntador; K: Posicion; var F:Archivo);


var
J: Apuntador;
Aux: Pagina;
410 Estructura de datos

begin
seek(F,P);
read (F, Aux) ;
if K > o then
begin
J:=Aux.Ramas[K-l] ;
seek(F,J) ;
read ( F , Aux) ;
if Aux.Cuenta > Min then
Moverderecha(P,K,F)
else
Combina(P,K,F)
end
else begin
seek(F,P);
read (F , Aux) ;

j:= Aux.Ramas[l]; ,

seek(F,J);
read ( F , Aux) ;
if Aux.Cuenta > Min then
Moverizquierda(P,l,F)
else
Combina(P,l,F)
end
end;

procedure Quitar(P:Apuntador; K: Posicion; var F: Archivo);


var
i: Apuntador;
Pg: Pagina;
begin
seek(F,P);
read(F,Pg) ;
for i:=k+l to Pg.Cuenta do
begin
Pg.Claves [i-l]:= Pg.Claves [i];
Pg.Ramas[i-l]:= Pg.Ramas[i]
end;
Pg.Cuenta:= Pg.Cuenta-l;
seek(F,P);
write(F,Pg)
end;

procedure Sucesor(P:Apuntador; K: Posicion; var F: Archivo);


var
D: Tipoclave;
Q: Apuntador;
Aux,Pg:Pagina;
begin
seek(F,P);
read(F,Pg) ;
Q:= Pg.Ramas[k];
seek (F, Q) ;
read (F , Aux) ;
rboles 8 411

while Aux.Ramas[O] <> vaci o do


begin
see k(F,Aux.Ramas[O ]) ;
read(F,Aux)
end;
D:=Aux.Claves[l] ;
Pg.Claves[K] .' - D',
seek(F,P);
write(F,Pg)
end;

procedure Moverdere cha (P:Apuntador ; K: posicion; var F:Archivo);


var
j:Apuntador;
Aux,Auxiz,Auxdr:Pagina;
begin
seek(F,P);
read(F,Aux) ;
seek(F,Aux.Ramas[k-1]) ;
read(F,Auxiz) ;
seek(F,Aux.Ramas[k]) ;
read(F,Auxdr) ;
for J: =Auxdr.Cuenta downto 1 do
begin
Auxdr. Claves [j + 1] : =Auxdr. Claves [j] ;
Auxdr.Ramas[j+l] :=Auxdr.Ramas[j]
end;
Auxd r.Ramas[l] :=Auxdr.Ramas [O ] ;
Auxdr.Cuenta:=Auxdr.Cuenta+1;
Auxdr.Claves[l] :=Aux.Claves[K];
Aux.Cl ave s[k] : =Auxiz .Clave s[Auxiz .Cuenta];
Auxdr.Ramas[O] :=Auxiz.Ramas[Auxiz.Cuenta];
Auxiz.Cuenta:=Auxiz.Cuenta-l;
seek(F,P);
write (F , Aux) ;
seek(F,Aux.Ramas[k-1]) ;
wri te( F,Auxiz) ;
seek(F,Aux.Ramas[k]) ;
write(F,Auxdr)

end;

procedure Moverizquierda(P:Apuntador; K: Posicion; var F: Archivo);


var
Aux,Auxiz,Auxdr: Pagina;
J : Posicion;
begin
seek(F,P);
read(F,Aux) ;
seek(F,Aux.Ramas[K - 1]) ;
read(F,Auxiz) ;
seek(F,Aux.Ramas[K]) ;

read(F,Auxdr) ;
i Auxiz.Cuenta:=Auxiz.Cuenta+1;
Auxiz.C l aves[Auxiz.Cuenta] :=Aux.Claves[K];
412 Estructura de datos

Auxiz.Ramas[Auxiz.Cuenta) : =Auxdr.Ramas[O);
Auxdr.Ramas[O) : =Auxdr.Ra ma s [l);
Aux.Claves[K):= Auxdr.C l ave s [l);
Auxdr.Cuenta:=Auxdr. Cuenta-l;
for j:=l to Auxdr. Cuenta do
begin
Auxdr. Claves [j) : =Auxdr. Claves [j +1) ;
Auxdr.Ramas[j) :=Auxdr.Ramas[j+l]
end;
seek ( F,P);
wr i te ( F , Aux) ;
seek(F,Aux.Ramas[k-l ] ) ;
wr i te(F,Auxiz) ;
seek(F,Aux.Ramas[k) ;
write(F,Auxdr )
end;

procedure Combina(P:Apuntador; K: Posicion; var F:Archivo);


var
Dc ho, Izqdo:Apuntado r;
j: Posicion;
Aux,Auxiz,Auxd o :Pagina;
begin
seek(F,P) ;
read(F,Aux) ;
Dcho:=Aux.Ramas[k) ;
Izqdo:=Aux.Ramas[k-l) ;
seek ( F,Dcho) ;
read(F,Auxdo) ;
seek(F,Izqdo) ;
read(F,Auxiz) ;
Auxiz.Cuenta:=Auxiz.Cuenta+l;
Auxiz.Claves[Auxiz.Cuenta] :=Aux.Claves[k];
Auxiz.Ramas[Auxiz. Cuenta] :=Auxdo.Ramas[O];
for j:=l to Auxd o .Cuenta do
begin
Auxiz.Cuenta:= Auxiz.Cuenta+l;

Auxiz.Claves[Auxiz.Cuenta) :=Auxdo.Claves[j ) ; ,
',
Auxiz.Ramas[Auxiz. Cuenta) :=Auxdo.Ramas[j)
end; ;
.
for j:= K to Aux.Cuenta - l do

,.

begin
;

Aux. Claves [j] : =Aux. Claves [j +1] ; ,



Aux.Ramas[j] :=Aux.Ramas[j+l]
end; ,
Aux.Cuenta:=Aux.Cuenta-l ; !

seek(F,P); ~
)

write (F, Aux) ; ,


j

seek (F, 1 zqdo) ;


,.1
i
write(F,Auxiz) ; 1
,

liberar(Dcho,Pila)
end;
begin
end.



rboles B 413

Programa de gestin de un rbol B


en memoria externa

program Arbol_b;
uses crt, ArbolB,Pilapun;
const
B= 999;
var
F:Ar ch ivo;
Fh:Flibre;
Apun,R,D:Apuntador;
Re, L, Cl: integer;
Pos:Pos i c i o n;
En co n t rado:boolean;
Res:char;

begin
R:=vacio;
c lrscr;
Ini c ializa (F, Fh, R) ;
randomize;
writeln ('Elementos presentes');
Re co rrer(R,F) ;
repeat
writel n ;

writeln('l. Aadir claves');


write ln(' 2 . Eliminar Clave ');
writeln('3. SALIR');
repeat
Readln(Re)

until Re ln [1 .. 3];
if Re= 1 then
begin
for L:=l to 2 do
begin
Cl: = rand om (B) ;
Buscar(Cl,R,Enc o ntrado,Po s,D,F) ;
if not En co ntrado then
Inserta( C l,R,F)
end;
writeln;
Recorrer(R,F) ;
end;
if Re= 2 then
begin
writeln('Clave a e liminar');
readln(Cl) ;
Eliminar(Cl,R,F) ;

Reco rrer(R,F )

end
,
until (Re = 3);
,
Fin(Fh,F,R);

repeat until keypressed


end.
414 Estructura de datos

RESUMEN
Un rbol-B es una estructura de datos que se puede utilizar para implementar una tabla que reside
en memoria externa, tal como un disco. Los rboles B se denominan tambin rboles 2-3 y son
una clase de rboles no binarios sino ternarios, que obligan a que todas las hojas se encuentren al
mismo nivel.
Un rbol 2-3 permite que el nmero de hijos de un nodo interno varen entre dos y tres. Un
rbol2-3 es un rbol en el que cada nodo interno (no hoja) tiene dos o tres hijos y todas las hojas
estn al mismo nivel. Una definicin recursiva de un rbol 2-3 es: T es un rbol 2-3 de altura h si:
l. T est vaco (un rbol 2-3 de altura O).
o alternativamente:
2. T es de la forma
r

donde r es un nodo y TI Y T o son los dos rboles 2-3, cada uno de altura h-l. En este
caso, TI se llama subrbol izquierdo y Tose llama subrbol derecho.
O bien,

3. T es de la forma

donde r es un nodo y T" Te, T D son rboles 2-3, cada uno de altura h-l. En este caso, TI
se llama subrbol izquierdo, Te se llama subrbol central y Tose llama subrbol derecho.

Un rbol 2-3 no es necesariamente binario, pero est siempre equilibrado:

50 90

120 150

30 40 100 100 120 150 175

En un rbol 2-3, los nodos internos pueden tener dos o tres hijos, permitiendo que el nmero
de hijos vare; los algoritmos de insercin y supresin pueden mantener fcilmente el equilibrio
del rbol.
rboles B 415

EJERCICIOS
12.1. Dada la secuencia de claves enteras: 190,57,89,90,121,170,35,48,91,22,126,132
Y 80, dibuja el rbol B de orden 5 cuya raz es R, que se corresponde con dichas claves.
12.2. En el rbol R del problema 1, elimina la clave 91 y dibuja el rbol resultante. Vuelve a
eliminar, ahora, la clave 48. Dibuja el rbol resultante, ha habido reduccin en el nme-
ro de nodos?
12.3. Modifique la rutina de insercin de un rbol B de orden m para que si se intenta aadir
una clave a un nodo que ya est lleno, se efecte una bsqueda de un hermano no lleno
antes de partir el nodo.
12.4. En un rbol B de orden 5 se insertan las claves 1, 2, 3, ... n. Qu claves originan la
divisin de un nodo? Qu claves hacen que la altura del rbol crezca?
12.5. En el rbol B de orden 5 del ejercicio 12.4, las claves se eliminan en el mismo orden de
creacin. Qu claves hacen que los nodos se queden con un nmero de claves menor
que el mnimo y den lugar a la unin de dos nodos? Qu claves hacen que la altura del
rbol disminuya?
12.6. Prevemos tener un archivo de un milln de registros, cada registro ocupar 50 bytes de
memoria. Los bloques de memoria son de 1.000 bytes de longitud y adems hay un pun-
tero por cada bloque que ocupa 4 bytes de memoria. Disear una organizacin con rbo-
les B para este archivo.
12.7. El procedimiento de bsqueda de una clave se ha realizado con una llamada recursiva al
final del procedimiento. Volver a escribir el procedimiento eliminando la llamada recursiva.
12.8. Un rbol B* es un rbol B en el que cada nodo est, al menos, lleno en las dos terceras
partes (en vez de la mitad), menos quizs el nodo raz. La insercin de nuevas claves en
el rbol B* supone que si el nodo que le corresponde est lleno mueve las claves a los
nodos hermanos (de manera similar a como se mueven en la eliminacin cuando hay que
restaurar el nmero de claves de un nodo). Con 10 cual se pospone la divisin del nodo
hasta que los dos nodos hermanos estn completamente llenos. Entonces, stos pueden
dividirse en tres nodos, cada uno de los cuales estar lleno en sus dos terceras partes.
Especifique los cambios que necesita el algoritmo de insercin de una clave en un rbol
B para aplicarlo a un rbol B*.
12.9. Dado un rbol B* segn est definido en 12.8, especificar los cambios necesarios que
necesita el algoritmo de eliminacin de una clave en un rbol B para aplicarlo a un
rbol B*.
12.10. Dada la secuencia de claves enteras del ejercicio 12.1: 190,57,89,90,121,170,35,48,
91, 22 , 126, 132 Y 80, dibuja el rbol B* de orden 5 cuya raz es R, que se corresponde
con dichas claves.
12.11. Con las claves del rbol B de orden 5 del ejercicio 12.4 dibuja un rbol B* de orden 5.
12.12. En el rbol B * de orden 5 del ejercicio 12.11, las claves se eliminan en el mismo orden
de creacin: 1, 2, 3, 4 ... n. Qu claves hacen que los nodos se queden con un nmero
de claves menor que el mnimo y den lugar a la unin de dos nodos? Qu claves hacen

que la altura del rbol disminuya?


!
,f PROBLEMAS I
12.1. Dada la secuencia de claves enteras: 190, 57, 89, 90, 121, 170, 35, 48, 91, 22, 126, 132 Y
80, dibuja el rbol B de orden 5 cuya raz es R, que se corresponde con dichas claves. ,
,

416 Estructura de datos

12.2. En el rbol R del problema 12.1 elimina la clave 01 y dibuja el rbol resultante. Vuelve a
eliminar ahora la clave 48. Dibuja el rbol resultante, ha habido reduccin en el nmero
de nodos?
12.3. Cada uno de los centros de enseanza del Estado consta de una biblioteca escolar. Cada
centro de enseanza est asociado con nmero de orden (valor entero), los centros de cada
provincia tienen nmeros consecutivos y en el rango de las unidades de 1.000. (As, a
Madrid le corresponde del 1 al 1.000; a Toledo, del 1.00 l al 2.000 ... )
Escribir un programa que permita gestionar la infolluacin indicada, formando una estruc-
tura en memoria de rbol B con un mximo de 6 claves por pgina. La clave de bsqueda
del rbol B es el nmero de orden del centro> adems tiene asociado el nombre del centro.
El programa debe permitir aadir centros, eliminar, buscar la existencia de un centro por la
clave y listar los centros existentes.
12.4. En el problema 12.3 cuando se termina la ejecucin se pierde toda la informacin. Pues
bien, modificar el programa 1 para que al terminar la informacin se grabe la estructura en
un archivo de nombre centros.txt.
Escribir un programa que pellllita leer el archivo centros.txt para generar a partir de l la
estructura de rbol B. La estructura puede experimentar modificaciones nuevos centros,
eliminacin de alguno existente , por lo que al terminar la ejecucin debe de escribirse
de nuevo el rbol en el archivo.
12.5. Se quiere dar ms contenido a la informacin tratada en el problema 12.3. Ya se ha especi-
ficado que la clave de bsqueda del rbol 8 es el nmero de orden del centro de ensean-
za. Adems, cada clave tiene que llevar asociada la raz de un rbol binario de bsqueda
que representa a los ttulos de la biblioteca del centro. El rbol de bsqueda biblioteca
tiene como campo clave el ttulo del libro (tiene ms campos como autor. .. ). Escribir un
programa que partiendo de la informacin guardada en el archivo centros.txt cree un nue-
vo rbol 8 con los centros y el rbol binario de ttulos de la biblioteca de cada centro.
12.6. A la estructura ya creada del problema 12.3, aadir las operaciones que responden a estos
requerimientos:
Dada una provincia cuyo rango de centros es conocido, por ejemplo de 3.001 a 3.780,
eliminar en todos sus centros escolares los libros que estn repetidos en cada centro, y
que informe del total de libros liberados.
Dado un centro n, en su biblioteca se desea que de ciertos libros haya m ejemplares
(por ejemplo, 5.)

,
CAPITULO

.,
resentaclOn

O eraCIOneS
......., .1" , . , '
.... ,'
,' ,'. ' ," . " . ."
'.",~'I:,."
, .'" "', .
',. . , "

CONTE

13.1. Grafos y aplicaciones.


13.2. Conceptos y definiciones.
13.3. Representacin de los grafos.
13.4. TAO grafo.
13.5. Recorrido de un grafo.
13.6. Componentes conexas de un grafo.
13.7. Componentes fuertemente conexas de un grafo.
13.8. Matriz de caminos.
13.9. Puntos de articulacin de un grafo.
RESUMEN.
EJERCICIOS.
PROBLEMAS.

Este captulo introduce al lector a conceptos matemticos importantes


denominados grafos que tienen aplicaciones en campos tan diversos
como sociologa, qumica, geografa, ingeniera elctrica e indus-
trial, etc. Los grafos se estudian como estructuras de datos o tipos abs-
tractos de datos. Este captulo estudia los algoritmos ms importantes
para procesar grafos. Tambin representa operaciones importantes y
algoritmos de grafos que son significativos en informtica.

13.1. GRAFOS Y APLICACIONES

Con los rboles binarios se han representado relaciones entre objetos en las que existe
una jerarqua. Con frecuencia, es necesario representar relaciones arbitrarias entre obje-

417
418 Estructura de datos

tos de datos. Los grafos se clasifican en dirigidos y no dirigidos y son modelos naturales
de tales relaciones. As, los grafos se usan para representar redes de alcantarillado, redes
de comunicaciones, circuitos elctricos, etc. Una vez modelado el problema mediante
un grafo se pueden hacer estudios sobre diversas propiedades. Para ello se utilizan algo-
ritmos concretos que resuelvan ciertos problemas.
La teora de grafos ha sido aplicada en el estudio de problemas que surgen en reas
diversas de las ciencias, como la qumica, la ingeniera elctrica o la investigacin ope-
rativa. El primer paso siempre ser representar el problema como un grafo. En esta re-
presentacin cada elemento, cada objeto del problema, forma un nodo. La relacin, co-
municacin o conexin entre los nodos da lugar a una arista, que puede ser dirigida o
bidireccional (no dirigida). En la Figura 13.1 aparece una red de comunicaciones.

Impresora

PC1

Servidor

PC2

Figura 13.1. Un grafo como red de comunicaciones.

13.2. CONCEPTOS Y DEFINICIONES

Un grafo consiste en un conjunto de vrtices o nodos V y un conjunto de arcos A. Se


representa con el par G = (V, A).

EJEMPLO 13.1

El conjunto de vrtices V = {l, 4,5,7, 9} Y el conjunto de arcos A = {(1,4), (5,1),


(7,9), (7,5), (4,9), (4,1), (1,5), (9,7), (5,7), (9,4)} forman el grafo no dirigido G = {V, A} .

Grafos. Representacin y operaciones 419

EJEMPLO 13.2

El conjunto de vrtices V = {C, D, E, F, H} Y el conjunto de arcos A = {(C,D,),


(D,F), (E,H), (H,E), (E,C)} forman el grafo dirigido G = {V, A}.
Un arco o arista est formado por un par de nodos y se escribe (u, v) siendo u, v el par
de nodos. Un grafo es dirigido (digrafo) si los pares de nodos que forman los arcos son
ordenados, se representan u ~ v. El segundo ejemplo es un grafo dirigido.
Un grafo no dirigido es aquel que los arcos estn formados por pares de nodos no
ordenados, no apuntados, se representa u - v. El grafo del primer ejemplo no es dirigido.
Dado el arco (u, v) es un grafo, se dice que los vrtices u y w son adyacentes. Si el
grafo es dirigido, el vrtice u es adyacente a v, y v es adyacente de u. Un arco tiene, a
veces, asociado un factor de peso, en cuyo caso se dice que es un grafo valorado. Pense-
mos, por ejemplo, en un grafo formado por los pueblos que forman una comarca; un par
de pueblos est unido o no por un camino vecinal y un factor de peso que es la distancia
en kilmetros:
7
Lupiana - - - - - - - - - - - - - Horche

15
5

6
12 Centenera - - - - - - - - - - - Atanzn

Valfermoso

forman un grafo valorado no dirigido.

13.2.1. Grado de entrada, grado de salida


El grado es una cualidad que se refiere a los nodos de un grafo. En un grafo no dirigido
el grado de un nodo v, grado(v), es el nmero de aristas que contiene a v. En un grafo
dirigido se distingue entre grado de entrada y grado de salida; grado de entrada de un
nodo v, gradent(v), es el nmero de arcos que llegan a v, grado de salida de v, gradsal(v),
es el nmero de arcos que salen de v. A veces no se sabe distinguir entre arco y arista, la
diferencia est en qu aristas son arcos hacia los dos sentidos.
Por ejemplo, grado(Lupiana) = 3. Es el grafo dirigido del ejemplo 13.2,
gradent(D) = l Y el gradsal(D) = l.

420 Estructura de datos

13.2.2. Camino

Un camino P en grafo G de longitud n desde un vrtice Va a Vn es la secuencia de n + 1


, .
vertlces:

tal que (v, V+I) E A(arcos) para O $; i $; n. La longitud del camino es el nmero de arcos
que lo forma.

EJE LO 13.3

PI (4, 6, 9, 7) es un camino de longitud 3.


=
En algunos grafos se dan arcos desde un vrtice a s mismo (v, v), el camino v - v se
denomina bucle. No es frecuente encontrarse con grafos que tengan bucles.
Un camino P = (va, VI, V2' ... , v n ) es simple si todos los nodos que forman el camino
son distintos, pudiendo ser iguales Va, Vn (los extremos del camino). En el ejemplo ante-
rior PIes un camino simple.
Un ciclo es un camino simple cerrado, Va = Vn de longitud ~ 2, en definitiva compues-
to al menos por 3 nodos.

EJE LO 13.4

o E

Los vrtices (A, E, B, F, A) en este grafo dirigido forman un ciclo de longitud 4. Un


ciclo de longitud k se denomina k-ciclo. En el ejemplo 13.4 tenemos un 4-ciclo.
Un grafo no dirigido G es conexo si existe un camino entre cualquier par de nodos
que forman el grafo. En el caso de ser un grafo dirigido podemos distinguir entre fuerte-
mente conexo y conexo. Un grafo dirigido es fuertemente conexo si existe un camino
entre cualquier par de nodos que forman el grafo; un grafo dirigido es conexo si existe
una cadena que une cualquier par de vrtices. Un grafo completo es aquel que tiene un
arco para cualquier par de vrtices.
---- - - - - - - - _.- ----

Grafos. Representacin y operaciones 421

EJEMPLO 13.5 i

Grafo conexo Grafo fuertemente conexo

Grafo dirigido conexo

,
13.3. REPRESENTACION DE LOS GRAFOS

Al pensar en los tipos de datos para representar un grafo en memoria, se debe tener en
cuenta que se debe representar un nmero (finito) de vrtices y de arcos que unen dos
vrtices. Se puede elegir una representacin secuencial, mediante arrays; o bien una re-
presentacin dinmica, mediante una estructura multienlazada. La representacin me-
diante arrays se conoce como matriz de adyacencia, la representacin dinmica se deno-
mina lista de adyacencia. La eleccin de una manera u otra depender de las operaciones
que se apliquen sobre los vrtices y arcos.

13.3.1. Matriz de adyacencia


Sea G = (V, A) un grafo de n nodos, suponemos que los nodos V= {VI, V2, ... , v n } estn
ordenados y podemos representarlos por sus ordinales {l, 2, ... , n}. La representacin de
los arcos se hace con una matriz A de n x n elementos aij definida:

1 si hay un arco (v, v)


aIj
o si no hay arco (Vi' V)
la matriz se denomina matriz de adyacencia. En ocasiones la matriz de adyacencia es
una matriz boolean en la que el elemento aij es verdadero (true) si existe arco (Vi' V) Y
falso (fa/se) en caso contrario.
422 Estructura de datos

EJEMPLO 13.6
Sea el grafo dirigido de la figura siguiente

\.

Supongamos que el orden de los vrtices es el siguiente: {D, F, K, L, R}, Y por tanto
la matriz de adyacencia:

O 1 l o o
1 O O O O
A= O O O O O
O 1 l O O
1 O O O O

,,
EJEMPLO 13.7
Ahora el grafo de la figura es no dirigido.

,
,

La matriz de adyacencia:
I,
O 1 O 1 1
,
1 O 1 O O
A= O 1 O l l
1 O 1 O O
1 O 1 O O

Podemos observar qu es una matriz simtrica. En los grafos no dirigidos la matriz


de adyacencia siempre ser simtrica, ya que cada arco no dirigido (Vi' v) se correspon-
de con los arcos dirigidos (Vi' V), (Vj , vJ
Grafos. Representacin y operaciones 423

Los grafos con factor de peso, grafos valorados, pueden representarse de tal forma
que si existe arco, el elemento aj es el factor de peso; la no existencia de arco supone
que aij es O o (esto slo si el factor de peso no puede ser O). A esta matriz se la deno-
00

mina matriz valorada.


EJEMPLO 13.8

El grafo valorado de la figura es un grafo dirigido con factor de peso

4
Alicante Barcelona

1
3
5 3 6 2

Reus

Cartagena Murcia

Si suponemos los vrtices en el orden V = {Alicante, Barcelona, Cartagena, Murcia,


Reus} la matriz de pesos P:

." O 4 5 5 O
O O 3 6 3
,
P= 3 O O O O
O 2 O O O
O 1 O O O

Representacin en Pascal
Al ser una representacin esttica debe de estar previsto el mximo de nodos al que
puede llegar el grafo. Los nodos o vrtices tienen un identificador, los cuales se guardan
en un vector de cadenas. El tipo arco podramos representarlo con un registro con un
campo de tipo boolean, tomar el valor verdadero (true) si (v, v) es una arista, y en caso
necesario, falso (fa/se) otro campo de tipo numrico, que represente el factor de peso. La .
matriz de adyacencia que se representa es de tipo entero, tomando los valores de O al,
segn haya arco o no entre un par de vrtices.

const
Maxvert=20;
type
Indicevert = 1 .. Maxvert;
424 Estructura de datos

Ve r ti ce = s tr in g ;
Ve rti ces =array[In d i c evert , Indi ce vert ) of 0 .. 1
Gr a fo = record
N : In d i c e ve r t ;
V : Ve r tices ;
A : Ma t Ad cia
end;
var
G : Gr afo

En el tipo Grafo est definido el campo N (opcional) para tener contabilizados el


nmero de vrtices, no pudiendo superar el mximo establecido. La matriz G es una
variable de tipo G r a f o. A es la matriz de adyacencia. En el caso de que el grafo sea con
factor de peso y ste sea de tipo numrico, puede asociarse directamente a la matriz, o
bien, definir el tipo arco:

type

Ar co - record
Ad t e : b oo le a n;
Pes o : re a l
end;
Mat Adcia = array [I ndicever t, I n diceve r t ) o f Ar co ;

13.3.2. Listas de adyacencia


La representacin de un grafo con matriz de adyacencia puede resultar poco eficiente en
algunos casos. As, cuando el nmero de vrtices vara a lo largo del proceso, dndose el
caso de que el nmero de ellos sea mayor que el previsto. Tambin cuando el grafo es
disperso, es decir, tiene pocos arcos, y por tanto la matriz de adyacencia tiene muchos
ceros (matriz sparce), resulta poco eficiente la matriz de adyacencia ya que el espacio
que ocupa es el mismo que si el grafo tuviera muchos arcos. Cuando se dan estas inefi-
ciencias se representa un grafo mediante listas enlazadas que se denominan listas de
adyacencia.
Las listas de adyacencia son una estructura multienlazada formada por una lista
directorio cuyos nodos representan los vrtices del grafo y del que adems emergen
una lista enlazada cuyos nodos, a su vez, representan los arcos con vrtice origen el
del nodo de la lista directorio. Con la figura siguiente nos acercamos a esta represen-
tacin de un grafo.
Grafos. Representacin y operaciones 425

La representacin de este grafo dirigido mediante listas de adyacencia:

1 3

5 1 2 4

Representacin en Pascal

Cada nodo de la lista directorio tiene que guardar el vrtice que representa, la direccin
de acceso a la lista de adyacencia (arcos que salen de dicho vrtice) y adems la direc-
cin del nodo siguiente de la lista directorio. Grficamente:

Vrtice Lista Adcia Sgte

Cada nodo de la lista de adyacencia de un vrtice del grafo almacena la direccin del
vrtice (en la lista directorio) con el que forma un arco, en caso de ser un grafo valorado
tambin el factor de peso, y como en todas las listas la direccin del nodo siguiente.
Grficamente:

Dir-Vrtice <Peso> Sgte

Los tipos de datos:

type
PtrDir ~ ANodoDir;
PtrAdy ~ ANodoLy;
NodoDir ~ record
Vert : string; {identificador del vrtice}
Lady: PtrAdy;
Sgte : PtrDir
end;
426 Estructura de datos

Nodo Ly = record
Pt r V: Pt rDi r ;
Pe s o : r e a l; {ca mp o fa c tor d e pe s o , e s o p cio n a l }
Sgte : Pt rAd y
end;
var
G : Ptr Di r;

Con la variable puntero G se accede a la lista directorio, a partir de la cual se puede


acceder a las listas de adyacencia.

13.4. TAO GRAFO

Los grafos, al igual que las pilas, colas ... son tipos abstractos de datos. Ya hemos esta-
blecido los datos y su representacin, ahora definimos las operaciones bsicas sobre
esos datos y su realizacin que ser dependiente de la representacin de los datos.
La operacin unin (X, Y) aade el arco (X, Y) al grafo. En caso de ser un grafo
valorado se define la operacin unin-peso (X, Y, W) que aade el arco (X, Y) cuyo
factor de peso es W.

Operacin borr_arco (X, Y) elimina del grafo el arco (X, Y).


Operacin adyacente (X, Y), funcin lgica que debe devolver true si forman
un arco los vrtices (X, Y).
Operacin nuevo_vrtice (X) aade el vrtice X al grafo G.
Operacin borra_vrtice (X) elimina del grafo G el vrtice X.

Estas operaciones son el ncleo a partir del cual se construye el grafo. En la repre-
sentacin con listas encadenadas se hace uso de las operaciones propias de una lista
enlazada.

13.4.1. Realizacin con matriz de adyacencia

En esta realizacin los vrtices estn representados por el ordinal (1..n) dentro del con-
junto de vrtices.

Operacin unin

procedure u ni on (var G : Gra fo ; Vl, v2 : Ind ic ev e rt);


begin
G .A[ Vl, V2 l : = 1;
end;

Para un grafo valorado

procedure u n ion_ peso (var G: Grafo ; Vl , V2 : I ndi ceve r t , W: r eal) ;


begin
Grafos. Representacin y operaciones 427

G.A[V1, V2] .Adye := true;


G.A[V1,V2] .Peso := W
end;

La operacin que elimina un arco

procedure borr_arco (var G:Grafo; V1, V2: Indicevert)


begin
G.A[V1,V2] := O;
end;

La operacin adyacente (X, Y)

function adyacente (G:Grafo; V1,V2:Indicevert): boolean;


begin
adyacente := G.A[V1,V2] = 1;
end;

La operacin nuevo-vrtice (X)

procedure Nuevo_vertice (var G:Grafo; X:string);


begin
with G do
begin
if N<=Maxvert then
begin
N := N+1;
. - X,
V[N] .-
end
else {Error: no es posible nuevos nodos}
end
end;

Operacin borra_vrtice (X) elimina del grafo G el vrtice x.

La operacin de eliminar un vrtice del grafo no slo supone suprimirlo de la lista de


vrtices, sino que adems se debe ajustar la matriz de adyacencia, ya que el ndice de los
vrtices posteriores al eliminado debe quedar decrementado en l.
procedure borra_vertice(var G:Grafo; X:string);
var
I:Indicevert;
P:integer;
begin
P : = Ordinal (G, X) ;
with G do
begin
if P in [1 .. N] then
begin
{Eliminacin de vrtice X}
for 1 := P to N-1 do
V[I] := V[I+1];
{Ajuste de matriz de adyacencia}
{Desplaza columnas}
428 Estructura de datos

for C := P to N-1 do
for 1 := 1 to N do
A[I,C] := A[I,C+1];
{Desplaza filas}
for 1 := P to N-1 do
for C := 1 to N do
A[I,C] := A[I+1,C]
{Se reduce el nmero de vrtices}
N := N-1
end
el se {Vrtice no existe en el grafo}
end
end;

La operacin Ordinal (es una operacin auxiliar).


function Ordinal(G:Grafo; X:string): integer;
var
1 : 1ndicevert
Rd : integer;
begin
Rd:=-l; 1:=0;
while (I<G.N) and (Rd - -1) do
begin
1 : = 1+1
if G.V[I] - X then
Rd := 1
else
1 : = 1+1
end;
Ordinal := Rd
end;

13.4.2. Realizacin con listas de adyacencia


Las operaciones bsicas con listas se implementan con variables puntero y variables
dinmicas. Algunas operaciones son similares a las realizadas con el TDA lista, a pesar
de lo cual son realizadas. As, la operacin auxiliar para crear un vrtice.
function Crearvt (Vt: string) : PtrDir;
var
V:PtrDir;
begin
new(V) ;
VA.Vert -- Vt;
VA.Lady -- nil; VA.Sgte := nil;
Crearvt - V
-

end;

Operacin unin.

Dado el grafo y dos vrtices que forman un arco se aade el arco en la correspon-
diente lista de adyacencia. La realizacin de unin_peso slo presenta la diferencia de
asignar el factor de peso al crear el nodo de la lista de adyacencia.
Grafos. Representacin y operaciones 429

procedure uni o n (var G :P trDir ; VI, V2 :st r ing);


var
P,Q : PtrDir;
begin
P := Direc cion( G,VI ) ;
Q := Direccion(G,V2);
if (P <> nil) and (Q <>n il ) then
with pA do
if Lady = nil then {l i s t a de ady acencia est vaca}
Lady := CrearLy(Q)
el Be
Ultimo(Lady) A. Sgte : = CrearLy(Q)
end;

Han surgido operaciones auxiliares, como Direccin y Ultimo. La primera


operacin devuelve un puntero al nodo de la lista directorio donde se encuentra un vr-
tice; la segunda operacin devuelve un puntero al ltimo nodo de la lista. Los cdigos de
ambas funciones son:

function Direccion(G: PtrDir; v : string): PtrDir;


var
P,D: PtrDir;
begin
P:= n il; D := G ;
while (P=n il) and (D <> n i l ) do
if DA. Ve rt = V then
P := D
elBe D := DA . Sgte ;
Dire cc ion := P
end;

function Ultimo(L: PtrAdy): PtrAdy;


begin
if L<> nil then
while LA . Sg te <>nil do
. - L A. Sg te;
L .-
Ultim o .. -- L
end;

Operacin elimina arco: Una vez encontrada la lista de adyacencia se procede a


eliminar el nodo que representa el arco.

procedure borr_arco(var G :PtrDir; VI,V2:st ring) ;


var
P , Q : Pt rDir;
R,W: Ptrady;
Sw: boo l ea n ;
begin
P : = Direc c i o n (G , VI) ;
Q : = Direc c i o n( G , V2) ;
if (P <> nil ) and (Q <> n i l ) then
begin
R := PA . Lady ; W := nil; Sw : = f a lse;
while (R<>n i l) and not Sw do
if RA.PtrV = Q then
430 Estructura de datos

begin
if W = nil then
PA.Lady := RA.Sgte
elBe
WA.Sgte := RA.Sgte;
dispose (R) ;
Sw := true
end
elBe begin
W : = R;
R := RA.Sgte
end
end;
end;

Operacin Adyacente.
function Adyacente(G: PtrDir; Vl,V2: string) :boolean;
var
P,Q: PtrDir;
R,W: Ptradv;
Sw: boolean;
begin
P := Direccion(G,Vl),
Q := Direccion(G,V2);
if(P<>nil)and(Q<>nil) then
begin
{Proceso de bsqueda}
R := PA.Lady; Sw := false;
while(R<>nil) and not Sw do
begin
Sw := RA.PtrV = Q;
if not Sw then R := RA.Sgte
end;
Adyacente := Sw
end
elBe Adyacente := false
end;

Operacin Nuevo_vertice (X).

Aade un vrtice X del grafo a la lista directorio. Siempre se aade como ltimo
nodo.
procedure Nuevo_vertice(var G: PtrDir; x: string);
begin
if G<>nil then
Ultimo(G)A.Sgte := CrearVt(X)
el Be
G := CrearVt(X)
end;

Operacin Borra_vertice (X) elimina del grafo G el vrtice X.

La operacin de eliminar un vrtice del grafo supone eliminar los arcos que van a l
y despus suprimirlo de la lista directorio. Se utilizan operaciones auxiliares nuevas:

Grafos. Representacin y operaciones 431

An ter i o r (G, P) devuelve un puntero a la direccin del nodo anterior y


Liber a que libera la memoria de cada nodo de la lista de adyacencia.
procedure Bor r a_ver t i ce (var G : PtrDir ; x : st r i n g) ;
var
P, Q : PtrDi r,
R,W: P tra dy;
Sw: boolea n;
begin
P : = Direccio n( G, X) ;
if (P <> nil ) then
begin
Q := G;
while Q<> nil do {s uprim e to d os los pos ibles arc o s QA .Vert-X}
begin
bo r r _ arco (G, QA.Ve rt ,X) ;
Q := QA. Sgte
end;
{Aho r a el imi na nodo de la l i sta dir ector i o}
if G = P then
G := GA.Sg te
elBe
Ant erior{G , P ) A.Sgte : = p A. Sgte ;
Li be r a( p A. Lady) ;
dispo s e(P)
end
end;

13.5. RECORRIDO DE UN GRAFO


La operacin de recorrer una estructura consiste en visitar (procesar) cada uno de los
nodos a partir de uno dado. As, para recorrer un rbol se parte del nodo raz y segn el
orden se visitan todos los nodos. De igual forma, recorrer un grafo consiste en visitar
todos los vrtices alcanzables a partir de uno dado. Hay dos formas : recorrido en pro-
fundidad y recorrido en anchura.

13.5.1. Recorrido en anchura


Este mtodo comienza visitando el vrtice de partida A, para a continuacin visitar los
adyacentes que no estuvieran ya visitados. As sucesivamente con los adyacentes. Este
mtodo utiliza una cola como estructura auxiliar en la que se mantienen los vrtices que
se vayan a procesar posteriormente. La estrategia la expresamos de forma ms concisa
en estos pasos:

l. Visitar el vrtice de partida A.


2. Meter en la cola el vrtice de partida y marcarle como procesado.
3. Repetir los pasos 4 y 5 hasta que la cola est vaca.
,
., .
~
4. Retirar el nodo frente (W) de la cola, visitar W.

5. Meter en la cola todos los vrtices adyacentes a W que no estn procesados y


'.
marcarlos como procesados .

.'

,:;,


432 Estructura de datos

En el grafo dirigido de la figura queremos hacer recorrido a partir del vrtice D.

El seguimiento de la estrategia indicada: inicialmente aadir D a la cola, retirar el


elemento frente de la cola D, meter en cola los vrtices adyacentes a D no procesados.
La siguiente figura muestra el estado de la cola en cada paso, as como la sucesin de
vrtices recorridos.
,I Vrtices del recorrido desde D eola

, Frente Final

{D} Frente Final


'\ /
~B

{D, Bl Frente Final


'\ /

{D, B, el Final
/
14 l'
H R

{D, B, e, Hl Frente Final


'\ /
~R A T
~

{D, B, e, H, Rl Final
/
14 l'
A T

{D, B, e, H, R, A} Frente
. '>.. /
Final
y
...... T

{D, B, e, H, R, A, T} eola vaca


Grafos. Representacin y operaciones 433

En este ejemplo el recorrido del grafo en anchura a partir de D es el conjunto de


todos los nodos. En definitiva, todos los vrtices del grafo son alcanzables desde el vr-
tice D.

13.5.2. Realizacin del recorrido en anchura


Para codificar el recorrido en anchura tenemos que utilizar las operaciones del TAD
cola. Para marcar los vrtices ya visitados se pueden seguir varias alternativas, elegimos
la de definir una lista con todos los vrtices del grafo y un campo que indique si est o
no procesado.
Esta realizacin supone que el grafo est representado mediante listas de adyacen-
cia. Los tipos de datos para la cola y la lista de visitados.
type
Tipoeleme n = Vertice ;
Ptrnodoq = AN odoq ;
Nodoq = record
Inf o : Ti poe le me n ;
Sgte : Ptrnodo q
end;
Co l a = record
Frente,
F i nal : Ptrn odoq
end;
Pt r _ Lv = ANodo_Lv;
Nodo_ Lv = record
V : PtrDir ;
Vsdo : boolean ;
Sgte : Pt r_ l v
end;

CODIFICACiN
procedure Recorrido _ Anchu r a(G,W : PtrDir) ;
var
Lv,Av : Ptr I v ;
Qe : Cola ;
N : PtrD ir;
L : P t rAdy;
procedure Lis t a_Visitados (var Lv : Pt r_Lv ; G : PtrDir);
var P : Pt rDi r;
function Cre aV( Q : PtrDir ): Ptr _ Lv ;
var A : Ptr Lv;
begin
n ew (A) ;
AA . V : = Q; AA . Vsdo : = fa ls e;
CrearV : = A
end;
begin
if G<>n i l then
begin
Lv : = CreaV(G); P : = Lv; G : = GA . Sgte;
Grafos. Representacin y operaciones 435

la direccin de visitar es hacia adelante mientras que sea posible; al contrario que la
bsqueda en anchura, que primero visita todos los vrtices posibles en amplitud.
La definicin recursiva del recorrido en profundidad ya nos indica que tenemos que
utilizar una pila como estructura para guardar los vrtices adyacentes no visitados a uno
dado. De igual forma que en el recorrido en anchura, hacemos uso de una lista de vrti-
ces para controlar los ya visitados.
En la siguiente figura desarrollamos el recorrido en profundidad para el mismo grafo
y mismo vrtice de partida (D) que en el recorrido en anchura.

13.5.4. Recorrido en profundidad de un grafo


A

Vrtices del recorrido desde D Pila

D D ~ Cima

{D} B C ~ Cima

{D, C} B R ~ Cima

{D, C, R} B H ~ Cima

{D, C, R, H} B A T ~ Cima

{D, C, H, R, T} B A ~ Cima

{D, C, R, H, T, A} B ~ Cima

{D, C, R, H, T, A, B} Pila Vaca

13.5.5. Realizacin del recorrido en profundidad


La codificacin del recorrido en profundidad exige la utilizacin de operaciones del TAD
pila. Para marcar los vrtices ya visitados utilizamos la misma lista de vrtices del grafo
que en el recorrido de anchura.
Suponemos el grafo representado mediante listas de adyacencia. Los tipos de datos
para la pila y la lista de visitados.

I
o

Grafos. Representacin y operaciones 437

Dir ecc i o n (Lv ,W )A . Vsdo := tru e ; {Lv e s la li st a de n o d os v i s itado s}


L := WA. Lady ;
while L<> n i l do
begin
if not Direccion(Lv,LA . V) A. Vsdo then {si no v i s i tado}
Pro fundidad(L A.V,Lv) ;

end
end

13.6. CO ONENTES CONEXAS DE UN GRAFO


Un grafo no dirigido G es conexo si existe un camino entre cualquier par de nodos que
forman el grafo. En el caso de que el grafo no sea conexo se puede determinar todas las
componentes conexas del mismo.
En un grafo dirigido podemos distinguir entre grafo dirigido conexo y grafo fuerte-
mente conexo. Un grafo dirigido es conexo si para cada par de vrtices existe una cade-
na que los une. Y un grafo dirigido es fuertemente conexo si para cada par de vrtices
existe un camino que los une. El concepto de cadena se utiliza ms adelante en el estu-
dio del flujo mximo en una red.
Un algoritmo para detellninar las componentes conexas de un grafo G no dirigido.

l. Realizar un recorrido del grafo a partir de cualquier vrtice w. Los vrtices visi-
tados son guardados en el conjunto W. .
2. Si el conjunto W es el conjunto de todos los vrtices del grafo, entonces el grafo
es conexo.
3. Si el grafo no es conexo, W es una componente conexa.
4. Se toma un vrtice no visitado, z, y se realiza de nuevo el recorrido del grafo a

partir de z. Los vrtices visitados W forman otra componente conexa.


5. El algoritmo termina cuando todos los vrtices han sido visitados.

CODIFICACiN
Se parte de un grafo G representado mediante listas de adyacencia, los vrtices segn
son visitados son almacenados en un vector para as comparar los vrtices visitados con
el total de vrtices y determinar si el grafo es conexo. Es necesario seguir utilizando la
lista de vrtices visitados.
Los tipos de datos que se incorporan a los ya definidos para el recorrido:

const
M = 100; {Mx imo d e vr ti ces}
type
Co nj u n t o = record
Vc : array[ l .. M} of Vert i ce ;
N: O .. M
end;
Estructura de datos

El recorrido del grafo no dirigido para obtener una componente conexa:


procedure Conexa(G , Z ; PtrDir; var Lv: Ptr _L v ; var W: Co njunto);
var
Av: Ptr-Lv;
Pila: Ptrnodop;
N: PtrDir;
L: PtrAdy;
{Cdigo de procedimien tos y funci ones auxiliares, igual que
r ecorrido en anchu r a}
begin
P i l avacia(Pila) ;
Meter(z,pila); Dire ccion (Lv ,Z) A. Vsdo := t ru e;
repeat
Sacar(Z, Pila);

with W do

begin
N := N+l;
Vc[N] := ZA.Vert
end;
L := ZA.Lady;
while L<> nil do
begin
N := LA.V; Av := Direccion(Lv,N);
if not Av A. Vsdo then
begin
Meter(N,Pila) ;
AvA.Vsdo := true
end;
L := LA.Sgte

I end
until Esvacia (Pila)
,, II end;

procedure Compon e ntes_C one xas(G: Graf o) ;


var
T,W: Conjunto;
Z: PtrDir ;
J: intege r ;
function Dir_N ovis(L: Ptr_Lv): Ptr_L v ;
var
D: Ptr_Lv ;
,
Sw : bool ean;
begin
Sw := false; D := L;
while (D<>nil) and not Sw do
begin
Sw := not DA.Vsdo ;
if not Sw then D : = DA. Sgte
end;
Dir Novis := D
end;
begin
{En T guardamos el co njun to de t odos lo s v rtic es }
with T do
begin

,

Grafos. Representacin y operaciones 439

N : =O ; Z := G;
while z < >ni l do
begin
N : = N+l ;
Vc [ N] := ZA. Ve r t
Z : = ZA. Sg t e
end;
end;
Lista_V i sitados I Lv , G) ; {Todos los v rt i c es s e pone n a fa l se su
camp o v is ita do }
(Com i e n za a part i r de pr i mer vrtice n o vis it ado}
Z := Dir _N ov is(Lv);
while Z<>ni l do
begin
W.N := O;
Co n exaIG , Z , Lv , W) ;
if W. N = T .N then
wr i t e ln( 'Te nemos un gra f o no dirigido Cone x o')
elee begin
wri t e ( ' Co mp on en te Con e xa:' ) ;
for J := 1 to W. N do
wr i t e ( W. Vc [J ] , ' , ) ;
wr i teln
end;
Z : = Dir_No vi s(L v )
end
end;

13.7. COMPONENTES FUERTEMENTE CONEXAS


DE UN GRAFO DIRIGIDO
Un grafo dirigido fuertemente conexo es aquel en el cual existe un camino entre cual-
quier pareja de vrtices del grafo. De no ser fuertemente conexo se pueden determinar
componentes fuertemente conexas del grafo.

EJEMPLO
La figura siguiente muestra un grafo dirigido con sus componentes fuertes.

Grafo dirigido G Componentes fuertes de G

Pueden seguirse diversas estrategias para encontrar si un grafo G es fuertemente co-


nexo o en su caso determinar las componentes conexas. El siguiente algoritmo utiliza el
recorrido en profundidad.

,
440 Estructura de datos

l. Obtener el conjunto de descendientes de un vrtice de partida v, D(v), incluido


i
;
el propio vrtice v. As tenemos todos los vrtices desde los que hay un camino
que comenzando en v llega a l.
2. Obtener el conjunto de ascendientes de v, A(v), incluido el propio vrtice v. Es-
tos vrtices son aquellos en los que comienza un camino que llega a v.
3. Los vrtices comunes que tiene D y A, es decir, D(v) n A(v), es el conjunto de
,
, vrtices de la componente fuertemente conexa a la que pertenece v. Si este con-
,
,,
junto es igual al conjunto de vrtices de G, entonces el grafo es fuertemente

, conexo.
,, 4. Si no es un grafo fuertemente conexo se selecciona un vrtice cualquiera w que
I no est en ninguna componente fuerte de las encontradas [w E: D( v) n A( v)] y se
procede de la misma manera, es decir, se repite a partir de 1 hasta obtener todas
I
I,
las componentes fuertes del grafo.

Para el paso 1 se realiza un recorrido en profundidad del grafo G a partir del vrti-
ce v. Los vrtices que son visitados se guardan en el conjunto D.
, Para el paso 2 hay que proceder en primer lugar a construir otro grafo dirigido G que
!
! sea el resultante de invertir las direcciones de todos los arcos de G. Y a continuacin
proceder como en el paso l.
En cuanto a los tipos de datos, el tipo vrtice se supone entero de tal forma que el
ordinal del vrtice coincide con el vrtice. Adems se supone que el mximo de vrtices
es 100. El grafo est representado mediante listas de adyacencia. Se define el vector
boolean visitado cada elemento del vector tiene verdadero (true) si en el recorrido el
vrtice con el que se corresponde ha sido visitado. El recorrido est codificado segn su
definicin, de manera recursiva, de tal fOlma que los vrtices alcanzados desde un vrti-
ce de partida se guardan como sus descendientes; la lista de vrtices visitados se imple-

, menta con un vector global. Repitiendo el recorrido a partir del mismo vrtice, pero con
!
el grafo inverso (cambiando el sentido de los arcos), los vrtices alcanzados a partir del
vrtice de partida son sus ascendientes.

CODIFICACiN

El programa que se presenta tiene dos partes diferenciadas. La primera lee los arcos del
grafo, crea las listas de adyacencia del grafo G y a la vez las listas de adyacencia del
grafo inverso InvG . La segunda encuentra las componentes conexas y las escribe.

program Comp o nent es Fue r te s (input , output) ;


,
const n - l OO ;
type
Ver ti ce = 1 .. n ;
PtrD ir = ANodoD ir;
PtrAd y = ANodoLy ;
NodoD ir = record
Vert : Vertice ; (Id e nt i fi ca dor de l vrtice )
Lady : Pt rAdy ;
Sgte : PtrDir
,

442 Estructura de datos

Esconex o : = S
end;
procedure In terse cc ion(D ,A: Visit ad os ; Nv: vertic e;
var F : Visitados);
var J : Ve rt ice ;
begin
for J : = 1 to Nv do
F[J] := F [J] or (D[J] and A[J] )
end;

begin {programa p r inc ipa l }


write ('Numero de Vertic es:' ) ; re adln (NumVert s ) ;
ListaDirectorio(G , NumVerts) ;ListaD irec torio(InvG , Num Vert s);
Arcos(G , I n vG ,Nu mVerts) ;
for 1 := 1 to NumVerts do
Nu 1 o [ 1 ] : = fa 1 s e;
F uer tes : = Nulo ; Proc : = Nulo ;
for 1 : = 1 to Nu mVerts do
begin
if not Pro c [ I] then {V rti ce d e parti da cualqu i era q ue no

es t en ni nguna compone nte ya o bte n i da . }


begin
Vst dos : = Nu lo ; Desc ende n tes : = Nulo ; Ascende n tes := Nulo;
Profundidad (G , 1 , Descenden tes) ;
Vst dos := Nulo;
Profundidad( I nvG,I , As cendent e s) ;
I nterse ccion(Descende n tes,Asce nde n t es , NumVe rt s , Fuerte s) ;
if Esconexo ( F uertes , NumVer t s) then
begin
writ eln ( 'El graf o es fue rt emente c onexo ');
Proc : = Fuer t e s
end
else begin
writ e ( ' Comp o n ent e fuerte :');
for J : = 1 to NumVe r ts do
if Fuertes [ J] then write (J, ' ' ) ;
wr i te l n;
for J := 1 to NumVe rts do
Pr o e [ J ] : = Pr oc [ J ] or Fuer t es [J ] ;
Fu e r tes : = Nulo; { Prepara para buscar otra compon e n te fuerte}
end;
end ;
G : = GA. Sgte ; In vG : = In vGA . Sgt e
end
end.

13.8. MATRIZ DE CAMINOS. CIERRE TRANSITIVO


Conceptos importantes a considerar en la construccin de grafos son: Camino entre par
,I
de vrtices, la matriz de caminos y el cierre transitivo.


Camino entre par de vrtices

Sea G un grafo de n vrtices y A su matriz de adyacencia de tipo lgico. Obsrvese la


expresin lgica: A [ i , k ] and A [k , j ] . Esta expresin ser cierta si y slo si los va-
Grafos. Representacin y operaciones 443

lores de ambos operandos lo son, lo cual implica que hay un arco desde el vrtice i al
vrtice k y otro desde el vrtice k al). Tambin podemos decir que la expresin sea cierta
implica la existencia de un camino de longitud 2 desde el vrtice i al j.
Ahora consideremos la expresin:

(A[i, l] and A[ l,j]) or (A[ i , 2] and A[2,j] ) or '" or (A[i,NurnVerts ] and A [NurnVer ts ,j ] )

Si esta expresin es cierta implica que hayal menos un camino de longitud 2 desde el
vrtice i al vrtice) que pase a travs del vrtice 1, o a travs del 2, o a travs del vrtice
NumVerts.
Recordando el producto matricial A x A observamos que la expresin anterior si cam-
biamos and por producto y or por suma representa el elemento Aij de la matriz A2.
2
Segn esto los elementos (Aij) de la matriz A son verdaderos si existe un camino de
longitud 2 desde el vrtice i al vrtice) "di,) = 1..n.
De igual forma el producto matricial A2 x A = A3 nos permite determinar si existe un
camino de longitud 3 entre cualquier par de vrtices del grafo. En general, para determi-
nar la existencia de camino de longitud m entre cualquier par de vrtices se forma el
producto boolean de los caminos de la matriz A m - 1 con la matriz adyacente A.
En la figura siguiente tenemos un grafo dirigido.

La matriz de adyacencia

F T F F F
F F T F T
A= T F F F F
T T F F T
F F F F F

El producto boolean A x A

F F T F T
T F F F F AS, Al5 es verdadero (true) ya que hay un cami-
2
A = F T F F F no de longitud 2 desde A-E (A~B~).
F T T F T
F F F F F

il:.
444 Estructura de datos

El producto boolean N x A

T F F F F
F T F F F
3
As, A 4 es verdadero (true) ya que hay un ca-
A = F F T F T
mino de longitud 3 desde D-A (D~B~C~A).
T F T F T
F F F F F

Con el producto boolean se ha obtenido si hay camino de longitud m entre un par de


vrtices. En caso de que la matriz de adyacencia est representada mediante O, 1 pode-
mos obtener no slo si hay camino de longitud m sino adems el nmero de caminos.
Sea G = (V, A) un grafo representado por la matriz de adyacencia A tal que el ele-
mento A(i,j) es 1 si hay un arco desde el vrtice i al j, tambin nos da el nmero de
caminos del longitud 1 desde i a j. Haciendo un razonamiento similar, la expresin:

(A[i,j] * A[1.j]) + (A[i,2) * A[2,j))+ . . . +(A[i,NurnVerts) * A[NurnVerts,j))

nos da todos los posibles caminos de longitud 2 desde el vrtice i al j, adems, recor-
2
dando el producto matricial A x A, representa el elemento Aij de la matriz A Podemos
generalizar, la forma de obtener el nmero de caminos de longitud k entre cualquier
par de vrtices del grafo es obtener el producto matricial Al, A3 ... Ak, entonces el
elemento Ali,j) nos da el nmero de caminos de longitud k desde el vrtice i hasta
el vrtice j.

EJEMPLO 13.9
Consideremos el grafo anterior cuya matriz de adyacencia es

o 1 O O O
O O 1 O 1
A= 1 O O O O
1 1 O O 1
O O O O O

El producto A x A
.
O O l O 1
1 O O O O

A2= O 1 O O O
O 1 1 O 1
O O O O O

As, hay un camino de longitud 2 desde el vrtice D al vrtice E.


Grafos. Representacin y operaciones 445

El producto N x A

1 O O O O
O 1 O O O
A3 = O O 1 O 1
1 O 1 O 1
O O O O O

Existe un camino de longitud 3 desde el vrtice e al vrtice D.


Procedimiento para obtener el nmero de caminos
A continuacin se escribe el procedimiento para obtener la matriz Ak que nos permite
determinar el nmero de caminos de longitud k entre dos vrtices. El procedimiento
tiene como entrada la matriz de adyacencia, la longitud del camino K y el nmero de
k
vrtices Nvs. La salida del procedimiento es la matriz A

procedure Produeto_A(A: MatAdeia; K: integer; Nvs: Vertiee;


var Ak: Ma tAd e ia);
var
1: integer;
procedure Prod(A,B: MatAdcia; var N: MatAde ia);
var f,e,k,S: integer;
begin
for f := 1 to Nvs do
for e := 1 to Nvs do
begin
S := O;
for K := 1 to Nv s do
S := S+A[f.k]*B[c,k];
N[f.e] := S
end
end
begin
Ak : = A;
if K>=2 then
begin
Prod(A,A,Ak) ;
for 1 := 3 to K do
Prod(Ak,A,Ak)

end
end;

Matriz de caminos
,
Sea G un grafo con n vrtices. La matriz de caminos de G es la matriz n x n P definida:
,"

.
!-
,

1 si hay un camino desde Vi a V j


, p 1).. =
r
';<
"
O si no hay camino desde Vi a V j
~'

,
446 Estructura de datos

El camino de Vi a Vj ser simple si Vi :;:. Vj, o bien un ciclo cuando los extremos sean
el mismo vrtice Vi = Vj. Al ser el grafo G de n vrtices, un camino simple ha de tener
longitud n-l o menor, y un ciclo ha de tener longitud n o menor. Segn esto podemos
encontrar la siguiente relacin entre la matriz de caminos P, la matriz de adyacencia A y
las sucesivas potencias de A.
Dada la matriz Bn = A + A 2+ A) + ... +A n, la matriz de caminos P = (Pij) es tal que un
elemento Pij= 1 si y slo si EnU,}) 2! l yen otro caso Pij= O.
Una vez que tenemos la matriz de camino de un grafo G dirigido podemos determi-
nar de manera ms fcil si el grafo es fuertemente conexo. Recordar que para que G sea
fuertemente conexo se ha de cumplir que para todo par de vrtices Vi, Vj ha de existir un
camino de Vi a Vj y un camino de Vj a Vi. Por tanto, para que G sea fuertemente conexo
la matriz de caminos P ha de tener todos los elementos a 1.

Cierre transitivo
El cierre o contorno transitivo de un grafo G es otro grafo G' que consta de los mismos
vrtices que G y que tiene como matriz de adyacencia la matriz de caminos P del grafo
.
,.. G. Segn esta definicin, un grafo es fuertemente conexo si y slo si su cierre transitivo
es un grafo completo.

13.9. PUNTOS DE ARTICULACiN DE UN GRAFO

Un punto de articulacin de un grafo no dirigido es un vrtice V que tiene la propiedad


de que si se elimina junto a sus arcos, la componente conexa en que est el vrtice se
divide en dos o ms componentes. Por ejemplo, en la figura tenemos un grafo que tiene
dos puntos de articulacin: el vrtice A y el vrtice C. Al eliminar el vrtice C el grafo
que es conexo se convierte en dos componentes conexos: {B,E,F} y {A,D}; si se elimina
el vrtice A, el grafo se divide en estos dos componentes conexos: {C,B,E,F} y {D}. Sin
embargo, al suprimir cualquier otro vrtice del grafo, el componente conexo no se divide.

EJEMPLO 13.10

Grafo G Sin vrtice A Sin vrtice e


Los grafos tienen propiedades relativas a los puntos de articulacin. Un grafo sin puntos
de articulacin se dice que es un grafo biconexo. De no ser el grafo biconexo, es intere-
sante encontrar componentes biconexos. Un grafo tiene conectividad k si la eliminacin

Grafos. Representacin y operaciones 447

de k-l vrtices cualesquiera del grafo no lo divide en componentes conexas (no lo des-
conecta). Cuanto mayor sea la conectividad de un grafo (una red, por ejemplo) tanto
mayor probabilidad tendr de mantener la estructura ante el fallo (eliminacin) de algu-
no de sus vrtices.

Algoritmo de bsqueda de puntos de articulacin


El algoritmo utiliza los recorridos en profundidad de un grafo para encontrar todos los
puntos de articulacin.
El recorrido recursivo en profundidad del grafo a partir de un vrtice A puede repre-
sentarse mediante un rbol de expansin. La raz del rbol es el vrtice de partida A.
Cada arco del grafo estar como una arista en el rbol. Si en el proceso recursivo del
recorrido tenemos que al pasar por los vrtices adyacentes de v, arcos (v, u), el vrtice u
no est visitado, entonces (v, u) es una arista del rbol; si el vrtice u se ha visitado ya,
entonces (v, u) se dice que es una arista hacia atrs (realmente no es una arista e incluso
se dibuja con lnea discontinua). La figura nos muestra un grafo y el rbol del recorrido
en profundidad.

,
, ,
,
,, ,
,,
B--- ,,
,,
,,
Grafo ,,
,,
,

rbol de expansin

Numerando los nodos del rbol en un recorrido en preorden obtenemos el orden en


que han sido visitados.
El algoritmo para encontrar los puntos de articulacin de un grafo conexo sigue es-
tos pasos:

l. Recorrer el grafo en profundidad a partir de cualquier vrtice. Se numeran en el


orden en que son visitados los vrtices, esta numeracin la llamamos Num(v).
2. Para cada vrtice v del rbol del recorrido en profundidad determinamos el vr-
tice de numeracin ms baja [en este caso llamado Bajo(v)] que es alcanzable
desde va travs de O o ms aristas del rbol y como mucho una arista hacia atrs
(de retroceso).

La definicin de Bajo(v) se expresa matemticamente como el mnimo de los


siguientes tres valores:

448 Estructura de datos

a) Num(v).
b) El menor valor de Num(w) para los vrtices w de las aristas hacia atrs (v,w)
del rbol.
e) El menor valor de Bajo(w) para los vrtices w de las aristas (v,w) del rbol.
En la figura del ejemplo 13.11 se encuentran los valores Num(v), Bajo(v) de
todos los vrtices.
3. Una vez que tenemos los valores Num(v), Bajo(v), se determinan los puntos de
articulacin .

3.1. La raz del rbol (vrtice de partida) es punto de articulacin si y slo si
tiene dos o ms hijos.
3.2. Cualquier otro vrtice w es punto de articulacin si y slo si w tiene al
menos un hijo u tal que Bajo(u) ;;:: Num(w).

13.11
En la figura siguiente mostramos un grafo conectado (conexo) y el rbol de expansin.

3,3
---
---
, , --
, rbol; con cada nodo se escribe
,, ,
,, NumO y BajoO.
5,3
,
,


B 6,3

Tomando el vrtice B, el valor Bajo(B) = 3 porque el mnimo [Num(B), Num(C)] es 3;


observar que B tiene un arco de retroceso B-C.
El procedimiento para asignar los valores Num(v) a cada vrtice del grafo consiste
en recorrer en profundidad el grafo, cada llamada recursiva incrementa el contador de
llamadas que es el valor de Num(v) para el vrtice actual. A la vez en el array Ar i s ta
se guarda el vrtice w con el que el vrtice actual forma una arista del rbol de expan-
sin. Para facilitar la comprensin, el tipo vrtice es del rango de l .. n, siendo n el nme-
ro de vrtices, y para marcar los vrtices visitados se utiliza un array lineal.
const N = 8;
type
Vertice - l..n;
visitados = array[Verti cel of boolean;
Numcion - array[ Vert i ce l of Vertice;
procedure Val_Num(G:PtrDir, V:Verti ce ; var Vstdos:Visitados;
var C :integer; var Num:Numcion; var Arista:Numcion);
var
L: ptrAdy;
W: PtrDir;


Grafos. Representacin y operaciones 449

begin
Vs t dos [V] := t r ue ;
C : = C + 1 ; Num [ V] : = C ;
L := GA. Lady; {G ti ene l a di re cci o n del ve rtic e V}
while L <> n i l do
begin
W := L A. Ptr V ;
if not Vs t do s [W A. Ve r t ] then
begin
Ari sta[ WA. Ver t] . -- V,
Va l_Num( W, WA. Vert , Vstdos , C,Nu m , Ar ista)
end;
L : = LA . S gt e
end
end;

El procedimiento para calcular los valores llamados Baja(v) se realiza con un reco-
rrido en postorden de los vrtices. Son necesarios los valores calculados en el procedi-
miento anterior de Num y Arista. Adems se puede determinar los puntos de articulacin
de vrtices que no son la raz (vrtice de partida) al conocerse el valor de BajaO.

procedure Val _B a j o(G : PtrD i r ; V : Vertic e; var Nu m : Numcio n;


var Vs t dos : Vi si t a d os; var Ar ista : Num c i on ;var Ba j o : Nu mcion) ;
var
L: Ptr a dy ;
W: PtrDi r ;
begin
Vstdos [V] : = true ;
Baj o [ V] : = Nu m [ V ]; {va l o r i n icia l pa r a c l cul o de l mi smo}
L := GA . Lady ;
while L <> ni l do
begin
W : = L A. PtrV ;
if not Vs td os [WA. Vert ] then
if Num [ WA . Vert ] > Num [ V] then {arco d el r bol}
begin
Val _ Baj o(W ,W A. Ver t,Nu m,Vs tdos ,A r i st a, Bajo ) ;
(Calcu l a Bajo( w ) t a l qu e w hijo d e V }
if Ba jo [ WA. Ver t l > = Nu m [Vl then
wri tel n (V ,' es u n pun t o de ar t icu l aci n.' ) ;
Bajo [V l : = Mi n i mo (B ajo [Vl, Baj o [W A Ve rt ] )
(menor valo r de Bajo(w) ... reg l a e}
end
elBe if Ar i st a[ V] <> WA. Ver t then {a r ista ha c i a at rs }
Baj o [ V]: = Mi nimo(Ba j o [V ] ,N um [ WA. Ve rt ]) ; (me n or de Nu m( w )
r egla b }
L : = L A.S gt e
end
end;

Los procedimientos V al_Num y V al_Baj o se pueden combinar en un solo proce-


dimiento que calcule a la vez Num (v) y Baj o ( v) ; y adems nos muestre los puntos
de articulacih (excepto si lo es el vrtice de partida).
450 Estructura de datos

procedure Pt os _A r tc( G :PtrDir; V : Ve r t i ce ; var Num:Numcion;


var C :in te ger;var Vstdos:Visitados;
var Ari sta :Numc i o n; var Bajo:Numcion);
var
L: Ptrady;
W: PtrDir;
begin
Vstd os[V] := tru e; C : = C+l; Num[V] : = C;
Ba jo [ V) : = Num [ V ); (Valor in ici al pa r a el c lcul o del mn i mo )
L := GA .L ady ;
while L <> nil do
begin
W := LA.PtrV;
if not Vs tdos [W A. Ver t) then
begin
Ari sta[W A.V ert] .' -- V',
Ptos_Artc(W,wA.Vert.Num, C ,Vstdos,Ar i sta, Bajo) ;
if Bajo (WA. Ve rt ) > = N u m (V) then
writeln (V ,' es un punto de arti cul ac i n .' ) ;
Bajo[V] : = Minimo( Bajo[V) ,Bajo[W A.Vert)) (menor valor de
. Bajo(v) ... regla el
,
end
else if Arista[V) <> WA.Vert then {arista hac i a atrs}
Baj o [ V ) : = Minimo (Ba j o [V) ,Num [W A . Ver t ) ); (m e n or de
Num(w) ... r egla bl
L := LA .Sgt e
end
end;

RESUMEN

Un grafo G consta de dos conjuntos (G = { V, E}): un conjunto V de vrtices o nodos y un conjunto


,
E de aristas (parejas de vrtices distintos) que conectan los vrtices. Si las parejas no estn orde-
nadas, G se denomina grafo no dirigido; si los pares estn ordenados, entonces G se denomina
grafo dirigido. El trmino grafo dirigido se suele tambin designar como digrafo y el trmino
grafo sin calificacin significa grafo no dirigido.
El mtodo natural para dibujar un grafo es representar los vrtices como puntos o Crculos y
las aristas como segmentos de lneas o arcos que conectan los vrtices. Si el grafo est dirigido,
entonces los segmentos de lnea o arcos tienen puntas de flecha que indican la direccin.
Los grafos se pueden implementar de dos formas tpicas: matriz de adyacencia y lista de
adyacencia. Cada una tiene sus ventajas y desventajas relativas. La eleccin depende de las nece-
sidades de la aplicacin dada.
Existen diversos tipos de grafos no dirigidos. Dos vrtices de un grafo no dirigido se llaman
adyacentes si existe una arista desde el primero al segundo. Un camino es una secuencia de vrti-
ces distintos, cada uno adyacente al siguiente. Un ciclo es un camino que contenga al menos tres
i

vrtices, tal que el ltimo vrtice en el camino es adyacente al primero. Un grafo se denomina

conectado si existe un camino desde cualquier vrtice a cualquier otro vrtice.
Un grafo dirigido se denomina conectado fuertemente si hay un camino dirigido desde un
vrtice a cualquier otro. Si se suprime la direccin de los arcos y el grafo no dirigido resultante se
conecta, se denomina grafo dirigido dbilmente conectado.


,
l.
Grafos. Representacin y operaciones 451

El recorrido de un grafo puede ser en analoga con los rboles, recorrido en profundidad y
recorrido en anchura. El recorrido en profundidad es aplicable a los grafos dirigidos y a los no
dirigidos y es una generalizacin del recorrido preorden de un rbol. El recorrido en anchura es
tambin aplicable a grafos dirigidos y no dirigidos, que generaliza el concepto de recorrido por
niveles de un rbol.

EJERCICIOS
13.1. Sea el grafo no dirigido G de la figura

H
F L

R T

a)Describir G formalmente en trminos de su conjunto V de nodos y de su conjunto A de


aristas.
b) Encontrar el grado de cada nodo.

13.2. Sea el grafo dirigido de la figura

a) Describir el grafo formalmente en tlluinos de su conjunto V de nodos y de su conjun- I



to A de aristas.
b) Encontrar el grado de entrada y el grado de salida de cada vrtice.
e) Encontrar los caminos simples del vrtice M al vrtice T. I
13.3. Sea el grafo G de la figura

a) Encontrar todos los caminos simples del nodo A al nodo F.


b) Encontrar el camino ms corto de e a D.
e) Es un grafo conexo?
452 Estructura de datos

13.4. Dado el grafo valorado de la figura


7
5
4 5
9
8

a) Encontrar la matriz de pesos del grafo.


b) Representar el grafo mediante listas de adyacencia.

13.5. Un grafo G consta de los siguientes nodos V = {A, B, e, D, E} Y la matriz de adyacencia

,
I
o 1 1 1 O
1 O 1 O 1
M= 1 1 O l l
O l 1 O 1
O 1 l O O
a) Dibujar el grafo correspondiente.
b) Representar el grafo mediante listas de adyacencia.

13.6. Dado el grafo G del ejercicio 13.5 realice el recorrido del grafo en profundidad partiendo
del nodo C.
13.7. Dado el grafo G del ejercicio 13.5 realice el recorrido del grafo en anchura partiendo del
nodo C.
13.8. Un grafo dirigido acclico (gda) es un grafo dirigido sin ciclos. Dados los siguientes
grafos:

indicar si son gda,s. En caso de no serlo escribir los ciclos.


13.9. Dado el grafo de la figura

encontrar las componentes fuertemente conexas.


Grafos. Representacin y operaciones 453

13.10. Dado el grafo G de la figura

a) Escribe la matriz de adyacencia de G.


b) Escribe la matriz de caminos de G.

13.11. Dibujar un grafo dirigido cuyos vrtices son nmeros enteros desde 3 hasta 15 para cada
una de las siguientes rela~es:
a) ves adyacente de w si v + 2w es divisible entre 3.
b) v es adyacente de w si I Ov + w < v*w.

PROBLEMAS
13.1. Escribir un programa para dar de entrada los vrtices y las aristas de un grafo dirigido. La
representacin del grafo ser mediante matriz de adyacencia. El programa pedir un vrti-
ce para realizar el recorrido en profundidad del grafo a partir de dicho vrtice.
13.2. Un grafo valorado est formado por los vrtices 4,7, 14, 19,21,25. Las aristas siempre
van de un vrtice de mayor valor numrico a otro de menor valor, y el peso es el mdulo
del vrtice origen y el vrtice destino. Escribir un programa que represente el grafo en
listas de adyacencia. Adems, realizar un recorrido en anchura desde un vrtice dado.
13.3. Queremos formar un grafo de manera aleatoria con los siguientes requisitos: consta de
10 vrtices que son nmeros enteros de 11 a 99. Dos vrtices X.y estn relacionados si
x+ y es mltiplo de 3. Escribir un programa para representar el grafo descrito mediante
una matriz de adyacencia Determinar la matriz de caminos utilizando las potencias de la
matriz de adyacencia.
13.4. Una regin est formada por 12 comunidades. Se establece la relacin de desplazamiento
de personas en las primeras horas del da. As, la comunidad A est relacionada con la
comunidad B si desde A se desplazan n personas a B, de igual forma puede haber relacin
entre B y A si se desplazan m personas de B hasta A. Escribir un programa que represente
el grafo descrito mediante listas de adyacencia. Tiene fuentes y sumideros?
13.5. Dado el grafo descrito en el problema 13.4, escribir un programa para representarlo me-
diante listas enlazadas de tal fOI ma que cada nodo de la lista directorio contenga dos listas:
una que contiene los arcos que salen del nodo, y la otra que contiene los arcos que termi-
nan en el nodo.
13.6. Dado un grafo dirigido en el que los vrtices son nmeros enteros positivos y el par (x,y)
es un arco si x-y es mltiplo de 3, escribir un programa para representar el grafo mediante
listas de adyacencia de tal forma que cada lista sea circular. Una vez el grafo en memoria I
determinar el grado de entrada y el grado de salida de cada nodo.
13.7. Un grafo no dirigido est representado en memoria mediante listas de adyacencia y se
desea saber si el grafo es cclico o acclico. Escribir un programa que represente el grafo y
las funciones o procedimientos necesarios que determinen si el grafo es cclico o acclico.
Adems, escribir un procedimiento para listar los nodos que forman un ciclo (en caso de
que lo haya).

!
!

454 Estructura de datos

13.8. Un algoritmo para detectar ciclos en un grafo dirigido consta de los siguientes pasos:
l. Obtener los sucesores de cada uno de los vrtices.
2. Buscar un vrtice sin sucesores y eliminarlo de los conjuntos de sucesores.
3. Repetir paso 2 siempre que haya algn vrtice sin sucesores.
4. Si todos los vrtices del grafo han sido eliminados, el grafo no tiene ciclos.
Realizar un programa en el que se represente un grafo dirigido mediante listas de adya-
cencia y detecte si el grafo dirigido tiene ciclos siguiendo el algoritmo descrito.
13.9. Se tiene un grafo representado mediante una matriz de adyacencia, escribir los procedi-
mientos necesarios para representar dicho grafo mediante listas de adyacencia.
13.10. Un grafo en el que los vrtices son regiones y los arcos tienen factor de peso est repre-
sentado mediante una lista directorio que contiene a cada uno de los vrtices y de las que
sale una lista circular con los vrtices adyacentes. Ahora se quiere representar el grafo
mediante una matriz de pesos, de tal forma que si entre dos vrtices no hay arco su
posicin en la matriz tiene O, y si entre dos vrtices hay arco su posicin contiene el
factor de peso que le corresponde. Escribir los procedimientos necesarios para que par-
tiendo de la representacin mediante listas se obtenga la representacin mediante la ma-
triz de pesos.

,
/

,
,
,
CAPITULO

un amenta es con
,', ,
"
',"", i' i', ' ... .. ... . . ,
... . .. ' ' ' ' ' , ' ,
,
," ,', ""
.
, ,,l',e~'
"
].
" "', , .
t ~ ",',." '" e,' '~", "
, ' , ,1 '
'. " :" ;

CONTENIDO

14" 1.Ordenacin topolgica.


14.2. Matriz de caminos: algoritmo de Warshall.
14.3. Problema de los caminos ms cortos con un solo origen: algoritmo de Dijkstra.
14.4. Problema de los caminos ms cortos entre todos los pares de nodos: algoritmo de
Floyd.
14.5. Problema
, del flujo de fluidos.
14.6. Arbol de expansin de coste mnimo.
14.7. Problema del rbol de expansin de coste mnimo: algoritmos de Prim y Kruskal.
14.8. Codificacin del rbol de expansin de coste mnimo.
RESUMEN.
EJERCICIOS.
PROBLEMAS.

Existen numerosos problemas que se pueden formular en trminos de


grafos. La resolucin de estos problemas requiere examinar todos los
nodos o todas las aristas de un grafo; sin embargo, existen ocasiones
en que la estructura del problema es tal que slo se necesitan visitar
algunos de los nodos o bien algunas de las aristas. Los algoritmos im-
ponen implcitamente un orden en estos recorridos: visitar el nodo ms
prximo o las aristas ms cortas, y as sucesivamente; otros algoritmos
no requieren ningn orden concreto en el recorrido.
En base a lo anterior, se estudian en este captulo el concepto de
ordenacin topolgica, los problemas del camino ms corto, junto con
el concepto de rbol de expansin de coste mnimo. De igual modo se
consideran algoritmos muy eficientes probado en situaciones crticas y
de todo orden, tales como los algoritmos de Dijkstra, Warshall, Prim
y Kruskal, entre otros.

455

l.
456 Estructura de datos

14.1. ORDENACiN TOPOLGICA


Un grafo G dirigido y sin ciclos se denomina un gda (grafo dirigido acclico) o grafo
acclico. Los gda son tiles para la representacin de estructuras sintcticas de expresio-
nes aritmticas. Los grafos dirigidos acclicos tambin son tiles para la representacin
de ordenaciones parciales. Una ordenacin parcial R en un conjunto C es una relacin
binaria de precedencia tal que:

l. Para todo u perteneciente a C, u no est relacionado con u, u R u es falso , por


tanto, la relacin R es no reflexiva.
2. Para todo u, v, w e e, si u R v y v R w entonces u R w. La relacin R es tran-
sitiva.

Tal relacin R sobre C se llama ordenacin parcial de C. Un ejemplo inmediato es la


relacin de inclusin en conjuntos.
Un grafo G sin ciclos se puede considerar un conjunto parcialmente ordenado. Para
probar que un grafo es acclico puede utilizarse la bsqueda en profundidad, de tal for-
ma que si se encuentra un arco de retroceso en el rbol de bsqueda el grafo tiene al
menos un ciclo.
Una ordenacin topolgica T de un grafo acclico es una ordenacin lineal de los

vrtices, tal que si hay un camino del vrtice Vi al vrtice Vj' entonces vj aparece despus
de Vi en la ordenacin T.

EJEMPLO 14.1

,
i

,,.

,,
,

La figura muestra un grafo acclico que representa la estructura de prerrequisitos de


ocho cursos. Un arco cualquiera (r, s) significa que el curso r debe de terminarse antes )
de empezar el curso s. Por ejemplo, el curso M21 se puede empezar slo cuando termi-
nen los cursos Ell y Tl2; se dice que Ell y Tl2 son prerrequisitos de M21.
Una ordenacin topolgica de estos cursos es cualquier secuencia de cursos que cumple
los requerimientos (prerrequisitos). Entonces para un grafo dirigido acclico no tiene
por qu existir una nica ordenacin topolgica.
Del grafo de requisitos de la figura obtenemos estas ordenaciones topolgicas:

EII - Tl2 - M21 - C22 - R23 - S31 - S32 - T41


Tl2 - EII - R23 - C22 - M21 - S31 - S32 - T41

Algoritmos fundamentales con grafos 457

Est claro que una ordenacin topolgica no es posible en un grafo con ciclos. Qu
implica el que haya un ciclo? Pues que si v, w pertenecen al ciclo, entonces v precede
a w, y que w precede a v lo cual es evidentemente imposible.

Algoritmo para la obtencin de una ordenacin topolgica T

Para que resulte ms familiar la exposicin del algoritmo, los vrtices del grafo van a
representar tareas. En primer lugar hay que buscar alguna tarea que no tenga predeceso-
res, que no tenga prerrequisitos, esto es, que no tenga arcos de entrada. Este vrtice v
pasa a formar parte de la ordenacin T; a continuacin, todos los arcos que salen de v
son eliminados (el prerrequisito v ya se ha satisfecho). La estrategia se repite, se coge
otro vrtice w sin arcos incidentes, y as sucesivamente.
Precisando un poco ms la estrategia, el que un vrtice v no tenga arcos incidentes lo
expresamos como que el gradoentrada (v) = O. Eliminar los arcos que salen de v implica
ro.
r que el gradoentrada (w) de todos los vrtices w adyacentes de v disminuyen en l.
"
,.l ,
En una estructura de tipo cola se guardan los vrtices con gradoentrada O, el ele-
,
mento frente de la cola v pasa a formar parte de la ordenacin T. Se disminuye el grado-
entrada de los adyacentes de v, y aquellos vrtices cuyo gradoentrada se haga O se me-
ten en la cola; as sucesivamente hasta que la cola est vaca.

CODIFICACiN

La codificacin se hace pensando en que el grafo tiene relativamente pocos arcos, lo que
da origen a una matriz de adyacencia sparce (muchos ceros); por lo que la representa-
cin es con listas de adyacencia. Se utilizan las operaciones del TAD grafo.
const
N = {nme r o de vrt i ce s }
type
{t i pos para re p r ese n tar u n gra f o por l i s tas d e adyacenc i a}
Ve rt i c e =1 .. N;
Ptrnod oq = ~ N o doq;
Nodo q = record
I n f o: Vert i ce ;
Sgte: p trn o d o q
end;
Co l a = record
Fren te ,
Final: Pt rn odoq
end;

{Fu nci n qu e d e vu elve el g rad o de entr a da de un v rti c e }


function Gra d oE n t ra da(V : Ve r tice ; G : Pt rDir ) : i n t ege r;
{G e s la direccin de l ista di r ec t orio de l g r afo}
var
K: int ege r; W: Ve r t i ce ;
begin
K: =O;
while G <> nil do

458 Estructura de datos

begin
W:=GAVer;
if Adyacente(G,W,V) then { hay arco W ~ V }
K:=K+l;
G:=GA.Sgte
end;
GradoEntrada:=K
end;

procedure OrdenTopologica(G:PtrDir);
type
Vector = array[l . . N] of integer;
var
Grd: Vector;
V: Vertice;
Pv,Pw:PtrDir;
Lad:Ptrady;
Q: Cola;
begin
{Determina grado de entrada de cada vrtice}
for V:= 1 to N do
Grd[V]:= GradoEntrada(V,G);
Qcrear( Q); write( 'Ordenacin topolgica: ');
{Mete en cola vrtices con grado de entrada O}
for V:= 1 to N do
if Grd[V] = O then
I
Qponer(V,Q) ;
whi1e not Qvacia(Q) do
1-
begin
Qsacar(V,Q) ;
wr i t e (V: 2 " ');
Pv:= Direccion(G,V); Lad:=PvA.Lady;
{Decrementa grado entrada de V. adytes y si se pone a O es llevado
a cola}

whi1e Lad <> ni1 do


begin
Pw:=LadA.Pvert;
V:=PwA.Ver;
Grd[V]:= Grd[V]-l;
if Grd[V] = O then
Qponer(V,Q)
end
end;
end;

En cuanto al tiempo de ejecucin de algoritmo es de O (a + V) siendo a el nmero de


arcos y V el de vrtices. En caso de que la representacin del grafo sea con la matriz
de adyacencia el bucle mientras se sustituye por:

for K:= 1 to N do { Nmero de vrtices}


begin

Qsacar(V,Q) ;
write(V:2,' ');
for W:=l to N do { busca adyacentes}
if G.A[V,W]<> O then { W es adyacente de V}


Algoritmos fundamentales con grafos 459

begin
Grd[W] : = Grd[W]-l;
if Gr d[W ] = O then
Qp o ner(W, Q)
end
end;

y en este caso el tiempo de ejecucin es de O (n 2 ).

14.2. MATRIZ DE CAMINOS: ALGORITMO DE WARSHALL


El mtodo de calcular las sucesivas potencias de la matriz de adyacencia para as deter-
minar la matiz de caminos es poco eficiente. Warshall propuso un algoritmo ms eficien-
te para calcular la matriz de caminos (tambin llamado cierre transitivo).
Tenemos un grafo G de n vrtices representado por su matriz de adyacencia A. Que-
remos encontrar la matriz de caminos P del grafo G. Para explicar el algoritmo se define
una secuencia de matrices n-cuadradas de O y 1 Po, P., P 2, P3 , Pn; los elementos de
cada una de las matrices Pk[i,j] tienen el valor O si no hay camino, 1 si hay camino del
vrtice i y alj. La diferencia entre P k y Pk- , radica en la incorporacin del vrtice k para
poder formar el camino del vrtice i y al j. Lo describimos con ms detalle:

Po[i,j] = 1 si hay un arco de i aj.


O en otro caso.
P,[i,j] = 1 si hay un camino simple de Vi a vj que no pasa por ningn otro vrtice

a no ser por el vrtice l.
O en otro caso.
P2 [i,j] = 1 si hay un camino simple de Vi a vj que no pasa por otro vrtice a no
ser por los que estn comprendidos entre los vrtices 1 .. 2.
O en otro caso.
.
, P3 [i,j] = 1 si hay un camino simple de Vi a vj que no pasa por otro vrtice a no
ser por los que estn comprendidos entre los vrtices 1 .. 3.

O en otro caso.

Observamos que en cada paso se incorpora un nuevo vrtice, el que coincide con el

,
ndice de P, a los anteriores para poder formar camino.

Pk[i,j] = 1 si hay un camino simple de Vi a vj que no pasa por otro vrtice a no


.
ser por los que estn comprendidos entre los vrtices 1 .. k .
O en otro caso.
Pn[i,j] = 1 si hay un camino simple de Vi a vj que no pasa por otro vrtice a no
ser por los que estn comprendidos entre los vrtices 1 .. n; en defini-
tiva en el camino puede estar cualquier vrtice.
O en otro caso.
460 Estructura de datos

Segn estas definiciones, Po es la matriz de adyacencia A del grafo. Y al ser un grafo


de n vrtices la matriz Pn es la matriz de caminos.
Warshall encontr la siguiente relacin entre los elementos de la matriz Pk y los ele-
mentos de la matriz P k_ 1: para que cualquier elemento Pk[i,j] = l ha de ocurrir uno de
estos dos casos:

l. Ya existe un camino simple de Vi a vj del que pueden formar parte los vrtices de
ndice l a k - 1(VI a Vk _ ); por tanto, el elemento de la matriz P k _ I [i,j] = l.
2. Hay un camino simple de Vi a Vk Y otro camino simple de Vk a vj de los que pueden
formar parte los vrtices de ndice 1 a k-I; por tanto, esto equivale a cumplirse

(P k - I [i,k] = 1) Y (P k - I [k,j] = 1)

Estos dos casos pueden representarse en la figura siguiente:

,... .............. .. ...... "


.. -- ...... .
,, , # .. # ......

,, , vk '' ,, ''
v'J '

, .
'

,, /
'
,
vJ'
,

.
,

,-
, .,
,,
v'I ~, vi
,, , ,. .
'

,, , , ,
...... .... , ,
........... .. .. .,' '. .... ........ ," '

Camino de Vi a Vi Camino de V, - Vk- y.J

En definitiva, Warshall encuentra una relacin entre la matriz P k _ I Y P k que


nos permite, partiendo de Po que es la matriz de adyacencia, encontrar Pn (matriz de
caminos) por sucesivas iteraciones.
La relacin para encontrar los elementos de Pk la podemos expresar como si fuera
una operacin lgica.

P k [i,j] = Pk _l[i,j] v (P k 1 [i,k] /\ P k - I [k,jD

Como nuestra matriz es de 0 .. 1, esta relacin la debemos expresar

Pdi,j] = Minimo [1, Pk-l[i,j] + (P k - I [i,k] * Pk - I [k,j])]

Se tiene un grafo G de n vrtices, representado por su matriz de adyacencia. El algo-


ritmo expresado en seudocdigo encuentra la matriz de caminos P.

{ Ini cializ ar P}
desde i <- 1 hasta n hacer
desde j <- 1 hasta n hacer
P [ i,j] <- A [ i , j )
fin desde
fin desde
,,,
Algoritmos fundamentales con grafos 461
,

{A con ti n u ac i n se ob t iene n las suces i vas mat ri ces Po, P" P" P, ... , Pn q ue
es la mat r iz de cami n os del gra f o}
desde k - 1 hasta n hacer
desde i <- 1 hasta n hacer
desde j<- 1 hasta n hacer
P[i,j] < - Minimo(l , P [ i,j]+(p[i,k ] *P[ k ,j ]))
fin desde
fin d es de
fin des d e
fin algor it mo

3
Se puede observar que la eficiencia del algoritmo es O (n ).

CODIFICACiN
El tipo de datos para representar la matriz de adyacencia es el ya utilizado
const
Maxv e r t= 20;
type
Indiceve r t = 1 .. Maxvert ; .,
MatAdcia = array [Indi ce vert , I n d i cevert ] of 0 . . 1
procedure Wars h all(A : MatAdc ia ;n: I ndicevert ; var P: Ma t Adc i a);
var i,j ,k: in d i cevert;
function Mi nimo (x, y: i n teger) : in t ege r ;
begin
if y < x then
Min imo := y
else
Mi nimo:= x
end;
begin
for i:= 1 to n do
for j := 1 to n do
P [ i ,j] : = A[i,j ] ;
{ }
, for k = 1 to n do
f
I for i := 1 to n do
,
j
for j := 1 to n do
P[i , j] : = Minimo(l , P[i,j ] + (p [i , k) *P[k , j)))
end;

,
14.3. PROBLEMA DE LOS CAMINOS MAS CORTOS
CON UN SOLO ORIGEN: ALGORITMO DE DIJKSTRA
Otro problema que se plantea con relativa frecuencia es determinar el camino ms corto
entre un par de vrtices. Se parte de un grafo dirigido y valorado (jactor de peso), por lo
I
que cada arco (v ,v) tiene asociado un coste cij ;::: O. De tal forma que el coste de un
k- I

!,

cammo V I ,V2 ... Vk es ,
1=
LI C + 1
'
Y lo que se pretende es encontrar el camino de VI a Vk de

coste mmlmo .
- -----
~
---------------------------------------------...

462 Estructura de datos

Otro problema que se plantea es determinar el camino de menor longitud de VI a Vk'


entendiendo como tal el que tenga menor nmero de arcos para ir de VI a Vk'
Un ejemplo del problema de los caminos ms cortos es el determinar la ruta que en
menor tiempo nos lleva desde un punto (nuestra casa, por ejemplo) a un conjunto de
centros de la ciudad. Los vrtices intermedios son paradas de Bus o Metro.

14.3.1. Algoritmo de la longitud del camino ms corto


La Figura 14.1 nos muestra un grafo dirigido sin factor de peso, ya que se desea encon-
trar la longitud del camino ms corto (menos arcos).
Se elige el vrtice VI como el vrtice desde el que se desea determinar la longitud de
camino ms corto al resto de los vrtices. El camino ms corto de VI a VI es obvio que
es O. A continuacin buscamos todos los vrtices cuya distancia de VI sea 1, stos son los
vrtices adyacentes de VI: V2' V4; en la Figura 14.1 estn marcados con 1. Los vrtices
cuya longitud de camino es 2 son aquellos adyacentes de V2 Y de V 4 , stos son V3, V 6 , Vs;
en la figura estn marcados con 2. Examinando los vrtices adyacentes a los anteriores,
V3 , V6 , Vs que son vs V7' V8' tenemos caminos de longitud 3; en la Figura 14.1 estn
marcados con 3.
La estrategia que se sigue es la de bsqueda en anchura. Para codificar este algorit-
mo se utiliza una tabla en la que cada elemento representa un vrtice y tiene tres infor-

maClOnes:

Alcanzado: estar a verdadero (true) si se ha pasado en el recorrido por el vrtice.


Distancia:
,
nmero de arcos desde el vrtice inicial al vrtice representado.
Ultimo: guarda el ltimo vrtice desde el que se alcanza el vrtice representado,
para as poder reconstruir el camino.

Inicialmente los valores de estos tres campos estarn a falso, 00 (excepto vrtice de
partida, que estar a cero) y O.

Figura 14.1. Grafo dirigido sin factor de peso.


Algoritmos fundamentales con grafos 463

Tambin se hace uso de una cola. Como primer paso, la cola contiene el vrtice de
partida (VI), que es el vrtice de longitud de camino O. A continuacin se saca el elemen-
to frente y aaden los vrtices adyacentes a l, que son los de longitud de camino l, y as
sucesivamente. La cola (primero en entrar primero en salir) nos garantiza que no se pro-
cesan vrtices de longitud de camino m + 1 hasta que no han sido procesados todos que
tienen longitud m.

CODIFICACiN
,
type
{tipos para r ep r ese n ta r l os vrt i ces y la matri z de adyace n cia}
Est ad o = record
Alcanz ad o: bo o lean;
Di s ta n c ia: integer ;
Ult im o : Ve rtice;
end;
Ta bla = array[l . . NumV ertl of Estado;

procedure Lo n g _ camino( var T: Tab l a ; s : Vertice ; A: Matadcia) ;


var
Dist : i n te ger;
V,W: Vertice;
Q : Co l a ;
procedure Inicia l (var T:T ab la;S: Vertice) ;
var v: integer;
begin
for v: = 1 to NumVert do
with T[v ] do
begin
Alcanz ad o:= fa l s e;
Distan ci a: = maxint; { representa el 00 }
if v = S then Distanc i a :=;
Ulti mo: =
end
end;
begin
I nicia l (T,S) ;
Qc rear ( Q) ;Qp oner(S ,Q ) ;
repeat
Qu itar(V,Q) ; { retira el vrt ice fr ente}
T[ V] .Alcanzado:=true;
{mete en la cola todos l os vrt i ces ady a centes de V no pr ocesados }
for W: = l to NumV ert do
if A[V,W ]<> O then { W e s adyacen te de V }
if T[W] .Di s tancia = maxi nt then {v r t i ce n o alca n za d o}
begin
T [W] . Dista ncia: = T [V] . Distancia+l;
T[W ] .U ltimo := V :
Qponer(W,Q)
end
until Qvac ia(Q)
end;
464 Estructura de datos

En el procedimiento podemos observar que el campo Alcanzado realmente no es


necesario. Si algunos vrtices no son alcanzables desde el vrtice de partida el campo
Oi s t anc i a queda con el valor max i n t; adems, una vez que un vrtice es procesado
no vuelve a entrar en la cola. Por consiguiente, podramos suprimir el campo Al can-
z ado aunque su mantenimiento nos permite un ms fcil seguimiento del algoritmo y
posterior proceso de la tabla T.
Examinando el algoritmo podemos estimar que el tiempo de ejecucin es O(n) del
bucle para meter en cola los vrtices adyacentes, como el bucle se ejecuta un mximo
2
de n veces, por lo que podemos estimar que el tiempo total es O(n ). Si el nmero de
arcos a fuera mucho menor que n2 y representando los arcos mediantes listas de adya-
cencia el tiempo de realizacin del procedimiento sera OCa + n), siendo a el nmero
de arcos.

Algoritmo del camino ms corto: algoritmo de Dijkstra


Tenemos un grafo dirigido G = (V,A) valorado y con factores de peso no negativos, uno
de los algoritmos ms sencillos y eficientes para determinar el camino ms corto des-
de un vrtice al resto de los vrtices del grafo es el algoritmo de Dijkstra. Este algorit-
mo es un tpico ejemplo de algoritmo vido, que resuelven los problemas en sucesivos
pasos, seleccionando en cada paso la solucin ms ptima en aras de resolver el problema.
Recordamos que al ser un grafo valorado cada arco (v, v) tiene asociado un cos-
k- l
te cij ~ O. De tal forma que el coste de un camino V,V2 ... Vk es L C,+ l'
~ 1

El algoritmo de Dijkstra en cada paso selecciona un vrtice v cuya distancia es des-


conocida, entre los que tiene la distancia ms corta al vrtice origen s, entonces el cami-'
no ms corto de s a v ya es conocido y marca el vrtice v como ya conocido. As, suce-
sivamente va marcando vrtices hasta que de todos los vrtices es conocida la distancia
mnima al origen s.
Veamos con ms detalle cmo realizar esta estrategia. En un conjunto F tenemos los
vrtices cuya distancia ms corta respecto al origen es ya conocida. En el vector D se
almacena la distancia ms corta (coste mnimo) desde el origen a cada vrtice del grafo.
Inicialmente, F contiene nicamente el origen s y los elementos de D, Di ,el coste de los
arcos (v"v); si no hay arco de s a i suponemos el coste oo. En cada paso se agrega algn
vrtice v de los que todava no estn en F, es decir, de V - F, que tenga el menor valor
D( v); adems se actualizan los valores D( w) para los vrtices w que todava no estn en
F: D(w) = mnimo [D(w), D(v) + c",w)' De esta manera ya conocemos que hay un camino
de s a v cuyo coste mnimo es D(v).
Para reconstruir el camino de coste mnimo que nos lleva de s a cada vrtice v
del grafo se almacena para cada vrtice el ltimo vrtice que hizo el coste mnimo.
Entonces asociado con cada vrtice tenemos dos campos, la distancia o coste mni-
mo y el ltimo vrtice que hizo el camino ms corto; esto nos lleva a definir un re-
gistro con esos dos estados y una tabla (como ya hicimos en el problema de longitud de
camino).

,
Algoritmos fundamentales con grafos 465

En la figura del ejemplo 14.2 tenemos un grafo dirigido valorado y queremos calcu-
lar el coste mnimo desde el vrtice 1 al resto de los vrtices siguiendo el algoritmo de
Dijkstra . .

EJEMPLO 14.2

Se tiene el grafo valorado dirigido:

La matriz de adyacencia con los pesos de los arcos y considerando el peso como 00

cuando no hay arco:

00 3 4 00 8 00

00 00 00 00 5 00

00 00 00 00 3 00
C= 00 00 00 00 00 00

00 00 00 7 00 3
00 00 00 2 00 00

Los valores que se van obteniendo en los sucesivos pasos estn representados en
forma tabular:

Paso F W DI2l D13) . . . D14) D(5) D(61

Inicial I 3 4 00 8 00

1 1,2 2 3 4 00 8 00

2 1,2,3 3 3 4 00 7 00

3 1,2,3,5 5 3 4 14 7 10
4 1,2,3 ,5,6 6 3 4 12 7 10
5 1,2,3,5 ,6,4 4 3 4 12 7 10

As por ejemplo, el camino mnimo de VI a V 6 es 10 y la secuencia de vrtices que


hacen el camino mnimo: VI - V ) - V s - V 6
466 Estructura de datos

CODIFICACiN
En la codificacin se supone que el vrtice origen es el de ndice l. Adems se tiene
como entrada la matriz de pesos la cual contiene el coste de cada arco, de no haber arco
i
contiene max i n t; {representa el oo}.
const
N = 15; { nmero de vrtices}
type
{tipos para representar los vrtices y matriz de adyacencia matriz de=
pe sos}
MatAdcia= array [ Indicevert, Indicevert] of integer ;
Estado=record
Distancia: integer;{Suponemos que el factor de peso es entero}
Ultimo : Verti ce;
end;
Tabla= array[l . . N ] of Estado;

procedure Dijkstra(var T :Tab la ; C :Ma tadcia) ;


{C la matriz de pe sos = A matriz de adyacencia}
type
ConjVert= set of 1 .. N;
var
I,V,W: IndiceVert;{1 .. N}
Todos,F: ConjVert ;

procedure Inicial(var T : Tabla) ;


var v: i nt ege r;
begin
for v: = 2 to N do
with T [ v] do
begin
Distancia:= C[l,v];
Ultimo:= 1
end
end;

function Minimo(T:Tabla;R:ConjVert) :IndiceVert;


var
J,V: IndiceVert;
Mx: integer;
,

begin

Mx:= maxint;
for J:= 2 to N do
if (J in R) and (Mx > .T[J] .Di sta nc ia) then
begin
V:= J ;
Mx: = T [J ] . Distancia
end;
Minimo:=V
end;
begin
F:= [1]; {Vrtice origen}
Todos: =[l. .N];
Inicial (T) ;
Algoritmos fundamentales con grafos 467

{N-l pasos pa ra se l e c ciona r los N- l v r t i ce s}


for r : = 1 to N- l do
begin
{Bs qued a de l v rt i c e d e men or dis tan ci a}
W: = Minimo( T, Todo s-F);
F:= F+[W] ;
{S e ac tu a lizan las Dist anci as pa ra los v rti ces r esta nt es}
for V : =2 to N do
if V in (Todos- F ) then
with T[V] do
if (T [W ] . Di stanc i a+ e [W , V] ) < Di st a nc i a) then
begin
Dis tan c i a := T [ W] .D ista nci a + C[W, V]);
Ul ti mo : = W
end
end
end

En cuanto al tiempo de ejecucin del algoritmo, enseguida deducimos que lleva un


2
tiempo de O(n ) debido a los dos bucles anidados de orden n. Ahora bien en el caso
de que el nmero de arcos a fuera mucho menor que n 2 puede mejorarse su ejecucin
representando el grafo con listas de adyacencia y organizando los vrtices no integrados
en F (Todos-F) con una cola (como en el algoritmo de Longitud de camino), entonces
puede obtenerse un tiempo de O(a log n).

14.4. PROBLEMA DE LOS CAMINOS S CORTOS


ENTRE TODOS LOS PARES DE VRTICES:
ALGORITMO DE FLOVD

En algunas aplicaciones puede resultar interesante detenninar el camino mnimo entre


todos los pares de vrtices de un grafo dirigido valorado. El problema podra resolverse
por medio del algoritmo de Dijkstra, aplicndolo a cada uno de los vrtices, pero hay
otra alternativa que es ms directa y es mediante el algoritmo de Floyd.
Sea G un grafo dirigido valorado, G = (V,A). Suponemos que los vrtices estn numera-
dos de 1 a N; la matriz de adyacencia A en este caso es la matriz de pesos, de tal forma
que todo arco (v,v) tiene asociado un peso cij; si no existe arco (v,v) suponemos que
cij= oo. Cada elemento de la diagonal se hace O.
Ahora se quiere encontrar la matriz D de NxN elementos tal que cada elemento Dij
sea el coste mnimo de los caminos de (v, vJ
El proceso que sigue el algoritmo de Floyd tiene los mismos pasos que el algoritmo
de Warshall para encontrar la matriz de caminos. Se genera iterativamente la secuencia
de matrices Do, DI, D2, , Dk , , Dn cuyos elementos tienen el significado:

,
Do[i,j] = e ij coste (peso) del arco de i a j.
00 si no hay arco.
'.
l.
-'

-
,
468 Estructura de datos

DI [i,j] = mnimo (Do[i,j], Do[i, 1] + D o[1,j]). Es decir, el menor de los costes entre
el anterior camino de i -? j Y la suma de los costes de caminos de i -? 1,
l-?j.

D 2 [i,j] = mnimo (DI[i,j], D I[i ,2]+ DI[2J]). Es decir, el menor de los costes entre el
,
,
anterior camino de i -? j Y la suma de los costes de caminos de i -? 2,
2 -? j.

En cada paso se incorpora un nuevo vrtice para ver si hace el camino


,
mnimo entre un par de vrtices.

mnimo (Dk-l[i,jJ, Dk_l[i,k] + Dk_l[k,j]). Es decir, el menor de los costes

Dk[i,j] =
entre el anterior camino de i -? j Y la suma de los costes de caminos de
,
i i -? k, k -? j.

De esta forma hasta llegar a la matriz Dn que ser la matriz de caminos mnimos del
grafo.

EJEMPLO 14.3

En la figura siguiente se tiene un grafo dirigido con factor de peso; aplicando los sucesi-
vos pasos del algoritmo de Floyd se llega a la matriz de caminos mnimos.
La matriz de pesos:
4

Las sucesivas matrices DI , D 2, D5 que es la matriz de caminos mnimos:

o 1 00 00 00

00 O 00 4 7
DI = 3 2 O 00 4 Al incorporar el vrtice 1 ha cambiado D I (4,2) ya que
6 O 2 C(4,1) + C(1,2) < C(4,2).
7 00

00 00 00 3 O

O 1 00 5 8

00 O 00 4 7 Al incorporar el vrtice 2 ha habido varios cambios.
D2 = 3 2 O 6 4 As ha ocurrido con DI(1,4):
6 7 00 O 2
00 00 00 3 O D I(1,2) + D I(2,4) < DI (1 ,4).
Algoritmos fundamentales con grafos 469

o 1 00 5 8
00 O 00 4 7
03 = 3 2 O 6 4 Al incorporar el vrtice 3 no ha habido cambios; al
6 7 00 O 2 vrtice 3 no llega ningn arco.
00 00 00 3 O

As se seguira para determinar 0 4 y 0 5 ,


Al igual que se ha hecho en el algoritmo de Oijkstra por cada vrtice se desea guar-
dar el ndice del ltimo vrtce que ha conseguido que el camino sea mnimo del Vi a vj ,
en caso de que el camino sea directo tiene un cero. Para ello se utiliza una matriz de
, .
vertlces.

CODIFICACiN
, ..
const
N ~ 15 ; {nmero de vrtices}
type
{tipos para representar l o s vrtices y matr i z de a dy ace n cia matr iz de=
pesos}
Ma t Adcia ~ array [Indicevert,I ndi c e ve rt] of intege r;
MatCmo~ array[In d ic evert, rn d ic eve r t ] of O .. N;
procedure Floyd(C: Ma tadcia ; var D: Matadcia ; var Tr : MatCmo) ;
var
i,j,k: integer;
begin
for i :~ 1 to n do
for j: ~ 1 to n do
begin
D[ i, j ] := C [i ,j ];
Tr [ i , j] : = O
end;
{El camino mnimo de un ve r tice a s mismo se consi d era cero}
for j:= 1 to n do
D[ j,j ] : = O;
for k = 1 to n do
for i = 1 to n do
for j:= 1 to n do
if (D[i,k]+D[ k, j])<D[ i, j ] then
begin
D [i ,j] :~ D [i, k ] + D [k, jl;
Tr [ i , j ] : = k
end
end;

14.4.1. Recuperacin de caminos


En la matriz Tr se ha guardado el ltimo vrtice que ha hecho el camino de coste mni-
mo del vrtice i al j. Para obtener la sucesin de vrtices que determinan el camino hay
que volver hacia atrs, y qu mejor forma de hacerlo que con llamadas recursivas .




i
470 Estructura de datos

El procedimiento Cami no recibe el par de vrtices y utiliza la matriz Tr como va-


riable global para no cargar el tiempo de ejecucin.

procedure Cami no(V i, Vj:lnd ic eVe r t) ;


var Vk : in teg er ;
begin
vk : = Tr[V i ,Vj ] ;
if v, <> o then
begin
Cam i no(Vi , Vk ) ;
wr i t e (Vk,' ' ) ;
Cam i no(Vk , Vj)
end
end;

14.5. CONCEPTO DEL FLUJO

La primera idea de flujo se obtiene del significado popular: forma de enviar objetos de
un lugar a otro.
Ejemplos de la vida diaria: entre los centros de produccin y los centros de distribu-
cin hay un flujo de mercancas. Entre los lugares de residencia y los centros de trabajo
se produce un flujo de personas. Un sistema de tuberas para transporte de agua, cada
arco es un tubo y el peso representa la capacidad de la tubera en Litros/Minuto y los
nodos son puntos de unin de los diversos tubos.
Esta es la idea intuitiva de flujo, ahora exponemos la formulacin matemtica de flujo:
Se llama flujo a una funcin Fij definida en A (arcos) que verifica las propiedades:

I. D >
rlj_ O V'(i, j) E A
2. I:,Fij-I,F'ji = O i E V, i :t:. S, i :t:. T
JEa. JE PI

a i == conjunto vrtices conectados con el vrtice i mediante arcos que salen de i.


Pi == conjunto vrtices conectados con el vrtice i mediante arcos que entran en i.
V es el conjunto de nodos.
S es el nodo inicial del flujo.

T es el nodo destino del flujo .

3. Fij ~ Uij V'(i, j) E A

Siendo Uij la capacidad del arco i,j.


La segunda condicin impone la conservacin de la cantidad total de flujo (ley de
Kirchofi). Las condiciones primera y tercera imponen la cota superior e inferior de los
valores del flujo.


_ - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - - -
......

Algoritmos fundamentales con grafos 471

14.5.1. Planteamiento del problema


Sobre una red de flujos pueden plantearse diversos problemas. As se puede desear maxi-
mizar la cantidad transportada desde un vrtice origen a un vrtice destino. Otro proble-
ma tpico es conocer el modo ms econmico de enviar una determinada cantidad de
objetos desde un origen a un destino en un sistema de distribucin.
Por consiguiente, un grafo con factor de peso, una red de flujo es una estructura ideal
para modelar estas situaciones.

EJEMPLO 14.4

Planificacin de rutas alternativas para circulacin en horas punta.

Supngase un punto de origen con fuerte trfico, por ejemplo una ciudad dOllnitorio,
y otro punto que representa el centro, zona comercial, de la gran ciudad. Entre ambos
puntos se pueden establecer diversas rutas de entrada, cada una de ellas con una capaci-
dad de trfico mxima, dato que es conocido y expresado en miles de vehculos por

10 6
2
5

5 4 B

Modelo de red viaria de trfico


2

6
6

hora. Un problema que se puede plantear es encontrar cul es el flujo mximo de vehcu-
los que pueden desplazarse desde el punto origen al destino en la hora punta, y conocer
cul ser el ndice de utilizacin de cada una de las rutas de entrada. Esto nos conduce a
un problema de optimizacin.


EJEMPLO 14.5

Consideremos un sistema de tuberas de transporte de agua; cada arco representa un


tubo y el factor de peso es la capacidad en litros/minuto. Los vrtices representan puntos
en los cuales las tuberas estn unidas y el agua es transportada de un tubo a otro.
Dos nodos, S y T, representan la fuente de emisin del agua y el punto de consumo,
respectivamente. Se desea maximizar la cantidad de agua que fluye desde el vrtice fuente
hasta su punto de consumo .


j
,

472 Estructura de datos

,
,

j
1
,
1

s 3 e Red de flujos j
5
5 6 ,1

4
B D
3

Los pesos representan la capacidad de cada tubera en litros/minutos.

14.5.2. Formulacin matemtica


Sea la red G = (V, A) con un nico vrtice S fuente y un nico sumidero T, donde aso-
ciado a cada arco (i, j) hay un nmero Uij que representa la capacidad mxima del
,

arco.
,
,
1

,
F(S, X)
~E V
= VI = F(X,
'6V
T)
I
!
,
I la cantidad de agua, trfico ... que sale del vrtice S es igual a la cantidad que entra
i, en el sumidero T, y esta cantidad es Vr.

, El problema del flujo mximo consiste en enviar la mayor cantidad posible de flujo

desde el vrtice fuente S al vrtice sumidero T.

Matemticamente, maximizar Fit


i ,t: I
,


sujeto a las condiciones (flujo que entra = flujo que sale): I/ij - LJ). =
. .
O; i..=S,i..=T
J J

O _ <
lO'"
rlJ _ T T"
vI) < (i, j) E A

La funcin objetivo es la suma de los flujos que llegan al vrtice sumidero. Es preci-
samente la cantidad que se desea hacer mxima. Esta funcin de flujo se denomina el
ptimo.

14.5.3. Algoritmo del aumento del flujo: algoritmo


de Ford y Fulkerson
Este es uno de los algoritmos ms sencillos y a la vez eficientes para determinar el flujo
mximo en una red, partiendo de un nodo fuente S y teniendo como destino el nodo
sumidero T.
Algoritmos fundamentales con grafos 473

La idea bsica de algoritmo es partir de una funcin de flujo , flujo cero, e iterativa-
mente ir mejorando el flujo. La mejora se da en la medida que el flujo de S hasta T
aumenta, teniendo en cuenta las condiciones que ha de cumplir la funcin de flujo en
lenguaje natural:

Flujo que entra a un nodo ha de ser igual al flujo que sale.


En todo momento el flujo no puede superar la capacidad del arco.

Los arcos de la red pueden clasificarse en tres categoras:

No modificable: arcos cuyo flujo no puede aumentarse ni disminuirse, por tener


capacidad cero o tener un coste prohibitivo.
Incrementable: arcos cuyo flujo puede aumentarse, transportan un flujo inferior a
su capacidad.
Reducible: arcos cuyo flujo puede ser reducido.

Con estas categoras podemos establecer las siguientes mejoras de la funcin de flu-
jo desde S a T:

l." Forma de mejora: encontrar un camino P del vrtice fuente S al sumidero T tal
que el flujo a travs de cada arco del camino (todos los arcos incrementables) no
supera a la capacidad:

F(Vi, Vj) ~ Ui,j V'(i, j) E P

Entonces el flujo se puede mejorar en las unidades:

Mnimo {(Ui,j - Fi,j), V'(i, j) E P}

2." Forma de mejora: encontrar un camino P' del sumidero T a la fuente S formado
por arcos reducibles, entonces es posible reducir el flujo de T a S y por tanto
aumentar en las mismas unidades de flujo de S a T en la cantidad:

Mnimo {Fi,j, V(i, j) E P' }

3." Forma de mejora: existe un camino PI desde S hasta algn nodo V con los arcos
incrementables, un camino P2 desde un nodo W hasta el sumidero T con arcos
incrementables, y un camino P3 desde W a V con flujo reducible. Entonces el
flujo a lo largo del camino W - V puede ser reducido y el flujo desde S a T
puede ser incrementado en las unidades de flujo igual al mnimo de estas dos
cantidades:

Mnimo {(Ui,j - Fi,j), V'(i, j) EPI, o bien, E P2}


Mnimo (Fi,j, V'(i,j) E P3}

Este mnimo se llama aumento de flujo mximo de la cadena. Acaba de aparecer


en este contexto de redes el concepto de cadena, conviene que establezcamos
una definicin.
474 Estructura de datos

Una cadena que une los vrtices Vi, Vj es una sucesin de arcos con origen
en el vrtice i y final en el vrtice j, tal que dos arcos sucesivos tienen un vrtice
comn, aunque no necesariamente el vrtice final de un arco es el inicial del
siguiente.
De manera ms escueta, una cadena, tambin llamada semicamino, desde
V a W es la secuencia de nodos V = Xl ' X2 , , Xn = W tal que para todo i,
l < =i < =nsecumpleque (X i - I ,X ;l o (Xi'X i - l ) es un arco.
De inmediato podemos afirmar que todo camino P de V a W es una cadena,
aunque no toda cadena es un camino. En el grafo de la figura siguiente encontra-
mos que una cadena de S a Tes:
S- A- B- D- T
A cualquier cadena de la red de S a T a la que se le pueda aplicar una de las
formas de mejora de flujo ser una cadena de aumento de flujo. El objetivo que
persigue el algoritmo de aumento de flujo es encontrar cadenas de aumento de
flujo en la red y aumentar el flujo en la cantidad determinada en los tres modos
expuestos. La solucin ptima se encuentra cuando ya no hay ms cadenas de
aumento de flujo.

14.5.4. Ejemplo de mejora de flujo


Considrese de nuevo la red de tuberas

5
4

2 3

los pesos de los arcos representan las capacidades en litros/minuto.


Existen los caminos Pl S-A-C-T, P2 S-B-D-T Y P3 S-A-D-T con arcos in-
crementables. Por el camino P 1 el flujo puede ser mejorado en 3 unidades, por el cami-
no P2 el flujo es mejorable en dos unidades. Una vez realizadas estas mejoras la funcin
de flujo queda:

,3
5,0 6,

4,2
3,2
2,2

Algoritmos fundamentales con grafos 475

Ahora en los arcos se ha representado la capacidad y el flujo actual. An puede ha-


cerse otra mejora por el camino P3 en 1 unidad. La funcin flujo quedar:

33
5,4
e
s
5,0

4,2 T

----~ 3,3
2,2

Como se observa de la fuente S salen 6 unidades de flujo que son las que llegan al
sumidero T.
Para que sirva de ejemplo de mejora de flujo por aumento de cadena, sea el siguiente
grafo en el que representamos la capacidad de cada arco:

x
4
3

5
T

4 4

La funcin de flujo queda con la mejora por caminos con arcos incrementables:

5,4

4,4

Ahora si el flujo de y a X es reducido, aumentando en las mismas unidades el de S a


Y, el flujo de entrada de x a T aumenta en dicha cantidad. Ha habido un aumento neto
del flujo de S a T. Expesndolo en trminos de cadena: hay un camino de S a Y con
arcos incrementables (4-0), un camino de X a Y con arcos reducibles (4) y un camino de
X a T con arcos incrementables (3-0); en definitiva, la cadena S - Y - X - T. El
aumento de flujo por la cadena es el valor mnimo entre arcos incrementables y reduci-
bles, que en este caso es 3 unidades. La funcin de flujo:
476 Estructura de datos

5,1

4,4

14.5.5. Esquema del algoritmo de aumento de flujo


Los pasos que sigue el algoritmo de aumento de flujo:

l. Parte de un flujo inicial, F ij = O. Determina arcos que son incrementables y los


que son reducibles. Marca el vrtice fuente S.
2. Repetir hasta que sea marcado el vrtice sumidero T, o bien no sea posible mar-
, ,.
car mas vertlces:
2.1. Si un vrtice i est marcado, existe el arco (i j ) y es tal que (i j) es
I I

arco incrementable, entonces marcar vrtice j.


2.2. Si un vrtice i est marcado, existe el arco (j i ) Y es tal que (j i) es
I I

un arco reducible, entonces marcar el vrtice j.


3. Si ha sido marcado el vrtice sumidero T, hemos obtenido una cadena de aumen-
to de flujo. Aumentar el flujo al mximo aumento de flujo permitido por la cade-
na. Actualizar los flujos de cada arco con las unidades de aumento. Borrar todas
las marcas, salvo la del vrtice s, y repetir a partir del paso 2.
4. Si no ha sido marcado el vrtice T , finalizar la aplicacin del algoritmo; no es
posible enviar ms flujo desde S hata T.

EJEMPLO 14.6

Dada la siguiente red, en la que los pesos de los arcos representan la capacidad y el

flujo actual, se aplican los pasos que propone el algoritmo de Ford-Fulckenson para
encontrar el flujo mximo.

3,0

4,

6,0 6,0
4,0

En una primera pasada se marcan los vrtices S, x, Y, T; todos los arcos


son incrementables, se tiene una cadena de aumento de flujo. El incremento de flu-
Algoritmos fundamentales con grafos 477

jo= Min{ (Cij- Fij) para todo arco de la cadena}, en esta cadena
es 4. Ahora se actualizan los flujos de cada arco con el valor 4.

3,0

4 5,0

6
6,0
4,0

En una segunda pasada se marcan los vrtices S, Z, Y, T; todos los arcos son incre-
mentables, se tiene una segunda cadena de aumento de flujo. El incremento de flu-
jO=Min{(Cij- Fij) para todo arco de la cadena},enestacadena
es 2. Se actualiza los flujos:

3,0
w
5,0

T
6,6
6,2
y
4,2

En una tercera pasada se marcan los vrtices S, Z, Y, x, W, T; los arcos (S, z ) ,


( Z , Y) son incrementables, el arco (X, Y) es reducible y los arcos (X, W), (W,
T) son incrementables; se tiene una tercera cadena de aumento de flujo. El incremento
.
I
, de flujo de la cadena es 2. Se actualizan los flujos:

3,2

5,2

6,
6,4
4,4

En esta red ya no es posible encontrar ms cadenas de aumento de flujo. Por tanto, el


flujo mximo que llega a T es 4 + 4 = 8; su solucin est representada en la figura
anterior.
.
478 Estructura de datos

El anlisis de la solucin proporciona informacin muy valiosa para valorar en qu


arcos conviene aumentar la capacidad para que aumente ms el flujo que llega a T.

14.5.6. Tipos de datos y pseudocdigo


Los procesos indicados anteriormente para encontrar el flujo mximo se detallan a con-
. .,
tmuaclOn:

inicio
I nicializar la funcin de flujo a cero en cada arco
Nocadena f- false
repetir
<En contrar una cad ena de S a T que incremente flujo hacia T en x>
si <No se puede encontrar cadena> entonces
Nocadena f- true
sino
<Aumentar flujo a cada n o do en la cadena en x>
fin_si
hasta Nocadena
fin

Los tipos de datos son aquellos necesarios para representar las acciones indicadas en
el algoritmo.
Para marcar un nodo, una vez que ste ha sido colocado en una cadena, utilizamos
el vector boolean Encadena, de tal forma que Encadena [nodo] indica si el nodo
est en la cadena que se est fOllllando o no. En el vector boolean Fin v i a un elemento
Fin v i a [nodo] indica si el nodo est al final de la cadena que se est formando.
Para obtener correctamente la secuencia de nodos que forman la cadena, el vector
Precede es tal que Precede [nodo] referencia al nodo precedente del nodo ndice
en la cadena de la que forma parte. El vector boolean Adelante es tal que Adelan-
te [nodo] es true si el arco es hacia adelante, hacia T; en definitiva, el arco (prece-
de [nodo] I nodo).
Las unidades de flujo acumuladas hasta un nodo se guardan en la posicin corres-
pondiente del vector Fl uj os.
La capacidad de un arco y su flujo actual se almacenan respectivamente en las posi-
ciones correspondientes de las matrices e, F: e [i j] Y F [i j ] .
I I

Ahora se pueden expresar con un poco mas de detalle el algoritmo de aumento de


flujo:
Inicio
Para todos los nodos:
Finvia[nodo ] f- false
Encadena[nodo ]f- false
{S , T son los nodos origen y sumidero }
Finvia[S]f- true
Encadena[S]f- true

mientras (no Encadena[T]) y (exista nd, ,Finvia[nd]) hacer


Finvia[nd] f- false
Algoritmos fundamentales con grafos 479

mientras exis t a nod o i" (no Encadena [i 1) y


(F[nd,i) < C[nd,i l )y Adyacente(nd,i) hacer
(arco(nd,i) es in c rement able}
Encade na[il , Fi nv i a [il, Adelante[il~ true
Precede [i 1 ~ n d
x ~ C [nd, i 1 - F [nd, i 1
{Almacena el mnim o de los arcos ... }
si Flujos[ndl < x entonces
Flujos [ i l< - Flu jos [ndl
sino
Flujos[il~ x
fin si
fin_mientras
( Ahora busca arco s ha cia S reduc ib l es )
mientras exista nodo i " (no Encade na[il y
F[ i ,nd l>O y Adyacente( i ,nd) hacer
{arco ( i,n d) es reducib le}
Encadena[i). F i nvi a [il~ true
Adelante[il~ fal se
Precede [i 1 ~ nd
si Flujos[ndl < F[ i ,ndl entonces
Flujos[i l ~ Fluj os [ ndl
sino

F l uj o s [i l ~ F[i,ndl

fin - si
fin mientras
fin mientras {te r min a bucle de bsq ueda d e cade na}
si En cadena [ Tl entonces
<Aumentar e l flujo en l os arco s de l a cade na >
sino
<El flujo ya es mximo >
fin_si
fin

14.5.7. Codificacin del algoritmo de flujo mximo: Ford-Fulkerson


En la unidad F 1 u j o encapsulamos los tipos de datos y los procedimientos que imple-
mentan el algoritmo de Ford-Fulkerson.

unit UnitFlux;
interface
const
Ma xnodos = 10;
type
Indexnodo = 1 .. Ma xnodos ;
Vn odos = array[I ndexnodol of Indexnodo;
Matr i z = array [Indexnodo , I ndexnod o l of integer;
Ve c t o r 10 gic o =array [ I nd e xn odo l of boo1ean;
procedure Impr i me ( F j: ma t riz ) ;
procedure Maxfluj o (Cap:Ma triz ; S , T :l ndex nod o ;
var Fj: Matriz; var Fj ototal:integer);
implementation
i. uses p rinter;
procedure Cadena (var Pred: Vnodos ; S,A: Indexnodo);
1
'J
o
o

480 Estructura de datos

var ,
Nd: Indexnodo;
begin
if A= S then
write(lst,' Cadena de aumento de flujo: ':40, S)
elee begin ,
o

Cadena(Pred, S, Pred[A]); o

,
wr i t e ( 1 s t , ' - - " A) ,
o

end ,o
,

'1
,
end; ,

1
procedure Imprime (Fj: Matriz); ,

,
var ,
;
Vi,Vj: Indexnodo; ,i,
begin ,~
,,
,
writeln (1st, 'Flujo de cada arco de la red':50);
'j
)
writeln (1st, 'Origen Arco, Final Arco, Flujo':55); ,1
for vi:= 1 to Maxnodos do
for Vj:= 1 to Maxnodos do 11
if Fj [Vi,Vj] <>0 then 00

writeln (1st, Vi:25,' ':14, vj,' ':11,Fj[Vi,Vj]) , 1


writeln(lst) ; 1,
writeln(lst)
end;

procedure Maxflujo;
var
pred,nd,i: Indexnodo;
x: integer;
Precede: Vnodos;
Flujo: array[Indexnodo] of integer;
Finvia,Adelante,Encadena: Vectorlogico;

function Alguno (Finvia :Vectorlogico): boolean;


{Busca si existe un nodo i que sea fin de va}
var
i: Indexnodo;
Encontrado: boolean;
begin
l' .
-- 1,
,
Encontrado:= false;
while (i<= Maxnodos) and not Encontrado do
if Finvia[i] then
Encontrado:=true
elee
i:=i+l;
Alguno:=Encontrado
end;

begin { inicio del procedo Maxflujo }


for nd:=l to Maxnodos do
for i:=l to Maxnodos do
Fj[nd,i]:=O;
Fjototal:=O;
repeat
{ tratamos de encontrar una va desde S a T }
for nd:=l to Maxnodos do

.,- .
,
Algoritmos fundamentales con grafos 481

begin
Finvia [nd] : =false;
Encadena [nd] : =false
end;
Finvia[S]:= true;
Encadena[S]:= true;
Flujo[S]:= maxint ; {mximo valor posible}
while (not Encadena[T]) and (Alguno(Finvia)) do
begin
nd:=l;
while not Finvia[nd] do {bsqueda del ltimo nodo en la
semicadena actual}
nd:=nd+l;
Finvia [nd] : = false;
for i:=l to Maxnodos do
begin
{La condicin de adyacentes es cierta en cuanto
Cap[nd,i]>O}
{Inspecciona si es arco incrementable}
if (Fj [nd,i]<Cap[nd,i]) and (not Encadena[i]) then
begin
Encadena[i] :=true;
Finvia[i] :=true;
Precede[i] :=nd;
Adelante[nd] :=true;
x:=Cap[nd,i]-Fj [nd,i];
if Flujo[nd]<x then
Flujo[i] :=Flujo[nd]
elee
Flujo[i] :=x
end;
{Ahora se trata la posibilidad de que sea un arco
hacia S, en vez de hacia T. En cuyo caso el arco
podra ser reducible}
{La condicin de adyacentes es cierta en cuanto
Fj[i,nd]>O}
if (Fj [i,nd]>O)and (not Encadena[i]) then
begin
Encadena [i] : =true;
Finvia[i] :=true;
Precede[i] :=nd;
Adelante [nd] : =false;
if Flujo[nd] <Fj [i,nd] then
,
Flujo[i] :=Flujo[nd]
, elee
,
,, Flujo[i] :=Fj [i,nd)
?
end
end {ltima sentencia del bucle for}
,,, end ; {ltima sentencia del bucle while}
,
if Encadena[T) then
{Ha sido encon~ada una cadena, puede aumentar el flujo en la
semiva(cadena) al sumidero T}
,
begin
x:= Flujo[T);
Fjototal:= Fjototal+x;
Algoritmos fundamentales con grafos 483

14.6. PROBLEMA DEL RBOL DE EXPANSiN


DE COSTE MNIMO
Este problema se aplica sobre grafos no dirigidos. Un grafo no dirigido G = (V, A) es un
conjunto finito de vrtices V y de arcos A. Cada arco est formado por un par no ordena-
do de vrtices.
Los grafos no dirigidos se emplean para modelar relaciones simtricas entre entes.
Los entes estn representados por los vrtices del grafo.

14.6.1. Definiciones
Red conectada: es una red tal, que cualquier par de vrtices pueden ser unidos me-
diante
,
un camino.
Arbol: en una red es un subconjunto G' del grafo G que es conectado y sin ciclos.
Los rboles tienen dos propiedades importantes:

1. Todo rbol de n vrtices contiene exactamente n-l arcos.


2. Si se aade un arco a un rbol, entonces resulta un ciclo.
,
Arbol de expansin: es un rbol que contiene a todos los vrtices de una red.
De esta ltima definicin concluimos que buscar un rbol de expansin de una red es
una forma de averiguar si la red es conectada.

b d

La figura anterior muestra un grafo no dirigido y su rbol de expansin. Segn el


rbol de expansin el grafo es una red conectada.

14.6.2. rboles de expansin de coste mnimo


Una de las aplicaciones tpicas de los rboles de expansin est en el diseo de redes de
comunicacin en todas sus vertientes.
Pensemos en los pueblos que forman parte del Ayuntamiento de Sigenza 1; cada par
de pueblos est conectado por un camino vecinal, el peso de un camino directo entre dos

, Pueblo de la provincia de Guadalajara (Espaa).

484 Estructura de datos

pueblos, un arco, viene dado por la distancia en kilmetros. Se quiere construir una red
de carriles-bicicleta de coste mnimo de tal forma que cada par de pueblos est comuni-
cado a un coste mnimo.
El planteamiento, dado un grafo no dirigido ponderado y conexo, encontrar el sub-
conjunto del grafo compuesto por todos los vrtices, con conexin entre cada par de
vrtices y sin ciclos, cuya suma de los costes de los arcos sea mnima. Hay que encontrar
el rbol de expansin de coste mnimo.

14.7. ALGORITMO DE PRIM Y KRUSKAL

El algoritmo de Prim para encontrar el rbol de expansin mnimo sigue la metodologa


de hacer en cada iteracin lo mejor que se puede hacer, esta metodologa se llama
algoritmo voraz.
El punto de partida es un grafo G = ( V , A) que es una red, siendo e ( i , j ) el peso
o coste asociado al arco (i ,j).
Supngase V = { 1 , 2 , 3, ... , n}, el algoritmo arranca asignando un vrtice
inicial al conjunto W, por ejemplo el vrtice l

w= { 1 }

A partir del vrtice inicial el rbol de expansin crece, aadiendo en cada iteracin otro
vrtice z de V - W tal que si u es un vrtice de W, el arco (u, z) es el ms corto. El
proceso termina cuando v = w.
Observamos que en todo momento el conjunto de nodos que forma w forman una
componente conexa sin ciclos.
Otra forma de expresar el algoritmo de Prim es que, partiendo de un vrtice inicial u,

tomar la arista menor (u, v) que no forme un ciclo, y as iterativamente ir tomando


,
! nuevos arcos de menor peso (u, v) sin formar ciclos y formando en todo momento una
!
, componente conexa.
El conjunto de vrtices de la Figura 14.2 V = {1, 2, 3, 4, 5, 6, 7, 8,
9, lO} parte de w= {1 }, el arco mnimo es (1, 2) , por lo que W = {1, 2}.

2
2 2 2 2

3 4 4
1 4 1
3 3
3 5 3

4 4

Figura 14.1. Grafo valorado y su rbol de expansin mnimo.


Algoritmos fundamentales con grafos 485

2
8 7

5 6 11 9 4

8 6

12
8 12
3
3
15

Figura 14.2. Grafo valorado conexo; representa una red telefnica.

El siguiente arco mnimo (2 4) , w= {1,


I 2 I 4 } . El algoritmo puede expresarse:

procedimiento Prim( G, T)
{ G : grafo
T : co nj u n to de arcos del rbo l de cos t e mnimo}
var

W: c onjunt o de vertlces;
u,w: vrti c es;
Inicio
T <- {}
V <- {lo .n }
u <- 1
W <- {u}
mientras W<> V hacer

<Encontrar v de V- W " (u ,v ) sea InlnlmO, siendo u E W>
W <- W+ {v}
T< - T+ {(u ,v )}
fin_mientras
fin_procedimiento

Para encontrar el arco de menor coste entre W y V-W en cada iteracin se utilizan
dos arrays:

Ma s _ Cerca, t al que Mas_Cer c a [il contiene e l vrtice de W de men or c o ste


re spec to e l v rti ce i de V-W.
Coste, tal q u e Co ste[ il cont iene e l co st e del ar co (i ,Ma s _Cerca[i l) .

En cada paso se revisa Cos t e para encontrar algn vrtice z de V -w que sea el ms
cercano a W. A continuacin se actualizan los arrays Mas_Cerca y Coste, teniendo
en cuenta que z ha sido aadido a W.
La implementacin del algoritmo en Pascal:
Algoritmos fundamentales con grafos 487

El algoritmo comienza con un grafo T con los mismos vrtices V pero sin arcos. Se
puede decir que cada vrtice es una componente conexa en s mismo.
Para construir componente conexas cada vez mayores, se examinan los arcos de A,
en orden creciente del coste. Si el arco conecta dos vrtices que se encuentran en dos
componentes conexas distintos, entonces se aade el arco a T. Se descartarn los arcos
si conectan dos vrtices contenidos en el mismo componente, ya que pueden provocar
un ciclo si se le aadiera al rbol de expansin para ese componente conexo. Cuando
todos los vrtices estn en un solo componente, T es un rbol de expansin de coste
mnimo del grafo G.
En el algoritmo siguiente se definen estos tipos de datos:
IndexNo d o= 1 . . n ;

Co n jVert= set of In dex Nodo ;


,
, Arco= record
, u , v : Ind exNodo ;
Coste : real

!
end;
ListArco s= array[ l . . n*n] of Arco ;
Li stCo n js= array[ l . . n] of Co n jVe rt;

procedure Kruskal (C : matr iz; var T : ListArcos ; var Ct : real) ;

var
Ar c os : Li stA r cos;
Co mpConx : Li s t Conjs ;
U , v ,
e_u , e_ v ,
Co mp_n : In dexNodo ;
Kn , Ka , K : in teger ;
Mi n _ Ar : Arco;

begin
Kn : = O ; {Nmer o de arcos e n T}
Ka : = O; {Nmer o de arcos de la matriz de costes C}
Ct := O ; { Coste del rbo l de expansin}
Inicia l (C , Arcos,Ka) ; {obtie n e l os Ka arcos en orde n crec i ente de costes }

for V : = 1 to n do
CompCo n x [v ]: = [ v ];
{Obtiene los n compone n tes conexos i ni ciales,
con cada v rti ce}
Comp _ n: = n; {Nmero de c o mponentes conexos}
K: = O;
while Co mp_n > 1 do
begin
K : = K+l;
Mi n Ar: = Arc os [ K] ; { Arco m nimo actu a l }
C_ u : = NumCompon(M i n _ Ar . u , Comp Conx); {Componente do nde se
encuentra el vrtice u de l arco mni mo}
C_ v : = NumCompon(Min_ Ar . v, CompCo nx ) ;
if C u<>C v then {Co n ecta dos compone n tes dist in tos}
begin
Ct := Ct + Mi n_ Ar. Cdste ;
wri te l n( ' Arco ', Mi n _ Ar .u,' - > ', Mi n_Ar . v) ;
Co mbina(C _ u , C_ v , CompConx) ; {Une co mponentes u y v . Nueva componente
qu e da en u }


488 Estructura de datos

Comp_n: = Co mp_n-1;
Kn:= Kn +1;
T [Kn ] := Mi n _ Ar
end
end
end;

14.8. CODIFICACiN.
, RBOL DE EXPANSiN
DE COSTE MINIMO

En la siguiente unidad encapsulamos los tipos de datos necesarios para realizar los algo-
ritmos que determinan el rbol de expansin mnimo. En esta unidad tambin quedan
incorporados los tipos para representar la matriz de adyacencia.

unit UniCa mno;


interface
const
Maxn o dos= 10 ;
n= Maxnodo s; {Para man t ener iden t if i cadores }
type
In d exnodo= 1 .. Maxnodos;
ConjVe rt= set of IndexNodo;
Ar c o = record
u, v: Ind e xNodo;
Coste: real
end;
ListArcos= array[l . . n*n] of Arco;
ListConjs= array[l . . n] of Con jVer t;
Mat r iz = array [Indexnodo , Indexnodol of real;
procedure Pri m ( e : Matriz; var Ct : rea l) ;
procedure Kruska l (C: Matri z ; var T : ListArcos; var Ct : rea l );
procedure Ini c ial(C: Ma t riz; var T: Li s tArc o s; var Ka: int e ge r );
procedure Combina(Cu , Cv: In de xnodo; var Cx : ListC o n j s);
function Num Compon(v : Indexnodo; Cx:listConjs): in t eger ;

implementation
procedure Ordena_ Rapid o ( var Lars: ListArcos; K: i n teger);
procedure Sort (iz,de : in t eger);
var
i, p: integer;
X, W: Arco;
begin

1: = 12;
p:=de ;
X:=Lars[ ( iz+de ) div 2 ];
repeat
while Lars[i].Coste < X .Coste do
i:=i+l;
while x.C o ste < Lars[p] .Coste do
p:=p-l;
if i < = p then
Algoritmos fundamentales con grafos 489

begin
W:= Lars[i];
Lars [i]: = Lars [p];
Lars [p] : = W;
i:= i+l
p: = p-1
end
until i > p;
if iz < p then Sort (iz,p);
if i < de then Sort (i,de);
end;
begin
Sort (1, K)
end;

procedure Inicia1(C: Matriz; var T: ListArcos; var Ka: integer);


{De la matriz de costes, obtiene los arcos en orden ascendente de peso}
var
J,I: Indexnodo;
begin
{Primero son almacenados los arcos.
Para despus ordenarlos segn el coste}
Ka: = O;
for 1:= 1 to n do
for J:= 1 to n do
if C[I,J]<> O then { arco <i,j> }
begin
Ka:= Ka+1;
with T[Ka] do
begin
.- 1 ;
u-
. - J;
v-
Coste:= C[I,J]
,
end
, end;
Ordena_Rapido(T, Ka)
end;

procedure Combina(Cu,Cv: Indexnodo; var Cx: ListConjs);


, ',' {Une las componentes conexas Cu, Cv. La unin queda en la posicin
Cu; la componente de la posicin Cv queda vaca}
begin
Cx[Cu]:= Cx[Cu]+Cx[Cv];
Cx[Cv]:= []
end;

function NumCompon(v: Indexnodo; Cx: ListConjs): integer;


{Obtiene el nmero de componente donde se encuentra el vrtice v}
var
Nc: integer;
Comx: boolean;
begin
{El nmero de componentes es n, aunque puede haber componentes vacas}
Nc:= O;
Comx:= false;
490 Estructura de datos

while (Nc< N ) and Not Comx do


begin
Nc:= Nc+1;
Comx:= v in Cx[N c ]
end;
if Comx then
NumCompon: = Nc
elae
NumCompon := O
end;

procedure Prim (C: Matriz; var Ct: rea 1 ) ;


C : Matriz de adyacencia . s i n o e x is te ar co (i, j) , Cij tiene
e l valor infinito.
Ct: Coste del rbo l de expansin mn imo}
var
Coste: array [ l . . n ] of real;
Mas _ Cerca : array[l .. n] of integer ;
i , j : in tege r;
z : Indexnod o;
Min : real;
W : ConjVert;
begin
Ct:= O;
{Vrtice ini cia l es e l 1}
W: = [1);
for i:= 2 to n do

begin
; Coste[i] := C [ l ,i ] ; {Inicialmente coste de cad a vrtic e de V- el]
es el arco (l,i)}
Mas_Cerca [i] : = 1 {deb i do a que W= [1]}
end;
for i:= 2 to n do
begin
(Encuentra el vrtice z de V-W ms cercano(menor arco a a l gn
vrtice de W)}
Min:= Coste[2];
z:= 2;
for j := 3 to n do
if Coste [ j] < Min then
begin
Min:= Coste[j ] ;

z:= J
end;
Ct : = Ct+ Min;
{Escri be arco del rbol de expa nsi n}
writeln(z, ' -- ',Mas _ ce rca[z]);
{ El vrtice z es aadido a W }
Coste [z): = Infin ito ;
W:= W+[z ) ;
{Ajus ta l os costes de l resto de vrtices }
I
i, for j:=2 to n do
if (C [ z,j)< Coste [ j ] ) and not (j in W) then
begin
Coste[j]:= C[z,j];
Mas_Cerca [ j ] : = Z
492 Estructura de datos

Coso Matriz;
T: ListArcos;
NI, N2: Indexnod o ;
CosteTot: real;

procedure grafo(var M: Matriz);


var
NI, N2: Indexnodo;
Fchero:string;
F: t ext ;
begin
clrscr;
writeln( 'Archivo con datos de grafo con', n, 'Nodos') ;
readln(Fchero) ;
assign(F,Fchero) ;
{$I - }
reset (F) ;
{$I+}
if Ioresult<> O then
begin
writeln('Archivo no existe, o est en otra unidad') ;
Halt
end;
while not eof(F) do
, begin
readIn(F,NI,N2,M[NI,N2)) ;
M[N2,NI):= M[Nl,N2 ]
end;
end;

begin
{Los costes son inicializados a infinito}
for Nl:= 1 to Maxnodos do
for N2:= 1 to Maxnodos do
Cos[Nl,N2) :=Infinito;

{Los datos del grafo se encuentran en un archivo.


En el procedimien to grafo se carga la matriz de costes}
Grafo(Cos} ;
wr i te (' rbol de expans in de cos te mnimo, ');
writeln (' (Algoritmo de Prim) ');
writeln;
CosteTot:= O;
Prim(Cos, CosteTot);
~ . ~.

write('Coste del rbol de expanSlon mlnlmo: I ) ;

writeln(CosteTot:12:1} ;
repeat until keypressed;
writeln;

write ('rbol de expansin de coste ffilnl.ffiO,
I ) ;

writeln('(Algoritmo de Kruskal) ' ) ;


writeln;
CosteTot:= O;
Kruskal(Cos, T, CosteTot);
write('Coste del rbol de expansin mnimo: ');
,
writeln(CosteTot:12:1)
end.

Algoritmos fundamentales con grafos 493

RESUMEN
Si G es un grafo dirigido sin ciclos, entonces un orden topolgico de G es un listado secuencial
de todos los vrtices de G, tales que todos los vrtices V, W E G; si existe una arista desde Va W,
entonces V precede a Wen el listado secuencial. El tImino acclico se utiliza con frecuencia para
representar que un grafo no tiene ciclos.
La ordenacin topolgica es un recorrido solamente aplicable a grafos dirigidos acclicos,
que cumple con la propiedad de que un vrtice slo se visita si han sido visitados todos sin prede-
cesores dentro del grafo. En un orden topolgico, cada vrtice debe aparecer antes que todos los
vrtices que son sus sucesores en el grafo dirigido.
Dado un grafo G, una de las operaciones clave es la bsqueda de caminos mnimos que sean
lo ms cortos posible, donde la longitud de un camino, tambin conocida como coste, se define
como la suma de las etiquetas de las aristas que lo componen. Una caracterstica fundamental en
un algoritmo es encontrar la distancia mnima de un vrtice al resto y otro para encontrar la dis-
tancia mnima posible entre todo par de vrtices.
Uno de los problemas ms importantes es calcular el coste del camino mnimo desde un vrtice
al resto. Una de las soluciones ms eficiente a este problema es el denominado algoritmo de
Dijkstra. Asimismo, se trata de deteIlninar el coste del camino ms corto entre todo par de vrtices
de un grafo etiquetado y de esta manera se puede generalizar la situacin estudiada. Adems de
Dijkstra, se dispone del llamado algoritmo de Floyd, que proporciona una solucin ms compacta
y elegante.
Un rbol de expansin es un rbol que contiene a todos los vrtices de una red y es una forma
de averiguar si la red es conectada. Los algoritmos que resuelvan los rboles de expansin mnima
ms usuales son: algoritmo de Prim y algoritmo de Kruskal.

EJERCICIOS
14.1. Dada la siguiente red:

3
2

A D
4 1
9

encontrar una ordenacin topolgica.


14.2. En la red del ejercicio 14.1 los arcos representan actividades y el factor de peso representa
el tiempo necesario para realizar dicha actividad (un Pert). Cada vrtice v de la red repre-
senta el tiempo que tardan todas las actividades representadas por los arcos que teIlninan
en v. El ejercicio consiste en asignar a cada vrtice v de la red 14.1 el tiempo necesario
para que todas las actividades que teIlninan en v se puedan realizar, ste lo llamamos tn(v).
Una founa de hayarlo: asignar tiempo O a los vrtices sin predecesores; si a todos los


494 Estructura de datos

predecesores de un vrtice v se les ha asignado tiempo, entonces tn(v) es el mximo para


cada predecesor de la suma del tiempo del predecesor con el factor de peso del arco desde
ese predecesor hasta v.
14.3. Tomando de nuevo la red del ejercicio 14.1 y teniendo en cuenta el tiempo de cada vrtice
tn(v) calculado en 14.2, ahora queremos calcular el tiempo lmite en que todas las actividades
que terminan en el vrtice v pueden ser completadas sin atrasar la terminacin de todas las
actividades, a este tiempo lo llamamos t/(v). Para lo cual podemos proceder: asignar tn(v)
a todos los vrtices v sin sucesores. Si todos los sucesores de un vrtice v tienen tiempo
asignado, entonces t/(v) es el mnimo de entre todos los sucesores de la diferencia entre el
tiempo asignado al sucesor, tl(v'), y el factor de peso desde v hasta el sucesor v'.
14.4. Una ruta crtica de una red es un camino desde un vrtice que no tiene predecesores hasta
un vrtice que no tiene sucesores, tal que para todo vrtice v del camino se cumple que
tn(v) = t/(v). Encontrar las rutas crticas de la red del ejercicio 14.1.
14.5. Dado el grafo de la figura:

5
H K L

, 2 2

encontrar un rbol de expansin de coste mnimo con el algoritmo de Primo


14.6. Dado el grafo del ejercicio 14.5 , encontrar un rbol de expansin de coste mnimo con el
algoritmo de Kruskal.
14.7. En el grafo dirigido con factor de peso de la figura:

12
6

8
6 5
10 9
,
6

E
3
5

11

encontrar el camino ms corto desde el vrtice A a todos los dems vrtices del grafo.

,

,
i
Algoritmos fundamentales con grafos 495

14.8. En el grafo del ejercicio 14.7 encontrar el camino ms corto desde el vrtice D a todos
los dems vrtices del grafo siguiendo el algoritmo de Dijkstra. Incluir la ruta que for-
man los caminos.
14.9. En el grafo del ejercicio 14.7 encontrar los caminos ms cortos entre todos los pares de
vrtices. Para ello, seguir paso a paso el algoritmo de Floyd.
14.10. Dibujar un grafo dirigido con factor de peso en el que algn arco tenga factor de peso
negativo, de tal forma que al aplicar el algoritmo de Dijkstra para determinar los caminos
ms cortos desde un origen se obtenga un resultado errneo.
14.11. Con el algoritmo de Dijkstra se calculan los caminos mnimos desde un vrtice inicial a
los dems vertices del grafo. Escribe las modificaciones necesarias para que teniendo
como base el algoritmo de Dijkstra se calculen los caminos mnimos entre todos los
pares de vrtices. Cul es la eficiencia de este algoritmo?
14.12. El algoritmo de Prim o el algoritmo de Kruskal resuelven el problema de encontrar el
rbol de expansin de coste mnimo. La cuestin es: funcionan correctamente dichos
algoritmos si el factor de peso es negativo?
14.13. El algoritmo de Dijkstra no se puede aplicar a un grafo valorado en el que alguna arista
tiene un factor de peso negativo. El algoritmo de Bellman-Ford resuelve el problema
cuando hay aristas negativas, aunque no lo resuelve cuando hay ciclos en el grafo con
peso negativo. En caso de haber un ciclo con peso negativo el algoritmo lo indica y
telmina.
Sea G = (V,A) un grafo valorado de n vrtices, consideramos el vrtice origen el I y P la
matriz de pesos, el algoritmo de Bellman-Ford para hallar los caminos mnimos desde un
origen lo expresamos en seudocdigo:

I n icio
d es d e v r 2 h ast a n { n e s e l n mero de nodos } h a c er
d(v) r 00

f in_d esd e
s r 1
d (s ) r O { ma rc a el o rigen d e l c a mi n o }
d esd e i r 1 h as ta n - 1 { n es el n me ro d e n odos } hac e r
pa r a c ada ar is ta (u , v) E A h a ce r
si d(v) > d( u) + P(u,v ) entonces
d (v) r d(u) + P( u , v)
f in _ si
fin _ de s de
{ Prue ba de c i clos c o n p es o neg a t i vo }
,
par a ca da arista (u , v) E A ha cer
si d( v d ( u) + P (u, v) , en t on c e s
Error r t rue
fin s i
{ en e l array d estn l o s caminos m n i mos desde s a l os d e m s
vrtices si Error e s f a l s e }
Fi n

Demostrar el funcionamiento del algoritmo de Bellman-Ford dibujando dos grafos con


factor de peso, y alguna arista negativa. En uno de ellos ha de haber un ciclo con peso
negativo.
496 Estructura de datos

14.14. Determinar los vrtices que son puntos de articulacin en el grafo de la figura:

B J L

A E

14.15. Un circuito de Euler en un grafo dirigido es un ciclo en el cual toda arista es visitada
exactamente una vez. Se puede demostrar que un grafo dirigido tiene un circuito de Euler
si y solo si es fuertemente conexo y todo vrtice tiene iguales su grado de entrada y de
salida.
Dibujar un grafo dirigido en el que se pueda encontrar un circuito de Euler.

PROBLEMAS
14.1. Escribe un programa en el cual sea representado en memoria una red (un Pert: grafo dirigi-
do sin ciclos y factor de peso) mediante la matriz de adyacencia (matriz de pesos) y calcule:
El tiempo tn(v).
El tiempo tl(v).
Adems encuentre las rutas crticas de la red.
(Nota: vanse los ejercicios 14.2-14.4.)
14.2. Escribir un programa en el que dada una red (un Pert), representada en memoria mediante
listas de adyacencia, encuentre las rutas crticas.
14.3. Tenemos una red (un Pert) representada con su matriz de adyacencia. Escribir un programa
que calcule el mnimo tiempo en el que todo trabajo se puede terminar si tantas actividades
como sea posible son realizadas en paralelo. El programa debe de escribir el tiempo en el
que se inicia y se termina toda actividad en la red.
14.4. Escribir un programa para que dada una red (Pert) representada por su matriz de adyacen-
cia, determine el tiempo mnimo de realizacin del trabajo si como mximo se pueden
realizar n actividades (de las posibles) en paralelo. El programa debe mostrar el tiempo de
inicio y el de finalizacin de cada actividad.
14.5. Escribir un procedimiento para implementar el algoritmo de Dijkstra con esta modifica-
cin: en la bsqueda del camino mnimo desde el origen a cualquier vrtice puede haber
ms de un camino del mismo camino mnimo, entonces seleccionar aquel con el menor
nmero de arcos.
Algoritmos fundamentales con grafos 497

14.6. El algoritmo de Dijkstra resuelve el problema de hallar los caminos mnimos desde un
nico vrtice origen a los dems vrtices. Escribir un procedimiento para resolver el
problema de que dado un grafo G representado por su matriz de pesos encuentre los
caminos mnimos desde todo vrtice Va un mismo vrtice destino D.
14.7. Escribir un programa en el que dado un grafo valorado, teniendo ciertos factores de peso
negativos, representado en memoria mediante la matriz de pesos, determine los caminos
ms cortos desde el vrtice origen a los dems vrtices. Utilizar el algoritmo de Bellman-
Ford del ejercicio 14.13.
14.8. Dado un grafo no dirigido con factor de peso escribir un programa que tenga como entra-
da dicho grafo, lo represente en memoria y determine el rbol de expansin de coste
, .
maxlmo.
14.9. Un circuito de Euler en un grafo dirigido es un ciclo en el cual toda arista es visitada
exactamente una vez. Se puede demostrar que un grafo dirigido tiene un circuito de
Euler si y slo si es fuertemente conexo y todo vrtice tiene iguales sus grados
de entrada y de salida. Escribir un programa en el que se represente mediante listas de
adyacencia un grafo dirigido. Implemente un algoritmo para encontrar, si existe, un
circuito de Euler.
14.10. Un grafo est representado en memoria mediante listas de adyacencia. Escribir las ruti-
nas necesarias para determinar la matriz de caminos.
(Nota: Seguir la estrategia expuesta en el algoritmo de Warshall pero sin utilizar la ma-
triz de adyacencia.)
14.11. Se quiere escolarizar una zona rural compuesta de 4 poblaciones: Lupiana, Centenera,
Atanzn y Pinilla. Para ello se va a construir un centro escolar en la poblacin que mejor
coste de desplazamiento educativo tenga (mnimo de la funcin Z J

Z = L Pj di}; donde Pj es la poblacin escolar de la poblacin} y di} es la distancia mnima


del pueblo} al pueblo i.
Las distancias entre los pueblos en kilmetros:
Lup Cen Atn Pin
Lup 7 11 4
Cen 5 12

Atn 8
La poblacin escolar de cada pueblo: 28, 12, 24, 8, respectivamente de Lupiana, Cente-
nera, Atanzn y Pinilla.
Codificar un programa que tenga como entrada los datos expuestos y determine la pobla-
cin donde conviene situar el centro escolar.
14.12. Un grafo G representa una red de centros de distribucin. Cada centro dispone de una
serie de artculos y un stock de ellos, representado mediante una estructura lineal orde-
nada respecto al cdigo del artculo. Los centros estn conectados aunque no necesaria-
mente bidireccionalmente.
Escribir un programa en el que se represente el grafo como un grafo dirigido ponderado
(el factor de peso que represente la distancia en kilmetros entre dos centros). En el
programa debe de estar la opcin de que un centro H no tenga el artculo z y lo requiera,

entonces el centro ms cercano que disponga de z se lo suministra.


14.13. Europa consta de n capitales de cada uno de sus estados, cada par de ciudades est co-
nectada o no por va area. En caso de estar conectadas (se entiende por vuelo directo) se
sabe las millas de la conexin y el precio del vuelo. Las conexiones no tienen por qu ser
bidireccionales, as puede haber vuelo Viena-Roma y no Roma-Viena.
498 Estructura de datos

Escribir un programa que represente la estructura expuesta y resuelva el problema: dis-


ponemos de una cantidad de dinero D, deseamos realizar un viaje entre dos capitales,
C I-C2, y queremos informacin sobre la ruta ms corta que se ajuste a nuestro bolsillo.
14.14. La ciudad dormitorio de Martufa est conectada a travs de una red de carreteras, que
pasa por poblaciones intermedias, con el centro de la gran ciudad. Cada conexin entre
dos nodos soporta un nmero mximo de vehculos a la hora. Escribir un programa para
simular la salida de vehculos de la ciudad dormitorio y llegada por las diversas conexio-
nes al centro de la ciudad. La entrada de datos ha de ser los nodos de que consta la red
(incluyendo ciudad-dormitorio y centro-ciudad) y la capacidad de cada conexin entre
dos nodos. El programa de calcular el mximo de vehculos/hora que pueden llegar al
centro y cmo se distribuyen por las distintas calzadas .






PARTE

i
--
"

CAPTULO

., ,
aCIOn, US mezca
- ."',{-'- ( "-:- . - ,'-.' '- ,
,' "
.. -
- - ., r,
!

. ,,' , ,-. -" "",- :-:c::,-:,.-.
-,,-~---,- --- - >
.
",,, . "',",", " ' ,"
~
"
,

. .'
,,

'- --

CONTENIDO

15.1. Introduccin.
15.2. Ordenacin.
15.3. Ordenacin por burbuja.
15.4. Ordenacin por seleccin.
15.5. Ordenacin por insercin.
15.6. Ordenacin Shell.
15.7. Ordenacin rpida (quicksort).
15.8. Ordenacin por mezcla (mergesort).
15.9. Ordenacin Heapsort.
15.10. Ordenacin Binsort.
15.11. Ordenacin Radix Sort.
15.12. Bsqueda lineal.
15.13. Bsqueda binaria.
15.14. Bsqueda binaria recursiva.
15.15. Mezcla.
RESUMEN.
,
EJERCICIOS.
PROBLEMAS. ,

Las computadoras emplean gran parte de su tiempo en operaciones de


ordenacin, de bsqueda y de mezcla. Los arrays (vectores y tablas) se
utilizan con mucha frecuencia para almacenar datos, por ello los algo-
ritmos para el diseo de estas operaciones son fundamentales y se de-
nominan a las operaciones internas, debido a que los arrays guardan
sus datos de modo temporal en memoria interna y desaparecen cuando
se apaga la computadora.
Los mtodos de ordenacin, bsqueda y mezcla son numerosos; en
este captulo se consideran algunos de los ms eficientes. Su importan-
cia reside en el hecho de que su anlisis y algoritmos servirn tambin,
en gran medida, para realizar las mismas operaciones con registros,
archivos y estructuras dinmicas de datos.

501

,
,

502 Estructura de datos


15.1. INTRODUCCION
Tres operaciones muy importantes en programacin de computadoras son: ordenacin,
bsqueda y mezcla; son esenciales para un gran nmero de programas de proceso de
datos y se estima que en estas operaciones las computadoras por trmino medio gastan
gran parte de su tiempo. La bsqueda, ordenacin y mezcla son tambin procesos que
las personas se encuentran normalmente en sus vidas diarias. Considrese, por ejemplo,
el proceso de encontrar una palabra en un diccionario o un nombre en una gua o listado
de telfonos. La bsqueda de un elemento especfico se simplifica considerablemente
por el hecho de que las palabras en el diccionario y los nombres en la gua telefnica
i estn ordenados o clasificados en orden alfabtico. Asimismo, la operacin de mezclar
datos de dos listas o conjuntos de datos en una sola lista suele ser una operacin frecuente.
En este captulo se estudian los mtodos ms usuales de ordenacin, bsqueda y
mezcla, relativos a listas o vectores (arrays), ya que si bien estas operaciones se aplican
sobre otras estructuras de datos como registros o archivos, su mayor aplicacin est casi
siempre asociada a los vectores, y, por otra parte, la comprensin de los algoritmos en
vectores extrapolables a otras estructuras' es ms fcil.


15.2. ORDENACION
La ordenacin o clasificacin de datos (sort en ingls) es una operacin consistente en
disponer un conjunto estructura de datos en algn determinado orden con respecto
a uno de los campos de elementos del conjunto. Por ejemplo, cada elemento del conjun-
to de datos de una gua telefnica tiene un campo nombre, un campo direccin y un
campo nmero de telfono; la gua telefnica est dispuesta en orden alfabtico de nom-
bres. Los elementos numricos se pueden ordenar en orden creciente o decreciente de
acuerdo al valor numrico del elemento. En terminologa de ordenacin, el elemento por
el cual est ordenado un conjunto de datos (o se est buscando) se denomina clave.
Una coleccin de datos (estructura) puede ser almacenada en un archivo , un array
(vector atabla), un array de registros, una lista enlazada o un rbol. Cuando los datos
estn almacenados en un array, una lista enlazada o un rbol, se denomina ordenacin
interna. Si los datos estn almacenados en un archivo, el proceso de ordenacin se llama
ordenacin externa.
Una lista dice que est ordenada por la clave k si la lista est en orden ascendente o
descendente con respecto a esta clave. La lista se dice que est en orden ascendente si:
i < j implica que K[i] < = K[j]
y se dice que est en orden descendente si:
i > j implica que K[i] > = K(j]

, para todos los elementos de la lista. Por ejemplo, para una gua telefnica, la lista est



clasificada en orden ascendente por el campo clave k, donde k[i] es el nombre del abona-
do (apellidos, nombre).
Ordenacin, bsqueda y mezcla 503

4 5 14 21 32 45 orden ascendente
75 70 35 16 14 12 orden descendente
Zacar ias Ro drigue z Ma rt i ne z Lopez Ga rcia orden descendente

Los mtodos (algoritmos) de ordenacin son numerosos; por ello se debe prestar es-
pecial atencin en su eleccin. Cmo se sabe cul es el mejor algoritmo? La eficiencia
es el factor que mide la calidad y rendimiento de un algoritmo. En el caso de la operacin
de ordenacin, dos criterios se suelen seguir a la hora de decidir qu algoritmo de entre
los que resuelven la ordenacin es el ms eficiente: 1) tiempo menor de ejecucin en
computadora; 2) menor nmero de instrucciones. Sin embargo, no siempre es fcil efec-
tuar estas medidas: puede no disponerse de instrucciones para medida de tiempo aun-
que no sea ste el caso de Turbo Pascal ,y las instrucciones pueden variar, dependien-
do del lenguaje y del propio estilo del programador. Por esta razn, el mejor criterio para
medir la eficiencia de un algoritmo es aislar una operacin especfica clave en la ordena-
cin y contar el nmero de veces que se realiza. As, en el caso de los algoritmos de
ordenacin, se utilizar como medida de su eficiencia el nmero de comparaciones entre
elementos efectuados. El algoritmo de ordenacin A ser ms eficiente que el B, si re-
quiere menor nmero de comparaciones. As, en el caso de ordenar los elementos de un
. vector, el nmero de comparaciones ser funcin del nmero de elementos (n) del vector
(array). Por consiguiente, se puede expresar el nmero de comparaciones en trminos de
n (por ejemplo, n + 4), o bien n en lugar de nmeros enteros (por ejemplo, 325).
2

En todos los mtodos de este captulo, normalmente para comodidad del lector'-
se utiliza el orden ascendente sobre vectores o listas (arrays unidimensionales).
Los mtodos de ordenacin se suelen dividir en dos grandes grupos:
.

directos burbuja, seleccin, insercin


indirectos (avanzados) Shell, ordenacin rpida, ordenacin por mezcla
En el caso de listas pequeas, los mtodos directos se muestran eficientes, sobre todo
porque los algoritmos son sencillos; su uso es muy frecuente. Sin embargo, en listas gran-
des, estos mtodos se muestran ineficaces y es preciso recurrir a los mtodos avanzados.

15.3. ORDENACiN POR BURBUJA


Este mtodo es clsico y muy sencillo, aunque por desgracia poco eficiente. La ordenacin
por burbuja (<<buble sort) se basa en comparar elementos adyacentes de la lista (vec-
tor) e intercambiar sus valores si estn desordenados. De este modo se dice que los valo-
res ms pequeos burbujean hacia la parte superior de la lista (hacia el primer elemen-
to), mientras que los valores ms grandes se hunden hacia el fondo de la lista.
Consideremos, como ya se ha expuesto, clasificaciones en orden creciente.
,

, 15.3.1. Anlisis
..
,
. ..
,
Supongamos un vector A[!], A[2], .oo, A[n]. Se comienza el seguimiento del vector de
,
'-

,,
,,

izquierda a derecha, comparando A(1] con A[2]; si estn desordenados, se intercambian


,..~
,.
,,!
,,..
..
504 Estructura de datos

entre s. A continuacin se compara A[2] con A[3], intercambindolos si estn desorde-


nados. Este proceso de comparaciones e intercambios contina a lo largo de toda la lista.
Estas operaciones constituyen una pasada a travs de la lista. Al terminar esta pasada el
elemento mayor est en la parte inferior de la lista y alguno de los elementos ms peque-
os ha burbujeado hacia arriba de la lista. Se vuelve a explorar de nuevo la lista, compa-
rando elementos consecutivos e intercambindolos cuando estn desordenados, pero esta

vez el elemento mayor no se compara, ya que se encuentra en su posicin correcta. Se ,,


I siguen las comparaciones hasta que toda la lista est ordenada, cosa que suceder cuan-

l do se hayan realizado (n - 1) pasadas. Para su mejor comprensin, veamos grficamente


! el proceso anterior con un vector (lista) de cinco elementos: A[ 1], A[2], A[3], A[ 4], A[5].

A(1) 23 15

A(2) 19 19

, A(3) 45 23
I

A(4) 31 31

A(5) 15 44

Lista sin ordenar Lista ordenada

,

En la lista A, i ser el nmero de la pasada y j indica el orden del elemento de la lista.
Se comenzar en el elemento j-simo y el (j + l)-simo.

!,
,
;
I

Pasada 1: i = 1

A[1) 23 19 19 19 19

A[2) 23 1.--, 23 23 23

A[3) 45 45 45 31 31

A[4] 31 31 31 45 15
Elemento
A(5) 15 15 15 15 45 ordenado

j= 1 j=2 j= 3 j=4
Comparacin 1 Comparacin 2 Comparacin 3 Comparacin 4
Ordenacin, bsqueda y mezcla 505

Se han realizado cuatro comparaciones (5 - 1 o bien n - 1, en el caso de n elementos)


y tres intercambios (rotulados por el smbolo tn.
Pasada 2: i = 2

A[1] 19 19 19 19 19

A[2] 23 I.h 23 23 23

A[3] 31 31 31 15 15

A[4] 15 15 15 31 31
Elemento
A[5] 45 45 45 45 45 ordenado

j= 1 j = 2 j=3 j=4
Comparacin 1 Comparacin 2 Comparacin 3 Comparacin 4

Pasada 3: i = 3
19 19 19 19 19

23 23 15 15 15

15 15 23 23 23

31 31 31 31 31

45 45 45 45 45

Pasada 4: i = 4
19 15 15 15 15

15 19 19 19 19

23 23 23 23 23

31 31 31 31 31

45 45 45 45 45

Se observa que se necesitan cuatro pasadas para ordenar una lista de nmeros de
cinco elementos, por lo que una lista de n elementos necesitar n-l pasadas. El proceso
se describe as:

506 Estructura de datos

l. Realizar cuatro pasadas por la lista: i = 1,2,3,4.


2. Para la pasada 1 (i = 1) se realizan comparaciones (j = 1,2,3,4). A[l] con A[2],
A[2] con A[3], etc.
3. Para la pasada 2 (i = 2) se realizan 3 comparaciones (j = 1,2,3).
4. Para la pasada 3 (i = 3) se realizan 2 comparaciones (j = 1,2).
5. Para la pasada 4 (i = 4) se realizan 1(5-4) comparaciones (j = 1):

El nmero de pasadas (4 o bien n - 1) se puede controlar con un bucle f or, y cada


secuencia de comparaciones se puede controlar con un bucle for anidado al bucle de
pasadas, en el que j vara desde 1 hasta 5 menos el valor especfico de i

bucle externo i 1=1 j=1, 2 , 3 ,4 5 - i =4 bucle interno ( n- i )


i =2 j =1 , 2,3 5 - i =3
i =3 j = 1 ,2 5- i= 2
i= 4 j =1 5 -1 =1

Por consiguiente, el bucle for que controla cada pasada ser:

for j = 1 to 5 -i

I
Algoritmo (pseudocdigo)
desde i r-1 hasta n - 1 hacer
desde j r- 1 hasta n - i hacer
si A[j ] > A[j+1 ]
entonces Inter ca mbio (A[j] , A[ j+1])
fin-si
fin_desde {bu cle j }
fin_desde {bucl e i }

La operacin de intercambio se realiza con las instrucciones

Aux r- A [ j]
A [j ] r- A [ j+1 ]
A [ j+1] Aux

o mejor modularizando esta operacin con un procedimiento Intercambio que recibe


como parmetro de entrada los dos valores a intercambiar y devuelve al procedimiento

llamador los dos valores ya intercambiados como parmetros de salida.

procedure In tercambi o (var A , B ; int eger) ;


var
Aux : integer;
begin
Aux -- A ,
A -
- B ,
B -
- Au x
end;

1
Ordenacin, bsqueda y mezcla 507

15.3.2. Procedimientos de ordenacin

Mtodo 1
procedure burbu ja 1 (var A : List a ; N : int eger);
{o rden ar A[l] , ... ,A[N] e n orden ascen dent e
Lista en un array u ni d i mensio n a l d e fin i do en e l programa p rin cipal d e N
eleme n tos d e tipo e n te r o}
var
r, J, Aux : inte ger;
begin
for I : = 1 to N -1 do
for J := 1 to N - I do
if A[J ] > A [J+ 1] then
begin { i n te rcambio de n t ro de l programa }
Aux : = A [ J ];
A [J ] : = A [ J +l]
A[J+1] : = Au x
end; {f in de los buc le s for }
end; {Bu r bu j a l}

Mtodo 2
procedure Burbuja1 (var A : Li sta ; N : int eger) ;
var
r , J : intege r;
procedure Inter c ambio (var X, Y : i n teger);
var
Aux : integer;
begin
Aux - X;
X - Y;

-
y Au x
end;

begin
for I := 1 to N-l do
for J : = 1 to N-I do
if A [ J ] > A [J+l ] then
Intercamb i o (A [ J ] , A [ J+l ] )
end; {Bu r bu j a l }

15.3.3. Algoritmo de burbuja mejorado (refinamiento)


La tcnica de ordenacin por burbuja compara elementos consecutivos de la lista, de
modo que si en una pasada no ocurrieran intercambios, significara que la lista est orde-
nada. El algoritmo burbuja se puede mejorar si disponemos de algn tipo de indicador

que registre si se han producido intercambios en la pasada. Cuando se explore la lista y
el indicador no refleje intercambios, la lista estar ya ordenada y se terminarn las com- ,i

paraClOnes.
508 Estructura de datos

El indicador ser una variable lgica NoIntercambio (o bien ordenado) que se


inicializa a verdadero (true) (significa que la lista a priori est ordenada). Si dos ele-
mentos se intercambian en una pasada, NoIntercambio se pone aJalse. Al principio
de cada pasada NoIntercambio se fija a true y se pone aJalse si se producen inter-
cambios. El bucle externo for se sustituye por un bucle repeat-until o bien while-do y
un contador i se necesitar para contar el nmero de pasadas.

Pseudocdigo BurbujaMejorado
i f- 1
repetir
NoIntercambio f- true
desde j f- 1 hasta n-i hacer
si A[jl > A [j+1l
1 entonces Intercambio (A[j], A[j+ll)
!
I NoIntercambio f- false
fin si
fin desde
, i f- i+1
,
hasta_que Nolntercambio = true
,

,
1
15.3.4. Programacin completa de ordenacin por burbuja
Se genera aleatoriamente una lista de 100 nmeros enteros (o bien se leen de un archivo de
entrada: teclado o disco) y se desea escribir un programa que realice las siguientes tareas:
l. Leer lista de nmeros aleatorios.
2. Visualizar lista.
3. Ordenar lista por burbuja.
4. Visualizar lista ordenada.
1
El procedimiento Leer sirve para introducir la lista de 100 nmeros; el procedi-
miento visualizar permite imprimir cualquier lista, en este caso tanto la lista orde-
nada como desordenada; y el procedimiento Ordenar clasifica la lista A.
i

program OrdenarBurbuja;
{Ordenacin ascendente por el mtodo de la burbuja}
const
Limite = 100;
type
Item = integer;
rango - O.. Limite;
Lista = array [Rangol of Item;
var
ListaItem : Lista;
Numitems : integer;
procedure Leer (var A: Lista; N: integer);
var
1 : integer;
begin
for 1 := 1 to N do
A [1] : = Random (10 OO)
end;

,,
.,

Ordenacin, bsqueda y mezcla 509

procedure Esc r ib ir (var A : L is t a ; N : integer) ;


var
I : integer ;
begin
for I : = 1 to N do
Write (A[I] : 4);
Wr i t e Ln
end;

procedure Burbu j a (var A : L i sta ; N : i nteger) ;


var
1, J : i n te ge r;
(p r oced i mi e n to de i nter cam bio )
procedure I n terca mbio (var A, B : i t e m) ;
var
Au x : item ;
begin
Aux -- A ,
A
- B ,
B
-- Aux
end;
begin
for I : = 1 to N- l do
for J:= I +1 to N do
i f A [ J - 1] > A [ J ] then
I n te r ca mbio (A [ J - l ) , A [ J))
end;

(programa p r inc i pal)


begin
Leer( List aItem, Limi te) ;
WriteLn ( 'La lista o ri g i na l es') ;
Escribir(Li staItem, L i mi te) ;
Burbuja(Lis taIt e m, Lim i te) ;
WriteLn ('La li sta ordenada es') ;
Escribir ( Li s t a I tem , Lim i te)
end.

15.3.5. Anlisis de la ordenacin por burbuja


Este algoritmo proporciona buen rendimiento en cuanto a su sencillez, pero por el
contrario su eficiencia es pobre. Para una lista de n elementos, el proceso de ordena-
cin requiere n - 1 pasadas y el nmero de comparaciones se refleja en la tabla si-
guiente:
Pasada Comparaciones i
l n- l
2 n- 2
3 n- 3

n- l 1
510 Estructura de datos

El nmero total de comparaciones es

1 + 2 + 3 +... + (n - 3) + (n - 2) + (n - 1) = - - - -(n 2 -n) ,



2 2

La funcin de eficiencia de rendimiento de un algoritmo se representa con la fun-


cin O(n), tambin llamada Notacin de O-grande. En el caso de la burbuja, en el peor ,.I
2
de los casos, el nmero de comparaciones es O(n ). 1

El algoritmo de burbuja es una ordenacin cuadrtica, lo que significa elevado n- .

mero de comparaciones y, por consiguiente, excesivo tiempo de ejecucin, o dicho de


!
1
otro modo: es un algoritm o lento. .
1


15.4. ORDENACION POR SELECCION

El algoritmo de ordenacin por seleccin de una lista (vector) de n elementos tiene los

siguientes pasos:

l. Encontrar el elemento mayor de la lista.


2. Intercambiar el elemento mayor con el elemento de subndice n (o bien si es el
elemento menor con el subndice 1).
3. A continuacin se busca el elemento mayor en la sublista de subndices 1.. n - 1,
Y se intercambia con el elemento de subndice n - 1; por consiguiente, se sita el
segundo elemento mayor en la posicin n - l.
4. A continuacin se busca el elemento mayor en la sublista 1.. n - 2, y as sucesi-
vamente.

Algoritmo

Desde j t- n hasta 2 [decremento - 1] hacer:


I
! Enc ont r a r el e lemento mayor e n e l array 1 ... j .
S i e l eleme nt o may o r n o e st e n e l s u b nd i c e j , entonces i nt e r ca mb i ar

e l emen t o ma y or co n e l d e s ub nd i ce i .

El algoritmo de PosMayor debe guardar j como la posicin del elemento mayor y


luego poder intercambiar.

program Or d e narSe l e cc i o n ;
{ l eer 1 00 e nt er os . Ord e nar . Vis u al i zar}
const
Li mi t e ~ 1 00;
type
Lis t a = array [1 . . Li mit e ) of i n te g er ;
Ordenacin, bsqueda y mezcla 511

var
1 , Num : 1 .. Lim ite ;
A : List a ;
function Pos Ma y o r (Ul timo :i nt e g er; var Tab la: Li s ta ) : in t eger ;
{encuen t r a el i ndi ce de l e l e me n t o mayo r e n la Tab l a [l .. Ul ti mo]}
var
I ndic e_Max , Ind i c e : 1 .. Limit e;
begin
I nd i ce _ max := 1;
for Indi ce := 2 to Ul timo do
if Tabla [I n d i ce ] > Tab l a [Indice _ Max]
then Ind i c e_Max := I ndice ;
Po s Ma yor : = Indic e_Max
end;
procedure Seleccion (Limi : i nteger ; var Tab l a : Li sta) ;
var
Aux, J , Mayo r : integer ;
begin
for J := Limi downto 2 do
begin
{enc o ntr a r e l Ele men t o mayor de 1 .. J}
Ma yo r : = Pos May or (J , Tab la);
{i n tercambio con el Eleme nt o Ta bl a [J ] }
Au x : = Tab l a [ Mayo r ] ;
Ta b la [Mayor] : = ta bl a [J ];
Ta b la [J] : = Aux

end
end;
{p r ogra ma pri nci pal}
begin
for 1 : = 1 to Li mi t e do
begin
A [1] : = Random (10 O) ;
Wr i t e (A [ I] : 4)
end;
WriteLn ;
Se l eccion (Limi te , A);
for I := 1 to Li mit e do
Write (A[I] : 4) ;
WriteLn
end.

Anlisis de la ordenacin por seleccin

Nmero de comparaciones por cada una de las pasadas.


Pasada Nmero de comparaciones
l n- 1
2 n-2
3 n-3

n- 1 1

512 Estructura de datos

El nmero total de comparaciones es


n'(n-l)_ 1 )
1 + 2 + 3 +... + n - 2 + n - 1 = 2 - 2(n--n)

La eficiencia, como se observa, es similar al mtodo de la burbuja.

, ,
15.5. ORDENACION POR INSERCION
Este mtodo est basado en la tcnica utilizada por los jugadores de cartas para cla-
sificar sus cartas. El jugador va colocando (insertando) cada carta en su posicin co-
rrecta.

tres cartas 2 6 10

cuatro cartas 2 6 10

cinco cartas 2 6 9 10

El mtodo se basa en considerar una parte de la lista ya ordenada y situar cada uno
de los elementos restantes insertndolo en el lugar que le corresponde por su valor, todos
los valores a la derecha se desplazan una posicin para dejar espacio.

Algoritmo
{para cada el emento de l a lista despu s del prim ero}
desde k f-- 2 hasta n hacer

Guardar el valor de ese elemen to A [k ] en una variab l e Aux.


Hacer espa c i o par a Aux despla z ando todos l os valores mayores que
dich o val or A[k] una pos i cin .
Inse rtar e l valo r de Aux en el l ugar de l lt imo valor de sp l azad o.

La operacin de desplazamiento se realiza con un procedimiento De splaza r, que


mueve todos los elementos de la lista mayores que Aux, comenzando con el elemento
de la lista de posicin Aux-l. Si Aux es el valor ms pequeo, la operacin de despla-
zamiento termina cuando un valor menor o igual a Aux se alcanza. Aux se inserta en la
posicin que ocupaba el ltimo valor que se desplaz.


Ordenacin, bsqueda y mezcla 513

Algoritmo de desplazamiento

mientras el primer elemento no se desp l aza


y valor de l elemen t o > Aux hacer
Desplaza r e l eme n to una posicin .
Compro bar v al o r del sig uiente elemen to.
De finir Nue vaPos co mo p os i c i on origin a l del lti mo elem ent o
despl azado
fin_mientras

Codificacin del procedimiento Ordenarlnsercion

procedure Ordenac ion lnversa (var Tabla: Lis ta ; N : i n tege r) ;


{Tabla (en t r ada /sal i da) , N (entrada)}
{Lis ta = ar ray de N elementos enteros}
var
K : i n te ge r; {subndice del sigu iente e l emen to al que se inser ta}
Nueva Pos : integer; {s ubnd ice de este elemento despus de la in sercin}
Aux : intege r;

begin
for K := 2 to N do
begin
Au x : = Tab l a [ K] ; {obtener s i gu i e n t e e l emento a in sert ar}

( d e s p l aza r todos los valor es > Aux u n e lemen to)


Desplaza r (Tabla , K, Aux , Nuev a Pos);

{in sertar Aux en posicin Nu evaPos}





Tabla [NuevaPos] : = Aux
, end
end;

El procedimiento Desp l azar es

procedure Despla z ar (var Tabla : Lista; Aux, K : i nteger;


var NuevaPos : integer);
var
En c on t rado : b oo l ea n; { i nd ica d o r }
begin
{de splaza r val ores > Aux . Come nzar con el elemento K- l }
En contrado := false;
while (K >1) and not Enc ontrado do
if (Tab la [ K- 1 ] > Au x) then
begin
Ta b l a [ K) := Tab l a [K-1 ] ;
K : = K- 1
end
else
Encontrado : = true ;
NuevaPos := K
end; {Desplazar }
514 Estructura de datos

15.5.1. Algoritmo de insercin binaria


El anlisis de la ordenacin por insercin es un poco ms complicado. El nmero de
comparaciones en i-simo paso es como mximo k - 1 Y como mnimo l. Por consi-
guiente, la media proporciona el nmero de comparaciones.

[(k - 1) +1] /2 = k/ 2

El nmero de comparaciones ( C) es
n
n2 - n -_
C mx = L (i - 1) = 1 + 2 + ... + (n - 1) =
;~2 2
n
Cmin = L (l) = 1 + 1 + ... + 1 = (n - 1)
;=2

Cmedia = (Cmax + Cmin )/2 =

Como se observa, la eficiencia es O(n 2 ).

15.5.2. Comparacin de ordenaciones cuadrticas


Caso favorable Caso desfavorable
2 2
Seleccin O(n ) O(n )
2
Burbuja O(n) O(n )
2
Insercin O(n) O(n )

Como el tiempo requerido para ordenar un array (vector) de n elementos es propor-


cional a n2 , ninguno de estos algoritmos es particularmente bueno para arrays grandes
(n >= 100). Para listas de mayor nmero de elementos, los mtodos avanzados son los
2
ms idneos ya que su eficiencia en lugar de depender de n depende de n x log2' n, lo
que reduce considerablemente el tiempo de ejecucin.

15.6. ORDENACiN SHELL


La ordenacin Shell debe el nombre a su inventor, D. L. Shell [CACM 2 (julio, 1959),
30-32]. Se suele denominar tambin ordenacin por disminucin de incremento (gap).
La idea general del mtodo (algoritmo) es la siguiente:

Lista original
504 88 513 62 908 171 898 277 654 427 150 510 612 675 750 704
l. Se divide la lista original (16 elementos, en este ejemplo) en ocho grupos de dos
(considerando un incremento o intervalo de 16/2 = 8).



Ordenacin, bsqueda y mezcla 515

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

Primer paso (divisin/ordenacin por 8)


504 88 513 62 908 171 898 277 654 427 150 510 612 675 750 704

Segundo paso (divisin/ordenacin por 4)


504 88 150 62 612 171 750 277 654 427 513 510 908 675 898 704


516 Estructura de datos

Tercer paso (divisin/ordenacin por 2)

504 88 150 62 612 171 513 277 654 427 750 510 908 675 898 704
"-- "- A A /--... .--A-.. A /'-.. ./'-..... ~
=---=><::A~_A~><::./'-.....~><:::../'-.....----=::.</~__/

Cuarto paso (divisin/ordenacin por 1)

150 62 , 504 88 513 171 612 277 654 427 750 510 898 675 908 704

62 88 154 171 277 427 504 510 513 612 654 675 704 760 898 908

El algoritmo de Shell tiene diferentes modelos; recogemos en este libro uno de los
ms populares y citados en numerosas obras de programacin.

Algoritmo
i n terv al o ~ n d i v 2
mientras (i n tervalo> O) hacer
desde i ~ ( in te r v a l o + 1 ) hasta n hacer
j ~ i -i n te r va l o
mientras ( j >O) hacer
k ~ j + i nt e rv alo
si a [ j J < = a[ k J
entonces
j ~ O
sino
I n tercamb i o (a [ j]. a[ kJ ) ;
fin si
j ~ j - i nt e r v al o
fin _ mientras
fin_desde
interva l o ~ i n t erv a l o div 2

program Orden a r S h e ll ;
{mo del o d e or de n aci n d e 500 e nteros a l eato r io s}
const
Nu mE l e me n tos = 5 0 0 ;
type
Rango - l . . Nume l e men tos ;
List a - array [ Ra ng oJ of i n te g er;
var
L : Li sta ; "

procedure Ge nera rA le a torios (var A : Lista ; E l e mentos : i n tege r ) ;


var
I : in te ge r ;
begin
Randomize;
for I : = 1 to El emen tos do
A [I J : = Ra n dom ( 1 000)
end;
Ordenacin, bsqueda y mezcla 517

procedure Visualizar (var A:Lista; Elementos:integer);


var
I : integer;
begin
for I := 1 to Elementos do
Write (A[I] : 6, " ) ;
WriteLn
end;

procedure Intercambio (var X, Y : integer);


var
Aux : integer;
begin
Aux := X;
X := Y;
y : = Aux
end;

procedure Shell (var A :Lista; N : integer);


var
Intervalo, I, J, K : integer;
begin
Intervalo := N div 2;
while Intervalo > O do
begin
for I := (Intervalo + 1) to N do
begin
J := I - Intervalo;
while (J > O) do
begin
K := J + Intervalo;
if A [J] <= A [K]
then
J := O
el se
Intercambio (A[J], A[K]);
J := J - Intervalo
end {while}
end;
Intervalo := Intervalo div 2
end
end;

begin
{programa principal}
WriteLn ('Comienza la ordenacin');
GenerarAleatorios (L, NumElementos);
Shell (L, NumElementos);
visualizar (L, NumElementos)
end.

15.7. ORDENACiN RPIDA (QUICKSOR7)


Uno de los mtodos ms rpidos y ms frecuentemente utilizado en ordenacin de arrays
es el conocido como ordenacin rpida (Quicksort). Fue inventado por C. H.
518 Estructura de datos

Hoare, y la cantidad de cdigo necesario es sorprendentemente pequeo comparado con


la excelente velocidad que proporciona.
La idea bsica de la ordenacin rpida de un array (lista) es:

Elegir un elemento del array denominado pivote.


Dividir o partir el array original en dos subarrays o mitades (sublistas), de modo
que en una de ellas estn todos los elementos menores que el pivote y en la otra
,,
sublista todos los elementos mayores que el pivote. ,
,
j

Las sublistas deben ser ordenadas, independientemente, del mismo modo, lo que ,

conduce a un algoritmo recursivo.


,
,,

La eleccin del pivote es arbitraria, aunque por comodidad es usual utilizar el tnni- ,
no central de la lista original, o bien el primero o ltimo elemento de la misma. ,,
,
Como ejemplo ilustrativo de la divisin de una lista en dos sublistas, consideremos ,
,

.",
,
la siguiente lnea de enteros: .
i'
~
;;

,
9 23 31 17 21 19 13 15 26 ,
j
;
i

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


pivote I
,
,,
,
'.~
9 23 31 17 21 19 13 15 26 ,
,
,
,

,
,,
2. A continuacin se establecen dos punteros en el array 1 o J. El primer puntero ,
'1
apunta al primer elemento. Por consiguiente, 1 = 1. El segundo puntero apunta al ,1
,
;,
ltimo elemento y, por tanto, J = 9 (noveno elemento): ,
";.,

9 23 31 17 21 19 13 15 26 ,
,
!
j

1= 1 J=9

3. Mientras 1 apunte a un elemento que sea menor que 20, se incrementa el


valor de 1 en 1, hasta que se encuentre un elemento mayor que el pivote. A
,
continuacin se realiza la misma tarea con el puntero J, buscando un elemento
menor que 21, y mientras no lo encuentra se decrementa J en 1.
;'

9 23 31 17 21 19 13 15 26

.. ..
1 J


Ordenacin, bsqueda y mezcla 519

4. Se intercambian los elementos apuntados por I y J Y a continuacin se incremen-


tan en uno los contadores 1, J.

9 15 31 17 21 19 13 23 26


1 J

5. El proceso se repite

9 15 13 17 21 19 31 23 26


1 J

9 15 13 17 21 19 31 23 26


1 J

9 15 13 17 19 21 31 23 26


J 1

6. En el momento en que J > 1, se ha terminado la particin. Se han generado dos


sublistas, que tienen las propiedades citadas: la primera sublista, todos los elemen-
tos menores o igual a 20, y en la segunda, todos los elementos mayores que 20.
Sublista izquierda Sublista derecha
9 15 13 17 19 21 31 23 26
Sintcticamente hablando, si el array original es a
a[k] <= 20 for k = 1..I - 1
(k = 1.. 5)
a[k] > 20 for k = j + l..N
(k = 6 .. 9)
520 Estructura de datos

Si se utiliza J como ndice final de la primera sublista, se tiene:

Sublista izquierda I..J (9 15 13 17 19)


Sublista derecha 1.. N (21 31 23 26)
7. La ordenacin de las sublistas implica el mismo proceso que antes, excepto que
los ndices en el caso de la sublista son (1..5) y (6 .. 9). Los pasos en el caso de la
sublista izquierda son:

Sublista izquierda 1 Sublista izquierda 11 Sublista izquierda 12


9 15 [U] 17 19 9[}] 15 17 19
t t
1 J Sublista 111 Sublista 112
9 13

9 15 [TI] 17 19 Sublista izquierda 1 ordenada


t t
1 J 9 13 15 17 19

9 13 15 17 19
t t
J 1

Algoritmo de ordenacin rpida

1. Inicializar 1 a Primero (primer ndice del array)


2. Inicializar J a Ultimo (ltimo ndice del array)
3. Seleccionar el elemento pivote (trmino Central)
Central ~ A [(Primero + Ultimo) div 2]
4. repetir
4.1. mientras A[I] < Central hacer
1 ~ 1 +1
fin-mientras
4.2. mientras A [J] > Central hacer
J ~ J - 1
fin-mientras
4.3. si 1 <= J entonces Intercambiar (A [I] ,A [J]
hasta_que 1 > J
5. si J > Primero, llamar al procedimiento Partir, para dividir la
sublista izquierda [Primero .. J]
6. si 1 < Ultimo, llamar al procedimiento Partir, para dividir la
sublista derecha [1 .. Ultimo]


Ordenacin, bsqueda y mezcla 521

Programa ordenacin rpida


program TestRapido ;
I
type I
En teros = array [1 .. 100] of integer;
var
Lista : Enteros;
K : integer;

procedure Rapido (var A: Enteros ; N : i n teg er) ;

procedure Partir ( Pr im er o , Ul t im o : intege r ) ;


var
1. J
in t eger;
Cen t ral : in teger ;

procedure Inter camb i a r (var M,N : integer);


var
Aux : integer;
begin
Aux -- M ,
M -

-
N ,
N := Aux
end; {In tercambi ar}

begin { Partir}
1 : = P ri mero;
J : = Ulti mo ;
{encontrar Elemento pivote (central) }
Central := A [(Prim ero + Ultimo) div 2];
repeat
while A[I] < Centr al do
1:=1+1 ;
while A[J] > Ce n tral do
J :=J- l ;
if 1 < = J then
begin
I n ter camb i ar (A [I ], A [ J]);
1 -- 1 + 1;
J -
- J - 1
end { if }
until 1 > J;
if Pr imero < J
then Partir (Prime ro , JI;
if 1 < Ultimo
then Partir (1, Ult i mo)
end; {Part ir }

begin { Rpido }
Part i r (1, N)
end; {R pido }
(pr og ram a principal)
begin
{ le ct ura de 100 ele ment os al e atorios}
for K : = 1 to 100 do
522 Estructura de datos

begin
Lista [ K] : = Random (1000);
Write (Lista [K] : 8)
endl
WriteLn;
{llama da al procedimiento Rapido}
Rapido (Lista. 100);
{escri tura de la lista ordenada}
for K := 1 to 100 do
Write (Lista [K] : 8);
WriteLn ,


end. ,


,



15.7.1. Anlisis de la ordenacin rpida ,




:!

El mtodo de ordenacin rpida es el ms veloz de los conocidos. El nico inconvenien-



']
te de este mtodo es la cantidad de memoria que se requiere en la pila. Caso de tener ,

problemas de memoria, deber realizar pruebas para evitar errores en ejecucin. En este
I
caso le recomendamos utilizar el mtodo de Shell. 1
~
Si se supone que la lista se divide siempre en dos partes iguales, entonces, despus j
d
de la d-sima divisin de la lista, se tendrn 2 partes. El nmero de iteraciones del
,I
procedimiento particin (partir) es O(n) para todas las partes. Como haba log2n divisio- ,1
i
nes, el algoritmo requerir O(n * log2n).
i
1
15.8. ORDENACiN POR MEZCLA (MERGESOR7) .~
!


Como su nombre sugiere, la idea bsica de la ordenacin es la mezcla de listas ya orde-
nadas. La filosofia de la mezcla ya la conoce el lector, la diferencia reside en que en este
I
caso las listas estarn ordenados por un campo clave determinado.

Algoritmo
l. Dividir la lista en dos mitades.
2. Ordenar la sublista izquierda.
3. Ordenar la sublista derecha.
4. Mezclar las dos sublistas juntas.

EJEMPLO 15.1

Ordenar por mezcla la lista.

9 1 3 5 10 4 6

El proceso consiste en dividir la lista en dos mitades y cada una de las mitades en otras
mitades. Este proceso se repite hasta que cada sublista contiene, cada una, una entrada,
segn se aprecia en el grfico.
l
~
;
~

1

Ordenacin, bsqueda y mezcla 523

L1 L2

9 1 3 5 10 4 6

9 1 3 5 10 4 6

9 1 3 5 10 4 6

9 1 3 5 10 4

La mezcla comienza con las sublistas de un solo elemento, que se mezclan en sublis-
tas ms grandes cuyos elementos estn ya ordenados, y el proceso contina hasta que se
construye una nica lista ordenada.

L2 L1

El procedimiento de ordenar por mezcla se disea con ayuda de la recursivi-


dad para dividir las listas y ordenar las sublistas; posteriormente se llama a un procedi-
miento Mezcla similar al estudiado ya en otro captulo.
El diagrama de mezcla se ilustra as:
524 Estructura de datos

9 1 3 5 10 4 6

1 9 3 5 4 10

1 3 5 9 4 6 10

, 1 3 4 5 6 9 10

,
Primero Ultimo

Algoritmo OrdMezcla
1. si Primero < Ultimo, entonces {ndices de la lista original}
1.1. Central f- ( Primero +Ultimo) div 2 {punto de divisi n para la
particin}
1.2. Llamar a OrdMezcla a [ Primer o .. Central )
1.3. Llamar a OrdMezcla a [Central+1 .. Ultimo]
1.4. Mezclar a [Primero .. Centr al] con a [C en tral+l. .Ultimo]

El procedimiento OrdMe z e 1 a (mergesort) es un proceso recursivo que se llama a


s mismo para ordenar la sublista izquierda y a continuacin la sublista derecha, y una
vez ordenadas las dos sublistas se llama al procedimiento Mezcla.

procedure OrdMezcla (var A:ListaEnteros; Primer o, Ultimo:integer);


{procedimient o recursivo ordena la subl i s ta A [ Primero .. Ultimo]}
var
Central : integer; {ndi c e del ltim o elemento de la subl ista derecha}
procedure Mez c l a (var List a :ListaEnteros ; Ida, Dcha,PuntoCen: intege r);
{mezcla la sublista ordenada Lista [IdaJ a Lista [PuntoCen] con l a
,
su blista orde nada Lista [ PuntoCen + 1J a Lista [Dc h aJ}
var
Aux : ListaEntero s;
X, Y, Z : in te ger;
begin {Mezcla}
X := Ida
y := PuntoCen + 1;
Z : = X;
{bu c l e para me z clar las sublistas}
while ( X <= Pun t oCen) and ( Y<= Dc ha) do
Ordenacin, bsqueda y mezcla 525

begin
if Li st a [X l . C lav e < = L is ta [Yl .Cl ave
then
begin
Aux [ Z 1 : = Li s ta [ X l ;
X := X + 1
end
elee
begin
Aux [ Z 1 : = Lista [ Y l ;
y := Y + 1
end;
Z .. -- Z + 1
end;

(bucle para copiar elem e ntos r est a ntes, si e x isten)


while X < = Punt o Ce n do
begin
Aux [Zl := Li st a [ X l;
X := X + l ;
Z : = Z + 1
end;
while 1 < = Dch a do
begin
Au x [Zl - Lista - [y 1,

y -
-
y + 1;
Z -- Z + 1
end;
( copiar Aux e n Li s ta)
for X : = Ida to Dc ha do
Lista [ Xl : = Aux [ X l
end; (Me z c la)

begin ( OrdM e zcla)


if P r imero < Ult i mo
then Ce nt ra l : = ( Pri mero + Ult i mo ) div 2 ;
Or dMezc l a (Lista, Prime ro , Centra l ) ;
OrdMezc l a (L i st a , Ce n tra l + 1, Ult im o);
Mezcla (Lista , Pr i mero , Ul t i mo , Cent r al)
end; {Or dMezc la}

15.9. MTODO DE ORDENACiN POR MONTCULOS


(HEAPSORT)

Este algoritmo de ordenacin est basado en la estructura de montculo. Por lo que vamos
a estudiar en primer lugar el concepto de montculo y despus describimos el algoritmo.

15.9.1. Montculo
Se define un montculo de tamao n como un rbol binario completo de n nodos, tal que
el contenido de cada nodo es mayor o igual al contenido de su padre.
526 Estructura de datos

33 41 18 31

Utilizamos un array para representar el rbol binario, de tal forma que si el ndice i
hace referencia a un nodo, entonces el nodo hijo izquierdo est referenciado por el ndi-

ce 2*i, el nodo hijo derecho por el ndice 2*i + 1, Y el nodo padre por i div 2.
As el nodo raz ocupar la posicin 1 en el array, y en la posicin 2 y 3 estarn sus
nodos hijo izquierdo y derecho, respectivamente.
, La representacin del rbol del ejemplo en un array

7 12 15 19 22 17 16 26 33 29 41 18 31 50

Utilizando esta representacin tendremos que para que se cumpla que todo nodo del
rbol ha de ser mayor o igual que el nodo padre, ha de cumplirse:

V[iJ ~ V[2*iJ
tri = 1 .. nI2
V[iJ ~ V[2*i+ 1J

Es claro que a partir de esta definicin de montculo la raz del rbol (o primer ele-
mento del array) es el elemento ms pequeo; en definitiva, V[l] siempre tendr el ele-
,
mento mas pequeno. -
Segn esto podemos descomponer el mtodo de ordenacin heapsort en los siguien-
tes pasos:

l. Construir un montculo inicial con todos los elementos del vector: V[lJ, V[2J,
I,


... V[nJ
I
I


2. Intercambiar los valores de . V[lJ y V[nJ (siempre se queda el mximo en el ex-
tremo).
3. Reconstruir el montculo con los elementos V[lJ, V[2J, ... V[n - 1].
4. Intercambiar los valores de V[lJ y V[n - 1J.
5. Reconstruir el montculo con los elementos V[l], V[2J, '" V[n - 2].
Ordenacin, bsqueda y mezcla 527

Est claro que estamos en un proceso iterativo que partiendo de un montculo inicial,
repite intercambiar los extremos, decrementar en 1 la posicin del extremo superior y
reconstruir el montculo del nuevo vector. Lo expresamos en forma algortmica:

procedimiento Ordenac i on_Heaps ort (Vector , N)


inicio
<Constru ir monticulo inicial (Vecto r, 1, N) >
desde K ~ N hasta 2 hacer
inter cambiar (Vector[11, Vector[Kl)
construir monticulo (Vec t o r, 1, K-1)
fin_desde
fin Ordenacion_Heapsort

Segn el algoritmo debemos considerar dos problemas: construir el montculo ini-


,,
cial y cmo restablecer los montculos intermedios. Como ahora veremos, la solucin a
"L_1:
< ambos problemas va a ser mediante una misma rutina. Consideremos que ya est cons-
"{
1:
l: truido el montculo inicial y se ha realizado el intercambio. La figura nos muestra esta
. .,

,.

sltuaClOn .
,"

'. Montculo construido


,,
l

64

66

Debido al intercambio queda

23
528 Estructura de datos

Para restablecer el montculo hay dos posibilidades:

V[l] es menor o igual que los valores de sus hijos, entonces la propiedad del
montculo no se ha roto.
En otro caso, el elemento mnimo que necesitamos poner en V[ 1] es o su hijo
izquierdo o su hijo derecho (V[2], V[3], respectivamente). Por lo que se detenni-
na el menor de sus hijos y ste se intercambia con V[l). El proceso contina repi-
tiendo las mismas comparaciones entre el nodo intercambiado y sus nodos hijos;
as hasta llegar a un nodo en el que no se viole la propiedad de montculo, o
estemos en un nodo hoja.

La figura nos muestra el proceso de restablecer la condicin de montculo en el rbol



resultante del intercambio; este proceso se expresa diciendo que el nodo situado en la
cspide del rbol se deja hundir por el camino de claves mnimas.
<

42 42

,
<

<

40

<

15.9.2. Procedimiento empuja


<
<

En el procedimiento e r i ba escribimos la codificacin del algoritmo, restablece el mon-

tculo dejando hundir la clave por el camino de claves mnimas.


<

procedure Criba (var V : Vector ; Pr i mero, Ul timo :i n t eger) ;


{Primer o; represen ta e l nodo raz }
var
Es Mt c l o : b oo l ean ;
Hijo :in teger;
begin
EsM tc l o : = Ealse ;
while (P r imero <= Ul t i mo div 2) and not Es Mt clo do
,

{prime ra c o n dici n qui ere exp resar que no sea u n a hoj a de r b ol }


begin

if 2 * Prim e r o = Ultimo then

Hij o := 2 *Prim e r o {t i e ne un n ico de s ce ndi e n te}


i
elee {s el ecc i o n a el mayo r de l os dos hij os }
if V [ 2 * Primero ] > V [ 2 * Prim ero +l ] then
Hi j o : = 2 *P rim ero
elee
Hijo : = 2 *P r imero+l;
{comp a r a n odo r a z co n el mayor de sus hi jo s }
if V [Pr i me r o ] < V [Hi jo] then

<

<

.-
;


<


<
<

:
,
!


<

---.
Ordenacin, bsqueda y mezcla 529

begin
Inter ca mbi a (V[ Prim e rol, V [Hi jo l);
Pr i mero : = Hijo {p a r a co n t in ua r p or la rama d e c l aves mnima s}
end
elee Es Mtc l o := tru e
end
end;

15.9.3. ntculo inicial


Para construir el montculo inicial se llama a Criba (V,j, n) para todo j = n/2, n/2 - 1, ... , l.
En definitiva se construye el montculo de abajo a arriba, desde el penltimo nivel
del rbol hasta la raz.

for j : = n d iv 2 downto 1 do
C r i ba (V , j , n) ;

De esta forma el procedimiento Criba es el ncleo de la realizacin del mtodo de


ordenacin Heapsortr.

Codificacin de Heapsort
Antes de escribir la codificacin cabe hacer una observacin. El mtodo ordena descen-
dentemente ya que siempre intercambia el elemento menor, V[1], con el ltimo del mon-
tculo actual. Para que la ordenacin sea en orden ascendente simplemente debemos de
invertir el vector. Pero si se desea que directamente termine en orden ascendente, se
cambia la condicin de montculo de modo que un nodo tenga la clave mayor (en vez de
menor) que las claves de sus hijos.
La codificacin del procedimiento de ordenacin Heapsort:

procedure Orde n a c i on_H eapsor t (var v: Vector ; N : i n tege r ) ;


var
J : integer ;
begin
for J := N d i v 2 downto 1 do
Criba (V, J , N) ;
for J := N downto 2 do
begin
In tercambi a ( V[ll , V[Jl) ;
Criba (V, 1, J - 1)
end
end;

15.10. MTODO DE ORDENACiN BINSORT


Este mtodo, tambin llamado clasificacin por urnas, plantea conseguir tiempos de eje-
cucin menores de O(n lag n) para ordenar n elementos siempre que se conozca algo
acerca del tipo de las claves por las que se estn ordenando.
530 Estructura de datos

Supongamos que tenemos un array de registros V, que se quiere ordenar respecto un


campo clave de tipo entero, adems se sabe que los valores de las claves se encuentran
en el rango de 1 a n, sin claves duplicadas y siendo n el nmero de elementos. En estas
circunstancias es posible colocar los registros ordenados en un array auxiliar T mediante
este bucle:

for i : = 1 to n do
T [ V[i ] .Cl ave ]: = V[i ];

Sencillamente determina la posicin que le corresponde segn el valor del campo


clave. El bucle lleva un tiempo de ejecucin O(n).
Esta ordenacin tan sencilla que hemos expuesto es un caso particular del mtodo de
ordenacin por urnas (binsort). Este mtodo utiliza urnas, cada urna contiene todos los
registros con una misma clave.
El proceso consiste en examinar cada registro R a clasificar y situarle en la urna 1,
coincidiendo i con el valor del campo clave de R. En la mayora de los casos en que se
utilice el algoritmo ser necesario guardar ms de un registro en una misma urna por
tener claves repetidas. Entonces estas urnas hay que concatenarlas en el orden de menor
ndice de urna a mayor, as quedar el array en orden creciente respecto al campo clave.

En la figura se tiene un array de 1 a m urnas .

i
Urnas

1 A1 A1 ... -
2 A2 ... - A2

A3 ... -


I



1
I
m Rm ... -

Realizacin del mtodo de ordenacin binsort


Para esta implementacin consideramos que el campo clave de los registros est en el rango
entero l .. m. Son necesarias m urnas por lo que vamos a definir un array de m urnas. Las
urnas van a ser representadas por listas enlazadas, cada elemento de la lista contiene un





:
, ,,,,,, - - - - - -- - - -- - - - - - - --

Ordenacin, bsqueda y mezcla 531

registro cuyo campo clave es el correspondiente al de la urna en la que se encuentra.


Una vez que hayamos distribuido los registros en las diversas urnas es necesario
concatenar las listas. En la figura siguiente se muestra cmo realizar la concatenacin.


R1 R1


R2 R2 R2

R3 R3
R3

Rm Rm
Rm

Los tipos de datos para esta realizacin

const
Li mi te - 1000;
M = 1 00 ; {Mx i mo va l or de l a c l ave}
type
TipoClave = 1 .. M;
Registro = record
Clave: T ipoClave;
end;
Vector = array [ l . . Limite] of Reg istro ;

La codificacin del procedimiento de ordenacin y las operaciones auxiliares que


utiliza:

procedure Bi nso rt (var V: Vector; N : i n t eger) ;



( Ti po s para manejo de las urnas . Es t as son represe n tadas por l istas}

type
Puntero =~ N o do;
Nodo = record
R : Re gistro;
$gte : Puntero
end;
Lista = record
Frente , Fin a l : pun t ero ,
,,1
end;
T_ Urnas = array[l . . M] of Lista; !
var 1
,,
Urn a s : T_ Urnas ; ,
J ,I: in t ege r;
L : Puntero ;
{procedi mi e n t os loca l es para el alg oritmo}
532 Estructura de datos

procedure CrearUrnas( var u: T_U rnas);


var K: intege r ;
begin
for K:= 1 to M do
begin
U[K] .Fr ente: = nil;
U[K].Final:= nil
end
end;

function Est aVaci a (Urn a : Lista) : bo ole an ;


begin
Es taVacia := Urna .Fr e n t e=nil,
end;

procedure A adirEnUrn a( var Un aUr na: Lis t a; R: Reg is tro) ;


{Inserta el regi str o co mo ltimo de la u r na}
var
T: Puntero ;
begin
new ( T ) ;
TA.R:= R; T A. Sg te: = n il;
with UnaUrna do
begin
if Est aV acia(U na Urna) then
Frente := T
else
Fi n alA . Sgte: = T;
F in a l:= T
end
end;

procedure En la z ar Urna (var Una: Li sta; U: Lis ta) ;


begin
if not EstaVa ci a(U) then
begin
Una.FinalA.Sgte : = U .Fren te ;
Una.Fi na l: = U.Fin a l
end
end; {Se n te n c ias de bins o rt }
,I
, begin
Cre a rUrnas( Urnas ) ;
{Distr ib ucin de los registr os e n s us correspo ndi e n tes urnas}
for J: = 1 to N do
Anad i rEnUrna(Urnas [V [ J ]. Clave ], V[J ] ) ;
{Con ca ten a las lista s que re pr esenta n a las urn as desd e Urna , ha st a
Urna m }
1: = 1 ; {bsqueda de pri mera urna n o vac a }
while EstaVacia(Urn as [I]) do {la lg ica de l prob l ema nos d i ce}
1 : = 1+1; {ha de ha ber alg una urna va c i a}
for J := 1 +1 to M do
En l azar Ur na (Urnas [I] , Ur n as[ J ] ) ;
{Se re co rre l a lista - urna resultante de la concat ena c i n}
J:= 1;
L:= Urnas[I] .Fr ente;
while L <> nil do
Ordenacin, bsqueda y mezcla 533

begin
V[J]:=LA.R;
.. J:= J+l;

L: = LA.Sgte

end

end;

,

,; .. 15.11. MTODO DE ORDENACiN RADIX-SORT



;
,..
c- Este mtodo se puede considerar como una generalizacin de la clasificacin por urnas l .

...
- ', ,

Aprovecha la estrategia de la forma ms antigua de clasificacin manual, consistente en


,".
';'.. .
.t,.
"
hacer diversos montones de fichas, cada uno caracterizado por tener sus componentes un
.,i '
, .
mismo dgito (letra si es alfabtica) en la misma posicin; estos montones se recogen en
orden ascendente y se reparte de nuevo en montones segn el siguiente dgito de la cla-
, ve. Para centrarnos en lo que estamos diciendo, supngase que tenemos que ordenar
estas fichas identificadas por tres dgitos:
.

345, 721,425,572,836,467,672,194,365,236,891, 746,431,834,247,529,216,389


Atendiendo al dgito de menor peso (unidades) se reparten las fichas en montones
del O al 9 (por ejemplo, el elemento 345 se coloca en el montn 5, el elemento 721 en el
montn 1, etc.; las urnas de nmeros cuyo primer dgito es O, 3 Y 8 no existen).
216
431 365 746
891 672 834 425 236 247 389
721 572 194 345 .81Q 467 529
1 2 4 5 6 7 9
Tomando los montones en orden, la secuencia de fichas queda:
721 891 431 572 672 194 834 345 425 365 836 236 746 216 467 247 529 389
De esta secuencia podemos decir que est ordenada respecto al dgito de menor peso.
Pues bien, ahora de nuevo distribuimos la secuencia de fichas en montones respecto al
segundo dgito:
236
529 836 247
425 834 746 467 672 194
216 721 431 345 162 572 182 m
1 2 3 4 6 7 8 9
Tomando de nuevo los montones en orden, la secuencia de fichas queda as:
216 721 425 529 431 834 836 236 345 746 247 365 467 572 672 389 891 194

I Una urna se considera una lista enlazada en la que se almacenan los elementos ledos con un detelllli-
nado criterio, el valor del dgito en la secuencia creciente de pesos (unidades, decenas, etc.).
534 Estructura de datos

Esta secuencia de fichas ya la tenemos ordenada respecto a los dos ltimos dgitos,
es decir, respecto a las decenas. Por ltimo se distribuye de nuevo las fichas respecto al
tercer dgito:

247 389 467 891


.
236 365 431 572 746 836
ill lli 345 425 529 672 ID ill
1 2 3 4 5 6 7 8

Tomando de nuevo los montones en orden, la secuencia de fichas queda ya ordenada:

194 216 236 247 345 365 389 425 431 467 529 572 672 721 746 834 836 891
La idea clave de la ordenacin radix-sort (tambin llamada por residuos) es clasifi-
car por urnas primero respecto al dgito de menor peso (menos significativo) d", despus

,.
concatenar las urnas, clasificar de nuevo respecto al siguiente dgito dk _ l , y as sucesiva-
! mente se sigue con el siguiente dgito hasta alcanzar el dgito ms significativo di' En ese
,
momento la secuencia estar ordenada.

Tipos de datos
Al igual que en el mtodo de binsort las urnas estarn representadas por un vector de
listas. En el caso de que la clave respecto a la que se ordena sea un entero, tendremos 10
urnas numeradas de O a 9. Las listas tienen una realizacin dinmica, cada lista se man-
tiene con dos punteros, uno al frente y otro al final de la lista, as el aadir un nuevo
"-
registro es inmediato ya que se enlaza por el final, de igual forma, concatenar las urnas
consistir en enlazar al final de una con el frente de la siguiente. Estas acciones ya estn
hechas en el mtodo binsort.
A continuacin se presentan los tipos de datos:

const
M = 9; . {numeracin de las urnas 0,1,2,- - -9}
Limite - 1000;
type
TipoClave = O.. maxint;
Registro = record
Clave: TipoClave;
end;
Vector = array[1, .Limite) of Registro;
{tipos para definir las urnas}
,
Puntero =~Nodo;

,
Nodo = record
R: Registro;
, Sgte: Puntero
,
, end;
, Lista = record
,

Frente, Final: puntero

end;
TUrnas = array[O .. M) of Lista;
,

,
I

Ordenacin, bsqueda y mezcla 535

CODIFICACiN
La codificacin supone que se est ordenando respecto a una clave entera y positiva. En
primer lugar se determina el nmero de dgitos que tiene el campo clave, mediante divisio-
nes sucesivas por 10; para ello, se toma el entero mximo que admite la computadora (en
nuestro caso, 32.767). A continuacin, se introducen de modo sucesivo cada elemento
en su correspondiente urna mediante la unidad? y se realizan iteraciones del bucle for 1,
hasta que I es el nmero mximo de dgitos del entero ms grande de la lista a ordenar.
A continuacin se presenta la codificacin del procedimiento de ordenacin Radix Sort.

procedure Rad ix Sort( var V :v ec t or ; N: in teger) ;


var
Urna s: T_ Urn a s;
l, J, R: integer;
Aux , D, Peso , Ndig : integer;
L, A: Puntero;
begin
{Se c alcula el n mero de d gitos }
Aux := Maxlnt; {Max l nt=32.7 67, en computado ra s de 16 bit}
Ndig := O,
while Aux >= 1 do
begin
Aux := Aux div 10;
Ndig : = Nd ig + 1 {nmero de dgitos de la c l avel
end;

Peso := 1; {Nos perm ite obte ner los dgi tos de menor a mayo r pe so}
for l : = 1 to Ndig do
begin
CrearUrnas(Urnas); {Crea las urnas con un bucle de O a M}
for J :=1 to N do
begin
D :=(V[J] . c l ave div Peso) mod 1 0 ;
Anadir EnU rna(Urnas [ D], V [J ]) ;
end;
J := O; {bsqueda de pr im era ur na no va c a}
while EstaVacia(Urnas [ J]) do
J := J+1;
for R : = J+ 1 to M do
Enl aza rUr na(Ur nas [J] , Urn as[R ]);
(S e r eco rre l a lista - u rn a re sultante d e la concatenacin)
R : = 1;
L := Urnas[J] .Fren te ;
while L < > nil do
begin
V [R] := LA .r;
R : = R + 1;
A : = L;
L : = LA.Sgte;
dispose(A)
end;
Pe so : = Pe so * 10;
end
end,
!
.~
,

,
536 Estructura de datos "
,

,
15.12. BUSQUEDA LINEAL ,

,,
,
Otro problema importante en proceso de datos, como ya se ha comentado, es la bsque- ,
1
"
da en un conjunto de datos de un elemento especfico y la recuperacin de alguna infor-

.~

macin asociada al mismo.


j,
Existen diferentes mtodos de bsqueda:

bsqueda lineal o secuencial


bsqueda binaria o dicotmica
bsqueda hash o por conversin de claves

Las dos primeras se pueden aplicar a listas implementadas con arrays, y la tercera es
ms propia de estructuras tipo registros o archivos. En esta seccin y en la siguiente
trataremos de la bsqueda lineal y de la bsqueda binaria dejando para el captulo de
archivos el tercer mtodo.
I ,
,

15.12.1. Anlisis
La bsqueda lineal o secuencial es la tcnica ms simple para buscar un elemento en un
,

,
array (vector). Consiste el mtodo en el recorrido de todo el vector, desde el primer
,
elemento hasta el ltimo, y de uno en uno. Si el vector contiene el elemento, el proceso
,
,
devolver la posicin del elemento buscado dentro del vector y, en caso contrario, un
:j
;, ;
mensaje que indique la falta de xito en la bsqueda.
,I
I ;
,
Mediante un bucle desde se compara el elemento t buscado con a[i]. ,En caso de
I
,,
encontrarlo, se almacena la posicin (el ndice del array) del mismo y finalmente se
,

devolver al programa principal. Dado que los algoritmos de bsqueda normalmente


slo devuelven la posicin, es muy frecuente que la implementacin del algoritmo se
haga con una funcin.

EJEMPLO
Supongamos una /ista de nmeros de la Seguridad Social incluidos en un array a y se
desea buscar a ver si existe el nmero 453714.

Pseudocdigo 1
posi c i on f-- o
{lista = vect or a [il de n e l e men tos}
desde i f-- 1 hasta n hacer
si a [ i 1 = t
entonces posici o n f-- i
fin_si
fin_desde

Este algoritmo tiene un grave inconveniente: sea cual sea el resultado (existe/no existe
el elemento) se recorre el vector completo. El algoritmo tiene una mejora: detectar el
momento de localizar el elemento y terminar el bucle. As, el algoritmo mejorado se
.j

,

Ordenacin, bsqueda y mezcla 537

a[1] 451871

a[2] 120467

a[3] 401321

a[4] 25761

Elemento a buscar: t
~---- 453714

a[98]
339412
a(99)
81467
a(100) 924116

Nmeros Seguridad Social

Figura 15.1. Bsqueda lineal de un elemento.

puede realizar con un bucle while o repeat, y utilizando unas banderas (interruptor) que
detecten cundo se encuentra el elemento. El bucle se terminar por dos causas:
La bandera o indicador (En co nt rado , por ejemplo) toma el valor esperado (por
ejemplo, true verdadero ) si la bsqueda ha tenido xito.
El valor del ndice i es mayor que el nmero de trminos de la lista, lo que signifi-
ca que se ha terminado de recorrer la misma y el elemento buscado no ha aparecido.

Pseudocdigo 2
Encontrado f - fals o
Posic i on f- O
i f- 1
mientras (i < = n ) y (No En con trado) hacer
si a [ i 1 = t
entonces Pos i c i o n f - i
En c ontr ad o f - verd a de ro

1 ~ l +l
fin_mientras

o bien con la estructura repetir


repetir

hasta_que (En c o n t rad o) o (i > n)



538 Estructura de datos


,
~

,,

Funcin bsqueda lineal ,
1
,
function BusquedaLineal (A:Lista; (entrada, vector bsqueda}
N : integer; {entrada, nmero de elementos}
T : integer; (elemento a buscar}) : integer;
var
Encontrado : boolean;
I : integer;
begin
BusquedaLineal := O; {posicin del elemento caso de no existir}
Encontrado := false;
I : = 1;
while (I <= N) and not Encontrado do
if A[I] = T then
begin
BusquedaLineal .. - I',
Encontrado := true;
end (fin del if )
else I : = I + 1
end; (posicion del elemento en la lista)

Si se desea saber en el programa principal si existe el elemento, bastar preguntar


con una sentencia ir cul es el valor de la funcin BusquedaLineal; si es cero no
,
existe el elemento, y en caso contrario existe y su valor es la posicin en la lista o vector.
I
Nota

-
,

function BusquedaLinealDos (A: Lista; N : integer;


T: integer) : integer;
var
I : integer;
begin
for I := 1 to N do
if T = A[I] then
begin
BusquedaLineal := I;
Exit
end;
BusquedaLineal := O
end;

Programa (se muestra una variante del algoritmo de la funcin)

program LinealBusqueda;
const
Total = 100;

Ordenacin, bsqueda y mezcla 539

type
Li s ta = array [1 .. To tal] of int e ger;
var
L : List a ;
P, J, Num : intege r;
function Bu s q ued a Linea l (t: i n t eg er ; A: L i s ta;Maximo : int e ger): integ er ;
var
1 : in te g er;
En co ntrad o : boo l ean;
begin
En co ntra do := fal se ;
1 .. -- O',
while (1 < Maxim o) and not Encontr a d o do
begin
1 := 1 + 1:
En c o ntr a d o : = A[I ) - t
end;
if En c on t r ad o
then Bu s qued a Linea l -- 1
elBe Bu squ eda Line a l -- O
end;

begin {p r ograma pri n c i pal}


for J : = 1 to Tot al do {l ec tur a de 100 en teros al e at o ri os }
L [ J ) : = Ran dom (1 00) ;
repeat
Wri t e ('i ntr od u zca n me r o a bus ca r ') ;
Re ad Ln (Nu m) ;
P : = Busqued a Lineal ( Num, L, Tota l);
if P = O
then
Wr i t e Ln (' no e xi s te e l nm e r o en l a lista')
elBe
Wri t e l n ('e n co ntr ado e n l a p o s ici n ' ,P:l)
until Num = O {marca fin de datos d e e ntrada }
end.

15.12.2. Eficiencia de la bsqueda lineal


El mtodo de bsqueda secuencial, en el peor de los casos (el elemento buscado est al
final de la lista o no existe), requiere consultar los n elementos de la lista para encontrar
el elemento deseado o determinar que el elemento no existe en la lista. Entonces el tiem-
po de bsqueda es directamente proporcional al nmero de elementos de la lista, por lo
que utilizando la notacin O se tiene para el tiempo t la frmula:

t = O [f(n)]

o simplificando

t = O(n)
540 Estructura de datos

,
15.13. BUSQUEDA BINARIA
La bsqueda lineal, por su simplicidad, es buena para listas de datos pequeas, para
listas grandes es ineficiente; la bsqueda binaria es el mtodo idneo. Se basa en el
conocido mtodo de divide y vencers.
Este mtodo tiene una clara expresin en la bsqueda de una palabra en un dicciona-
rio. Cuando se busca una palabra no se comienza la bsqueda por la pgina 1 y se sigue
secuencialmente, sino que se abre el diccionario por una pgina donde aproximadamen-
te se piensa puede estar la palabra, es decir, se divide el diccionario en dos partes; al
abrir la pgina se ve si se ha acertado o en qu parte (la primera o la segunda) se encuen-
tra la palabra buscada. Se repite este proceso hasta que por divisiones o aproximaciones
sucesivas se encuentra la palabra.
Supongamos que la lista donde se busca es

1331
1373
1555
1850
1892
1898 ....f - - - - elemento central
elemento buscado ----~ 1989
2002
2400
2670
3200

y que se busca el nmero 1989.


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

elemento a buscar------1~ 1989


2002
2400 f---- elemento central
2670
3200

, El elemento central en esta sublista es 2400, y como 1989 es menor, la nueva sublista
donde buscar es
I,
1989 ....f - - - - elemento considerado central
2002

Como ya no hay elemento central, se toma el nmero inmediatamente anterior a la


posicin central, que en este caso es 1989. En este caso se ha encontrado el elemento

Ordenacin, bsqueda y mezcla 541

deseado en tres comparaciones, mientras que en la bsqueda lineal hubiese necesitado al


menos seis comparaciones (la mitad de los elementos, redondeada a un entero).
Este mtodo es muy eficiente, con el nico inconveniente, como habr deducido, de
requerir la lista ordenada.

Algoritmo
l. Esta bl ecer Prime ro ~l y Ult im o ~n (n , nm ero d e e leme n to s). Es ta s
var i ab l es rep r ese n ta n l a pr i mera y lt i ma p o sic i n de la l i sta o
sublista donde se est bus c ando y permi te e l clcu l o de l a pos ic i n
d el el eme nto cen tr al .
2. E ncontrado ~ falso (var i able lgica) .
3. mientras Pri mero < = Ult imo y no Encon t rado hacer
{En c o n t r a r pos ic in ce ntra l}
Ce ntral~(Pr i mero+Ult i mo) div 2
{Compara r e l e me n to buscado t co n a (Ce n tral] )
si t = a[ Centra l ]
entonces E ncont r ado ~ v er dade r o
sino si t > a [Centra l ]
entonces Primero~Centra l + 1
sino U l timo ~ Centr al - 1

4. si Encontrado
entonces P osic io n ~ Ce nt ral {exi st e el el eme nt o}
sino posic i on ~ O {no se ha encontrado}
fin_si

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

1. Lectura del vector.


2. Ordenacin del vector.
3. Bsqueda binaria.
4. Visualizar resultados.

Aprovechando que en Turbo Pascal disponemos de la directiva de compilacin $[,


compile el procedimiento de ordenacin Shell, para archivos de inclusin y dle el nom-
bre Shell, se grabar con Shell.inc.

Program BusquedaB i na r ia;


const
Limite = 10 0 ;
type
Li s t a = array ( 1 .. Li mite] of in teger ;
var
A : Li s ta ;
I ,J , t : i n teger;
542 Estructura de datos

{directiva de inclusin, aqu se inserta el procedimiento Shelll


{$I Shell.lnc}
function Binaria (T: integer; var L: Lista; N: integer) :integer;
var
Primero, Ultimo, Central: integer;
Encontrado : boolean;
begin
Primero : = l;
Ultimo := N;
Encontrado:= false;
while (Primero <= Ultimo) and not Encontrado do
begin
Central := (Primero + Ultimo) div 2;
if T = L[Centrall
then
Encontrado := true
else
if T > L[Central]
then Primero := Central + 1
else Ultimo := Central - 1
end; {while}
if not Encontrado ,
then Binaria := O
else Binaria := Central
end;

begin {programa principal}


{lectura de 100 enteros aleat o rios}
for 1 := 1 to 100 do
A[I] := Random (100);
Shell (A,100);
Write ('introduzca nmero a buscar');
ReadLn (T);
J := Binaria (T,A,lOO);
if J = O
then WriteLn ('el nmero no figura en lista');
el se WriteLn ('el nmero ocupa la posicin', J:1);
WriteLn
{si desea repetir la bsqueda, aada a este programa una estructura
repetitiva}
end.

15.13.1. Eficiencia de la bsqueda binaria


En el algoritmo de bsqueda binaria, con cada comparacin se divide en dos mitades el
tamao de la lista en estudio. Si n es el tamao de la lista, los tamaos sucesivos de las
sublistas sern

n n n
2' 4' 8 'oo.

,
,

!
Ordenacin, bsqueda y mezcla 543

El proceso terminar cuando el tamao se hace igualo menor que l. Por consiguiente, si
k es el nmero mayor de comparaciones

o bien

.
Si se toman logaritmos en base 2, en ambos lados, se tiene

log2n :5 k. log22 = k
log2n :5 k

Por consiguiente, la eficiencia de la bsqueda binaria se puede escribir como

que es bastante ms rpido que la bsqueda lineal, como se puede ver en la Figura 15.3,
que representa las dos funciones O.
El tiempo que se ahorra utilizando el algoritmo de bsqueda binaria es muy conside-
rable. Para una lista de 50.000 elementos, la bsqueda lineal en el peor de los casos
requiere 50.000 comparaciones y 25.000 por trmino medio, mientras que la bsqueda
binaria nunca requerir ms de log2 50.000. A fin de ser sinceros, al tiempo de la bs-
queda binaria habra que sumarle el tiempo empleado en ordenar la lista.

y=x

Figura 15.3. Funciones O de bsqueda.


544 Estructura de datos

Recuerde

". La bsqueda binaria sl() funciQna~ C.o rrectamente si la lista est ordena.da. Sin
embargo, la bsqueda line;llfuncjona.tantQ;si la lista est ordenadac()mosjno~st
'. ordenada. .. .' " .
. _. ..
Ji _-

15.14. BSQUEDA BINARIA RECURSIVA


Ya se examin en otro captulo el diseo de un subprograma para realizar la bsqueda en
una lista (array) ordenado por el mtodo de bsqueda binaria. Reconsideremos este
ejemplo y reescribamos el subprograma de bsqueda utilizando recursividad, y recurriendo
a dos estructuras muy frecuentes: a) array de enteros; b) array de registros, y como gene-
ralizacin del mtodo en un caso utilizaremos una funcin y en otro un procedimiento.

15.14.1. Funcin bsqueda


Datos de entrada: Array ordenado A
Primero, Ultimo (ndices extremos de A)
Clave (elemento buscado)
Datos de salida: verdadero,
falso (existe/no existe la clave buscada)

Programa
function Busqueda (var A:Lista; Max, Min:integer; Clave: i nteger) :boolean;
var
Central : integer; {elemento cen tr al del array }
begin
if Min > Max
then Busqueda := false
el Be
begin
Central := (Ma x + Min) div 2;
if A[Central] = Clave
then
Busqueda := true
elBe
begin
if Clave> A [Central]
then
Min := Cen tr al + 1
elBe
Max := Central - 1;
Busqueda := Busqueda (A, Max, Min, Clave)
end
end
{bsqueda}
end;
Ordenacin, bsqueda y mezcla 545

15.14.2. Procedimiento BusquedaBin


Considrese ahora un arra y de registros.

type
Info Emp - record
Nombre : string [30] ;
Nu mSS : i nteger ; {nme ro de la Segur idad Soc ial}
Salario: real ;
Edad : integer;
end
Arr ay _ Emp = array [1 .. 1 00 ] of In f o Emp;
var
L i s ta : Array_Emp;

Parmetros de entrada
Lista
Clave (nmero de la Seguridad Social buscado)
Primero, Ult imo (lmite del array ndices )

Parmetros de salida
Indi ce (posicin que ocupa el nmero de la SS buscado, NumSS)

Programa
procedure BusquedaBin (var Lis ta :Array_Emp; var Indice:integer;

Pr i mero ,Ultimo:integ er ; clave : intege r) ; ,


var
Ce n tral : integer ;
begin
if Prim ero > Ult i mo then
I ndice := O
else begin
Central : = (Pr imero + Ult imo) div 2 ;
if Clave = Lista [Ce ntral] .Nu mSS then
Indic e := Cent r al
el se
if Clave < Lista [ Cen tral] .NumSS then
begin {busqueda en l a primera mitad}
Ultimo := Central - 1;
Busqu eda Bi n (L ista, In d i ce , Primero, Ultim o , Cl ave)
end
else
begin {bsqueda en l a segunda mitad}
Pri mero := Central + 1;
Bu squeda Bi n (Lista, I n dice, Pr imer o , Ulti mo , C la ve)
end
end {else}
end; {BusquedaBin}
--------------------------------------_._-_..--------_._---------------------------------------

546 Estructura de datos

15.15. MEZCLA
El proceso de mezcla, fusin o intercalacin (merge en ingls) consiste en tomar dos
vectores ordenados (a, b) y obtener un nuevo vector (e) tambin ordenado.
El algoritmo ms sencillo para resolver el problema es:

l. Situar todos los elementos del vector a en el nuevo vector c.


2. Situar todos los elementos del vector b en el nuevo vector c.
3. Ordenar todo el vector c.

Esta solucin tiene un inconveniente: no se tiene en cuenta que los vectores a y b ya


estn ordenados; ello supone una ralentizacin del proceso. El algoritmo que tiene en
cuenta la ordenacin es el siguiente:

l. Seleccionar el elemento de valor o clave ms pequeo con cualquiera de los dos


vectores y situarlo en el nuevo vector c.
2. Comparar a(i) y b(j) y poner el elemento de vector ms pequeo en c(k) (i, j, k
son los ndices de los elementos correspondientes en los vectores).
3. Seguir esta secuencia de comparaciones hasta que los elementos de un vector se
hayan agotado, en cuyo momento se copia el resto del otro vector en c.

EJEMPLO 15.2

Mezclar las dos listas de nmeros a y b.

2 4 78 97 Lista A
-15 O l3 15 78 90 96 Lista B

El proceso grfico se muestra en la Figura 15.4_

Procedimiento mezcla de los vectores A y B


1
,
procedure Mez c la (var A,B, C : Lista; M,N : inte g er ) ;
{A Y B: e ntrada. Ve c t o r es y a ordenad o s}
{M y N: nmer o de el e men t os de A y B re sp ectivame nt e}
{C : salida. Ve c tor mez c la ordenado}
{El tip o Lista t e ndr una l o ngitud mnima de M + N e leme nto s}
var
1, J, K : integer;
begin
1 --
1;
J
-- 1;
K
- 1 ,
while ( 1 < = M) and ( J < =N) do
begin
if A[I] < = B[ J}
then

..
Ordenacin, bsqueda y mezcla 547

2 4 78 97 Lista A

I Comparar A[i} y BUJ.
Poner el ms pe queo en C[k}.
<
'- ./ Incrementar los ndices apropiados

-15 O 13 15 78 90 94 96 Lista B

... -15 Lista e

2 4 78 97 Lista A
7
j se ha incrementado,
< junto con k

:;:::.
-15 O Lista B
. ....
-.
-15 O Lista e
B[] < AlI], de modo que C[k] se obtiene de B[]

Figura 15.4. Mezcla de dos listas.

begin
e [ K] - A [1 ] ;
1 - 1 + 1
end
elee
begin
e [K] -- B [J] ;
J . -- J + 1
end;
K .. -- K + 1
end;
{copi ar el resto del vector no ago tado }
if 1 > M
then
for P := J to N do
begin
e [K] := B [Pl;
K := K + 1
end
elee {J > N}
for P := 1 to M do
begin
e [K] := A[P];
K : = K + 1
end
end;
548 Estructura de datos

RESUMEN
Los procesos de programacin ms usuales son: bsqueda y ordenacin. Son partes esenciales de un
gran nmero de programas de procesamiento de datos. La bsqueda y la ordenacin son tambin
procesos que se encuentran nOllnalmente en la vida diaria. Es necesario constatar el hecho de que en
muchas ocasiones se consigue una eficiencia considerable cuando se trata de buscar palabras en un
diccionario o un nombre en una direccin telefnica, que vienen dispuestas en orden alfabtico.
Los procedimientos de bsqueda bsicos son: lineal y binaria. Una bsqueda lineal es slo
adecuada para listas de datos pequeas, mientras que para una lista de datos larga es muy inefi-
ciente. Uno de los mtodos de bsqueda ms eficiente es la bsqueda binaria. '
Los mtodos de ordenacin simple presentan muy poca diferencia en la eficiencia y as, para
listas o vectores pequeos, se pueden considerar los algoritmos de ordenacin, ordenacin mix-
tos, etc" mientras que para listas o vectores ms grandes, los algoritmos ms eficientes son las
ordenaciones de seleccin y de Shell. Segn un estudio de Hale y Easton I de 1987, los tiempos de
ordenacin requeridos para ordenar arrays de 512 y 2.500 elementos son:

512 elementos 2.500 elementos

Burbuja 5.654 segundos 131.618


Burbuja con indicador 5.713 segundos 135.469
Ordenacin por seleccin 5.967 segundos 137.526
Ordenacin por seleccin modificada 3.389 segundos 77.480
Ordenacin por insercin 1.453 segundos 30.361

Para el caso de arrays grandes, se consideran los mtodos de ordenacin avanzados, que son
mucho ms rpidos y eficientes que los mtodos de ordenacin elementales ya citados. Sin em-
bargo, excepto en el caso de ordenacin rpida (quicksort), los mtodos avanzados son mucho
ms grandes en cdigo que las ordenaciones simples.
Los tiempos requeridos para los mtodos de ordenacin avanzados en el caso de arrays de
512 y 2.500 elementos se resumen en la siguiente tabla (Hale y Easton, 1987):

512 elementos 2.500 elementos

Ordenacin Shell .370 segundos 2.540 segundos


Ordenacin por mezcla .487 segundos 3.171 segundos
Ordenacin
,
por montculo .342 segundos 2.092 segundos
Quicksort recursiva .195 segundos 1.160 segundos
Quicksort no recursiva .308 segundos 1.674 segundos

EJERCICIOS
15.1. Escribir un programa que lea una serie de nmeros enteros, los ordene en orden descen-
dente y a continuacin visualice la lista ordenada,

1 Hale, Guy J., y Easton, Richard J.: Applied Dala Struclures Using Pascal, Lexington, Massachusetts,
Heat and Company, 1987, pgs. 158 y 419.
Ordenacin, bsqueda y mezcla 549

15.2. Un mtodo de ordenacin muy simple, pero no muy eficiente, de elementos Xl' X2' X3, ... X n
en orden ascendente es el siguiente:
Paso 1: Localizar el elemento ms pequeo de la lista Xl a X n ; intercambiarlo con Xl.
Paso 2: Localizar el elemento ms pequeo de la lista X2 a X., intercambiarlo con X2 .
Paso 3: Localizar el elemento ms pequeo de la lista X3 a X., intercambiarlo con X3'
En el ltimo paso, los dos ltimos elementos se comparan e intercambian, si es necesario,
y la ordenacin se termina. Escribir un programa para ordenar una lista de elementos,
siguiendo este mtodo.
15.3. Escribir un programa que lea 42 nmeros enteros en un array 7 x 6 y realizar las siguientes

operacIOnes:
a) Imprimir el array.
b) Encontrar el elemento mayor del array.
e) Indicar dnde se encuentra el elemento mayor del array.
d) Si el elemento mayor est repetido, indicar cuntas veces y la posicin de cada ele-
mento repetido.
15.4. Igual que el ejercicio 15.1, pero con el mtodo Shell.
15.5. Se lee una lista de nmeros desde teclado y se desea saber si entre dichos nmeros se
encuentra el 333. En caso afirmativo, visualizar su posicin en la lista. Resolver el proble-
ma por:

a) Bsqueda secuencial.
b) Bsqueda binaria.

PROBLEMAS
15.1. Dado un vector x de n elementos reales, donde n es impar, disear una funcin que calcule
y devuelva la mediana de ese vector. La mediana es el valor tal que la mitad de los nme-
ros son mayores que el valor y la otra mitad son menores. Escribir un programa que com-
pruebe la funcin.
15.2. Se trata de resolver el siguiente problema escolar. Dadas las notas de los alumnos de un
colegio en el primer curso de bachillerato, en las diferentes asignaturas (5, por comodidad)
se trata de calcular la media de cada alumno, la media de cada asignatura, la media total de
la clase y ordenar los alumnos por orden decreciente de notas medias individuales.
15.3. Se dispone de dos vectores, Maestro y Esclavo, del mismo tipo y nmero de elementos. Se
deben imprimir en dos columnas adyacentes. Se ordena el vector Maestro, pero siempre
que un elemento de Maestro se mueva, el elemento correspondiente de Esclavo debe mo-
verse tambin; es decir, cualquier cosa que se haga a Maestro[i] debe hacerse a Esclavo[i].
Despus de realizar la ordenacin se imprimen de nuevo los vectores. Escribir un progra-
ma que realice esta tarea.
15.4. Cada lnea de un archivo de datos contiene informacin sobre una compaa de informti-
ca. La lnea contiene el nombre del empleado, las ventas efectuadas por el mismo y el
nmero de aos de antigedad del empleado en la compaa. Escribir un programa que lea
la informacin del archivo de datos y a continuacin la visualice. La informacin debe ser
ordenada por ventas de mayor a menor y visualizada de nuevo.
550 Estructura de datos

15.5. Se desea realizar un programa principal que realice las siguientes tareas con procedi-
mientos o funciones:
a) Leer una lista de nmeros desde el teclado.
b) Visualizar dichos nmeros.
e) Ordenar en modo creciente.
d) Visualizar lista ordenada.
e) Buscar si existe el nmero 444 en la lista.

Ampliar el programa anterior de modo qu.e pueda obtener y visualizar en el programa


principal los siguientes tiempos:

tI. Tiempo empleado en ordenar la lista de coordenadas.


12. Tiempo que se empleara en ordenar la lista ya ordenada.
t3. Tiempo empleado en ordenar la lista ordenada en orden inverso.

15.6. Se leen dos listas de nmeros enteros, A y B, de 100 Y 60 elementos, respectivamente. Se


desea resolver mediante procedimientos las siguientes tareas:
. .

a) Ordenar cada una de las listas A y B.


b) Crear una lista C por intercalacin o mezcla de las listas A y B.
e) Localizar si existe en la lista C el nmero 255.
Se desea visualizar tambin en el programa principal las siguientes tareas:
a) Escribir un mensaje existe/no existe el nmero 255.
b) Visualizar la lista C ordenada.

15.7. Escribir un programa que genere un vector de 10.000 nmeros aleatorios de l a 500.
Realice la ordenacin del vector por dos mtodos:
Binsort
Radixsort
Escriba el tiempo empleado en la ordenacin de cada mtodo.
15.8. Escribir un programa que lea una serie de nmeros enteros, los ordene en orden descen-
dente y a continuacin visualice la lista ordenada.
15.9. Un mtodo de insercin muy simple, pero no muy eficiente, de elementos X" X 2, . , X.
en orden ascendente es el siguiente:
Paso 1: Localizar el elemento ms pequeo entre XI y X. y cambiarlo con XI'
Paso 2: Localizar el elemento ms pequeo entre X 2 y X. y cambiarlo con X 2

En el ltimo paso, los dos ltimos elementos se comparan e intercambian, si es necesa-


rio, y la ordenacin se termina. Escribir un programa para ordenar una lista de elementos
siguiendo este mtodo
15.10. La fecha de nacimiento de una persona est representada por el registro
Fecha = record dia: 1..31; mes: 1..12; anno: 1900 ..2010 end. Escribir un programa que
tenga como entrada el nombre y la fecha de nacimiento de los alumnos de un colegio. La
Ordenacin, bsqueda y mezcla 551

salida ha de ser un listado en orden de nacimiento. Utilizar como mtodo de ordenacin


RadixSort (sin convertir fecha).
15.11. En un archivo se ha guardado la lista de pasajeros de un vuelo con salida en Roma.
Se sabe que el nmero de pasajeros no sobrepasa los 350 y que cada pasajero est iden-
tificado con un nmero de control en el rango de 1 a 999. Por un error informtico
hay nmeros de control repetidos. Escribir un programa que realice las siguientes ope-

racIOnes.

a) Ordenar en memoria interna la lista de pasajeros por el nmero de control.


b) Los pasajeros que tienen un nmero de control repetido, asignarles el nmero de
control no existente ms bajo.
e) Escribir en el archivo la lista de pasajeros en orden creciente del nmero de control.
15.12. Dado un vector x de n elementos reales, donde n es impar, disear una funcin que calcu-
le y devuelva la mediana de este vector. La mediana es el valor tal que la mitad de los
nmeros son mayores que el valor y la otra mitad son menores. Escribir un programa que
compruebe la funcin.
15.13. Se implementan cadenas de caracteres mediante arrays de caracteres de una dimensin.
Disear un programa que ordene cadenas. Aplicar el mtodo de RadixSort para la orde-
.,
naclOn.
15.14. Se quiere construir una agenda telefnica con la siguiente informacin: nombre, domici-
lio y nmero de telfono. Disear un programa para mantener la agenda, que como mu-
cho almacenar informacin sobre 100 personas, de tal forma que la bsqueda se realice
por el nombre de la misma y que se mantenga durante su procesamiento ordenada alfab-
ticamente de forma ascendente.
,


Ice


abierto-cerrado, 93 bsqueda secuencial, 536
Abstraccin, 3, 4, 5, 24, 84, 97, 107 de ordenacin, 565
Ada, 24 eficiencia, 553
Ada 95, 115 notacin O-grande, 556
Algoritmo, 4 ordenaciones cuadrticas, 514
anlisis, 553-571 orden de magnitud, 554

rbol de expansin de coste mnimo, 483, ordenacin por burbuja, 507, 566

488 ordenacin por insercin, 567 .


backtraking, 277 ordenacin por mezcla, 568
bsqueda de puntos de articulacin, 447 ordenacin Radix sort, 570
camino ms corto, 462, 467 ordenacin rpida, 520, 569
del aumento de flujo, 476 ordenacin por seleccin, 509, 565
de la mochila, 290 ordenacin por insercin, 514


Dijkstra, 455,461,464 tablas comparativas de tiempos, 571
diseo, 42 Anlisis, 3
divide y vencers, 267 ANSI,49
eficiencia, 553 Archivos, 581
, Prim y Kruskal, 455, 484, 486 Apuntador, 126-130. Vase Punteros
I
Ford-Fulkerson, 479 Archivos, 74
flujo, 470 aumento de la velocidad, 622
fundamentales, 455 compilados, 79
r Kruskal, 486 de inclusin, 74
ordenacin topolgica, 456-459 funcin de direccionamiento hash,
problema de la mochila, 290 622
problema de la seleccin mltiple, 297 indexados, 645
problema de las ocho reinas, 286 ordenacin, 655
problema de los matrimonios estables, resolucin de colisiones, 625
300 texto, 617
problema del laberinto, 293 Arrays,
problema del salto del caballo, 279, 281 circulares, 231
problema del viajante de comercio, 298 Asercin, 16
Torres de Hanoi, 167,271 Aserto, 16
vuelta atrs, 277
vuelta del caballo, 279
Warshall, 435, 459 Biblioteca de software, 110
Anlisis de algoritmos, 553-571 Bicola,239
bsqueda lineal, 536 estructura, 240

851
,


852 In dice

Booch, 106 FIFO,256


Bucle, 19 implementacin, 229
bug, 39 con arrays circulares, 231
Burbuja, 503 con listas circulares,

237
Bsqueda, 536 con listas enlazadas, 237
binaria, 536, 540, 563 Operaciones, 230, 231
anlisis, 543 Aadir, 230
eficiencia, 542 Borrar, 234
binaria recursiva, 544 Cola llena, 230, 233
conversin de claves, 536 Cola vaca, 230, 233
eficiencia de los algoritmos, 563 Quitar, 230, 234
lineal, 536 Siguiente, 233
anlisis, 536 TAD, 227, 228, 231
secuencial, 536, 563 Frente, 234
tablas comparativas de tiempos, 571 Cola de prioridad, 227, 244-252
!,
- implementacin, 245
1
i mediante una lista, 245
,
mediante lista de n colas, 246
C++,24 problema resuelto con, 247, 252
I Cadena de caracteres, 202 Comprensibilidad, 26
,
mediante listas circulares, 202 Concurrencia, 109
Calidad del software, 8 Correccin, 22
,
compatibilidad, 9 Chip de software, 110
I correccin, 8
,I eficiencia, 8
1 extensibilidad, 9
,,
facilidad de utilizacin, 8
i, Datos, 12, 96
factores, 8
flujo de, 12
integridad, 8
I
,
, reutilizacin, 9
predefinidos, 96
Depuracin, 3, 23, 38, 40, 41
1 robustez, 8
,
Depurador, 46
transportabilidad, 8
j verificabilidad, 8
Dijkstra, 13
Diseo, 3, 11
,1 Ciclo de vida, 3, 9
1 descendente, 5, 23
, anlisis, 10
dispose, 126, 137, 145, 160
definicin del problema, 10
divide y vencers, 267
depuracin, 10
Documentacin, 3, 35
, diseo, 10
del programa, 37
especificacin, 10
, externa, 37
implementacin, 10
interna, 37
mantenimiento, 10
manual de mantenimiento, 35, 36
requisitos, 10
manual de usuario, 35
Clasificacin, 502
Codificacin, 12, 15
Cola, 227
acolar, 256
bicola, 239 Eficiencia, 3, 27, 46
desacolar, 256 Eiffel, 115
especificacin formal, 228 Encapsulacin, 107
Final,231 Encapsulamiento, 7, 24
,
Indice 853

Errores, 32 Funcin, 32
compilacin, 44 hash, 623
localizacin, 39 Fusin, 546
lgicos, 45 .


reparacin de, 39
sintaxis, 44 gda,456
tiempo de ejecucin, 45 Genericidad, 110
tratamiento, 323 getmem, 145, 146
Estructura de datos, 5 goto, 31
dinmica, 125 grafo, 417
, .
estattca, 126 rbol de expansin mnimo , 48

es-un, 108 camino, 420


Es Vacia, 208 componentes conexas, 437
Expresin aritmtica, 215 componentes fuertemente conexas, 439
evaluacin, 215 conexo, 421

algoritmo de, 216 coste mnimo, 483


notaciones, 215 definiciones, 418
~ postfija,215 dirigidos, 418, 419, 493
i,, prefija, 215 de entrada, 419
I de Ford y Fulkerson, 472

de salida, 419
I
Fibonacci, 264 flujo , 470
Ficheros, 581 fuertemente conexo , 421
I bases de datos, 584 lista de adyacencia, 424
I, bloque, 585 matriz de adyacencia, 424
i campo, 582 matriz de caminos, 442, 459
I
,! clave, 585 no dirigidos, 418, 419
iI concepto, 581, 583 realizacin con listas de adyacencia,

estructura jerrquica, 581 426


factor de bloqueo, 585
~
realizacin con matriz de adyacencia,
operaciones 426
actualizacin, 591 recorrido, 431
clasificacin, 592 en anchura, 431
consulta, 590 realizacin, 433
-,
!
creacin, 590
destruccin, 592
en profundidad, 434
realizacin, 435
estallido, 592 representacin, 421
fusin, 592- 593 gda, 456
mantenimiento, 594 TAD, 426
procesamiento, 596
. .,
reorgamzaclOn, 592
.,
reumon,592
heap, 143
rotura, 592, 594
. ., Herencia, 7, 88
orgamzaclOn
Herramientas de resolucin de problemas
directa, 589 5 '
secuencial , 588
,
\ registro, 583
.i.
fisico, 585
FIFO, 227, 256 $1, 74
FreeMem, 146 Identificador, 30, 71

,.
i
,

854 In dice

. Implementacin, 12 Mantenimiento, 3, 14, 15


include, 74 Mark, 145
Ingeniera de software, 3, 9 MaxAvail, 145,147
Integracin, 13 MemAvai 1 , 145, 147
Intercalacin, 546 Memoria, 144
Interfaz, 26, 92 asignacin, 145
invariante, 14, 19 liberacin, 145
ISO, 49 Mezcla, 546
dos lista s, 547
Modelado, I I
Legibilidad, 23, 33 de datos, 11
Lenguaje de programacin, 111 Modelo objeto, 106
basado en clases, 114 Modificabilidad, 25
basado en objetos, 114 Modula-2, 24
clasificacin, 112, 114 Modularidad, 5, 6, 23, 25, 83, ll9, 107
criterios, 115 Modularizacin, 91
evolucin, 112 Mdulo, 5, 24, 53, 86-87, 90
genealoga, 113 acoplamiento, 94
hibrido,115 cohesin, 95
orientado a objetos, 114 cohesivos, 6, 25, 95
LlFO, 208 di seo, 94
Li sta circular, 179 estructura, 91
especificacin, 195 implementacin , 90
implementacin, 196 interfaz, 90
,
Lista doblemente enlazada, 179 Motculo, 143, 523
aplicacin, 186
creacin de nodos, 181
eliminacin de nodos, 184
I
especificacin, 179 new, 126, 130-134, 145, 160
implementacin, 180 nil, 138, 151
, programa Ambulatorio, 192 Nodo, 134
j Li sta enlazada, 153, 208

bsqueda, 162
especificacin formal, 153, 155

implementacin con arrays, 156 $0,76


,,; implementacin con punteros, 159 Objeto, 7, 24, 88,118
Inf o , 162 beneficios, 118
iniciar, 162 Objetos , 683
insercin, 164 clases, 685
nodo, 154 conceptos, 683
operaciones, 155 constructor, 717, 721
de direccin, 163 declaracin , 692, 693
recorrido, 168 definicin, 694
supresin de un elemento, 166 destructor, 707, 717
TAD lista , 153 dinmicos, 705, 717
vaca, 154 disp ose ,724
variable de puntero , 160 estructura, 684
Lista ordenada, 168 herencia , 696
bsqueda, 168 simple, 698
implementacin, 168 jerarqua, 715
Indica 855

mtodos, 685, 705 Pascal, 53, 829


anulacin, 718 gua de usuario, 829-849
implementacin, 693 Persistencia, 88, 109
virtuales, 716 Persistencia, 829-849
liberacin de memoria, 707 Pila, 207
new, 724 cima, 209
OOP,683 Cima, 209
polimorfismo, 714 definicin, 207, 224
POO, 683 . especificacin formal, 207
privada, 691 Esvacia,209, 212
private, 725 evaluacin de expresiones aritmticas,
public,725 215-218,222
pblica, 691 algoritmos, 216
recursivo, 263 fondo, 208
Self,709 implementacin, 208
sintaxis, 684 con arrays, 208
subclase, 697 con listas enlazadas, 208
unidades, 694 con variables dinmicas, 211
uso, 695 UFO, 208
variables instancia, 685 Meter, 209, 212
Obsolescencia, 15 Operaciones, 208
Ocultacin de la informacin, 5, 7, 24, 87, 93 Pilallena, 209
Ordenacin, 501-503 pilavacia, 209, 212
binsort, 529-533 Sacar,212
burbuja, 503-510 Suprime, 209, 212
anlisis, 510 Utilizacin, 210
heapsort, 525 Unidad ExpPost, 220
insercin, 512 Notaciones de expresiones, 215
mtodos, 503 polaca, 215
por montculso, 525-529 polaca inversa, 215
rpida, 517 postfija, 215, 216, 220
Quicksort, 517- 522 prefija, 215
radixsort, 533 Pilavacia, 208, 212
seleccin, 510 Plantillas, 98
Shell, 514- 517 Polimorfismo, 7, 8, 88, 108
Ordenacin externa, 655 POO,88
mtodos, 655 Portabilidad, 49
mtodo polifsico, 667 Postfija, 215, 216, 220
mezcla directa, 656 Postcondicin, 12, 16-18
mezcla equilibrada, 661 Precondicin, 12, 16-18
mezcla simple, 656 Prefija, 215
Orientacin a objetos, 105 Prioridad, 244
Overlay,75 cola de, 214-252
Problemas de programacin, 4
resolucin, 4
Paquete, 87 Procedimiento, 86
Parmetros, 31 recursivo, 263
valor, 31 Programa, 15,29
variable, 31 construccin, 52, 61 I
I
parte-de, 108 correccin, 22

l
r

,
856 Indice

obsoleto, 15 Requisitos, 11
reglas para pruebas, 17 especificacin, 11
verificacin, 16 Reutilizacin, 110
Programacin, 5
a gran escala, 9
a pequea escala, 9
Simula, 98
equipos, 41
Smalltalk, 114
estilo, 28
Software, 15
estructurada, 11 6
ciclo de vida, 3, 9, 15
facilidad de uso, 27
construccin, 106
imperativa, 98
evolucin, 15
orientada a objetos, 9
le, 110
paradigma, 88
iteracin, 15
segura contra fallos, 26
sistemas de, 23
Programacin orientada a objetos, 5, 7, 9,
Solapamiento, 75
683
sort, 500
PROLOG,89
Subprograma, 29

Prueba, 3, 13, 15,42


reglas, 17
Pseudocdigo, 13
Puntero, 125, 127-130 TAD, 5, 7, 24, 84, 87, 99-102, 207, 227, 426
asignacin, 135 implementacin, 101
!

comparacin, 139 ventajas, 10 1


I
declaracin, 127 Tecnologas Orientadas a Objetos, 118
,
I iniciacin, 135 beneficios, 119
, lista enlazada, 160 testing, 3, 42

naturaleza, 138 Transportabilidad, 3, 49


, .
paso con parmetros, 141 Tipo Abstracto de Dato, 5. Vase TAD
i
variable, 127, 134, 160 Tipo genrico pointer, 142
Torres de Hanoi, 267-269
concepto, 267
Recursin resuelto sin recursividad, 271
Recursividad, 5, 263 traza de un segmento, 269
algoritmos recursivos, 263-265 Transportabilidad, 3, 49
cundo no utilizar, 264 Turbo Pasacal,
divide y vencers, 267 depuracin, 783, 790
eliminacin de, 266 orientada a objetos, 794
el viajante de comercio, 298 depurador integrado, 788
I
!
generacin de permutaciones, 296 editor, 765-767, 779

implementacin, 270-277 errores, 783
! objetos recursivo, 263 cdigos, 797

ocho reinas, 286, 288 mensajes, 797

I,,
problema del laberinto, 293 tratamiento, 793

problema de la mochila, 290 gua de referencia, 807


, problema de la seleccin ptima, 297 mens, 769

problema de los matrimonios estables, Compile, 773
300-306 Debug,774
procedimiento recursivo, 263 Edi t ,770
Redundancia, 24 Help,778
release, 146 Opt ions, 775


ndice 857

Run,774 Graph,740 ,

Search,771 Lito, 241


Window,777 Overlay, 77-80, 740
Printer, 68, 740, 741
Situacin, 69
UCP, 24,53,91 Strings,760
Unidad, 25, 53, 91, 739-764 System, 66, 740
cabecera, 54 uso, 61
compilacin, 74 circular, 64
concepto, 54 utilizaci n, 65
creacin, 57 ventajas, 57
Crt, 66, 753 uses, 63
declaraciones, 62
DOS, 67
estndar, 739 Vademcum de matemticas, 73
estructura, 54, 58, 72 var, 31
excepciones, 73 variable, 31
Graph,68 dinmica, 126
implementation, 54, 56 puntero, 125, 127-130, 160
initialization,54 operaciones con, 161
interface, 54-55 referenciada, 11>0
DOS, 741-744 Vector dinmico, 172
Crt,740 Verificacin, 13

,
.

I
f
,,
,

,
,,
-r'" _ ,

You might also like