Documente Academic
Documente Profesional
Documente Cultură
ESTRUCTURAS DE DATOS
Un enfoque orientado a objetos
RODOLFO E. ARANA GONZALES
SASCI
01/01/2009
APUNTES DE
ESTRUCTURAS DE DATOS
Un enfoque orientado a objetos
RODOLFO E. ARANA GONZALES
Prefacio
El autor
Tabla de contenido
PREFACIO ............................................................................................................................................................ 3
1.
1.
SASCI
SASCI
Por ltimo, indicar que un TAD puede ser construido a partir de otro TAD ya definido. Por
ejemplo se pueden definir pilas, colas y rboles a partir de arrays o listas enlazadas. De hecho, las
listas enlazadas tambin pueden construirse a partir de arrays y viceversa.
Los tipos de datos abstractos (TAD) describen un conjunto de objetos con la misma
representacin y comportamiento. Los tipos abstractos de datos representan una separacin clara
entre la interfaz externa de un tipo de dato (nivel lgico) y su implementacin interna (nivel
fsico). La implementacin de un tipo abstracto de datos est oculta, por consiguiente se pueden
utilizar implementaciones alternativas para un mismo tipo abstracto de datos sin cambiar su
interfaz favoreciendo as las etapas de correccin y depuracin del software pues se puede
cambiar o mejorar un algoritmo interno sin cambiar su interfaz de modo tal que no afecta a los
dems mdulos del software.
Hoy en da con los nuevos paradigmas de programacin orientada a objetos, la aplicacin de los
conceptos de abstraccin se aplican mejor en paquetes cerrados llamados (clases) los cuales
presentan una interfaz al usuario de estas clases permitiendo solo el acceso a los mtodos y
operaciones definidas para este T.A.D., ocultando los detalles de la implementacin de tales
mtodos, aplicando as el concepto de abstraccin y facilitando al diseador del software pues
este utilizara dicha interfaz para construir aplicaciones sin la necesidad de preocuparse por
detalles de la implementacin del (T.A.D) Gracias a este concepto de abstraccin y la aplicacin
de la programacin orientada a objetos hoy por hoy se agiliza grandemente la realizacin de
proyectos de desarrollo de software desde proyectos que se terminaban en aproximadamente un
ao, a un mes; causando un gran impacto en el mercado del software. Por tanto las compaas de
desarrollo de software que no apliquen estos conceptos tienden a quedar en una gran desventaja
con sus competidores.
En trminos formales, a nivel lgico una Estructura de Datos d se define como una tripleta
compuesta por con conjunto de dominios D, un conjunto de funciones u operaciones F y un
conjunto de axiomas A.
d = (D, F, A)
donde:
D
F
A
El conjunto de dominios consiste en los tipos de datos primitivos que utiliza la estructura
Es el conjunto de funciones que manipulan los datos
Describen el significado de las funciones
SASCI
de una rreglo son del mismo tipo, es decir es una estructura homognea. El almacenamiento se
hace asociando un valor con cada ndice y la recuperacin significa que a partir de un ndice se
puede obtener el valor.
Aqu en conjunto dominios seran los enteros (para los ndices) y un tipo de dato (para los
valores), el conjunto de operaciones seran aadir un valor y recuperar un valor. Los axiomas
sera el significado de aadir un valor y el significado de recuperar un valor.
Por ejemplo, el siguiente arreglo es de nmeros enteros
Valores
(elementos)
242
666
45
-6
321
31
12
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
Indices
(posiciones)
Enero
Febrero
Marzo
Abril
Mayo
Junio
Julio
Agosto
Septiembre
Octubre
Noviembre
Diciembre
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]
[10]
[11]
[12]
Para realizar operaciones con arreglos, es necesario hacer operaciones a nivel de cada elemento;
es decir, por ejemplo cargar con datos un arreglo (leer) significara cargar cada elemento mediante
una instruccin apropiada del lenguaje de programacin.
Las principales operaciones con arreglos son: leer, imprimir, buscar mximo y mnimo, hallar
totales y subtotales, buscar un elemento, clasificar u ordenar un arreglo.
SASCI
Bsqueda secuencial
Tambin llamada bsqueda lineal. Este proceso consiste en que dado el valor que se busca, se lo
debe comparar con cada valor del arreglo hasta dar con el que se busca; en ese momento se
captura la posicin o ndice. En caso de haber revisado todos los valores y no encontrar el valor,
se dir que el valor no se encuentra. Un algoritmo para este proceso es el siguiente:
entero BsquedaSecuencial( V arreglo, n tamao, x valor, i ndice) // devuelve el indice
Inicio
encontrado = falso
i = -1
k=1
mientras (no encontrado ) y (k <= n)
si V[k] = x entonces
encontrado = verdadero
i=k
fin_si
k=k+1
fin_mientras
BusquedaSecuencial = i
Fin
El algoritmo de bsqueda secuencial no es optimo para cuando el tamao del vector es grande,
puesto que el nmero de comprobaciones (si-entonces) es, en promedio, (n+1)/2, es decir
aproximadamente igual a la mitad de los elementos del vector.
Bsqueda binaria
SASCI
No olvidemos que la bsqueda binaria requiere que el vector est ordenado, y en la prctica esta
condicin puede ser difcil de mantener, sin embargo, en contrapartida, la bsqueda binaria es un
mtodo muy rpido ya que el nmero de comparaciones es pequeo en relacin al tamao del
vector. Se ha determinado que el nmero mximo de comparaciones esta dado por log2 n.
Esto significar que si se tienen100 elementos, requerirn solo 7 comparaciones como mximo.
Si son 100000 elementos, el nmero de comparaciones ser de 20.
Clasificacin
SASCI
Ordenacin de arreglos
Ordenacin de archivos (ordenacin externa)
La ordenacin de arreglos se denomina tambin ordenacin interna, ya que se realiza y almacena
en la memoria de una computadora de gran velocidad y acceso aleatorio. La ordenacin de
archivos se suele hacer casi siempre sobre soportes de almacenamiento externo, discos, cintas,
etc. Por ello se denomina tambin ordenacin externa. Estos dispositivos son ms lentos en las
operaciones de E/S, pero por el contrario, pueden contener mayor cantidad de informacin.
En este curso veremos solo la ordenacin interna. Los principales mtodos de ordenacin de
arreglos son:
Insercin
o Insercin directa (baraja)
o Insercin binaria
Intercambio
o Burbuja
o Pares no adyacentes
Seleccin
Shell
Ordenacin rpida (quick-sort)
Mtodo de intercambio o de Burbuja
SASCI
Inicio
temporal = x
x=y
y = temporal
Fin
Mtodo de la Baraja
Es un mtodo de insercin, consiste en insertar un elemento en una parte del vector ya ordenada y
comenzar de nuevo con los elementos restantes. Por ser utilizado generalmente por los jugadores
de cartas se le conoce con el nombre de Baraja.
Baraja(V vector, n tamao)
Inicio
para i = 2 hasta n
aux = V[i]
k=i-1
u = i-1
bandera = Falso
mientras bandera < > Falso y k >= 1 hacer
si aux < V[k] entonces
V[k+1] = V[k]
k=k1
sino
bandera = Verdad
fin_si
fin_para
fin_mientras
V[k+1] = aux
Fin
Metodo QuickSort
SASCI
La lista queda separada en dos sublistas, una formada por los elementos a la izquierda del
pivote, y otra por los elementos a su derecha.
Repetir este proceso de forma recursiva para cada sublista mientras stas contengan ms de
un elemento. Una vez terminado este proceso todos los elementos estarn ordenados.
Como se puede suponer, la eficiencia del algoritmo depende de la posicin en la que termine el
pivote elegido.
En el mejor caso, el pivote termina en el centro de la lista, dividindola en dos sublistas de
igual tamao. En este caso, el orden de complejidad del algoritmo es O(nlog n).
En el peor caso, el pivote termina en un extremo de la lista. El orden de complejidad del
algoritmo es entonces de O(n). El peor caso depender de la implementacin del algoritmo,
aunque habitualmente ocurre en listas que se encuentran ordenadas, o casi ordenadas.
En el caso promedio, el orden es O(nlog n).
No es extrao, pues, que la mayora de optimizaciones que se aplican al algoritmo se centren en
la eleccin del pivote. Una versin en C++ que ordena un vector de tipo numrico es la siguiente
es la siguiente:
void QuickSort(float V[], int m, int N)
{
int i, j, p;
if (m < N)
{
i = m; j = (N) + 1; p = V[m];
do
{
do i++; while(V[i]<p);
do j--; while(V[j]>p);
if (i<j)
intercambiar(V[i], V[j]);
else
break;
}
while (1);
intercambiar(V[m], V[j]);
QuickSort(V, m, j-1);
QuickSort(V, j+1, N);
}
}
void intercambiar(float &x, float &y)
{
float aux = x; x = y; y = aux;
}
SASCI
10
SASCI
funcin distinta, se tiene que en la primera generacin de los sistemas software funciones y datos
se entremezclaban.
SASCI
ni las tcnicas funcionales, ni las orientadas a objeto son suficientes para capturar todas las
decisiones de diseo que el programa debe implementar.
Con las descomposiciones tradicionales no se aislan bien estos otros aspectos, sino que quedan
diseminados por todo el sistema enmaraando el cdigo que implementa la funcionalidad bsica,
y yendo en contra de la claridad del mismo. Se puede afirmar entonces que las tcnicas
tradicionales no soportan bien la separacin de competencias para aspectos distintos de la
funcionalidad bsica de un sistema, y que esta situacin claramente tiene un impacto negativo en
la calidad del software.
La programacin orientada a aspectos (POA) es una nueva metodologa de programacin que aspira
a soportar la separacin de competencias para los aspectos antes mencionados. Es decir, que
intenta separar los componentes y los aspectos unos de otros, proporcionando mecanismos que
hagan posible abstraerlos y componerlos para formar todo el sistema. En definitiva, lo que se
persigue es implementar una aplicacin de forma eficiente y fcil de entender.
Para propsito de esta discusin, un lenguaje ser considerado Orientado a Objetos Puro si
satisface todos los seis tems nombrados. Ser hbrido si slo cumple con algunos de esos 6
lineamientos (por lo generar son hbridos cumpliendo los tres primeros).
Programacin Orientada a Objeto
Los objetos son entidades que combinan estado, comportamiento e identidad:
El estado est compuesto de datos, sern uno o varios atributos a los que se habrn
asignado unos valores concretos (datos).
El comportamiento est definido por los procedimientos o mtodos con que puede operar
dicho objeto, es decir, qu operaciones se pueden realizar con l.
12
SASCI
La identidad es una propiedad de un objeto que lo diferencia del resto, dicho con otras
palabras, es su identificador (concepto anlogo al de identificador de una variable o una
constante).
La programacin orientada a objetos expresa un programa como un conjunto de estos objetos,
que colaboran entre ellos para realizar tareas. Esto permite hacer los programas y mdulos ms
fciles de escribir, mantener y reutilizar.
De esta forma, un objeto contiene toda la informacin que permite definirlo e identificarlo frente
a otros objetos pertenecientes a otras clases e incluso frente a objetos de una misma clase, al
poder tener valores bien diferenciados en sus atributos. A su vez, los objetos disponen de
mecanismos de interaccin llamados mtodos que favorecen la comunicacin entre ellos. Esta
comunicacin favorece a su vez el cambio de estado en los propios objetos. Esta caracterstica
lleva a tratarlos como unidades indivisibles, en las que no se separan ni deben separarse el estado
y el comportamiento.
Los mtodos (comportamiento) y atributos (estado) estn estrechamente relacionados por la
propiedad de conjunto. Esta propiedad destaca que una clase requiere de mtodos para poder
tratar los atributos con los que cuenta. El programador debe pensar indistintamente en ambos
conceptos, sin separar ni darle mayor importancia a ninguno de ellos, hacerlo podra producir el
hbito errneo de crear clases contenedoras de informacin por un lado y clases con mtodos que
manejen a las primeras por el otro.
Entre los lenguajes orientados a objetos se destacan los siguientes:
Ada
C++
C#
Lenguaje de programacin D
Object Pascal (Delphi)
Eiffel
Java
JavaScript (la herencia se realiza por medio de la programacin basada en prototipos)
Lexico (en castellano)
Objective-C
Ocaml
Oz
Lenguaje de programacin R
Perl
PHP (en su versin 5)
Python
Ruby
Smalltalk
13
SASCI
Magik (SmallWorld)
VB.NET
Visual FoxPro (en su versin 6)
Visual Basic
XBase++
Muchos de estos lenguajes de programacin no son puramente orientados a objetos, sino que son
hbridos que combinan la POO con otros paradigmas
14
SASCI
adecuado al objeto pertinente. Tambin se puede definir como evento, a la reaccin que
puede desencadenar un objeto, es decir la accin que genera.
Mensaje: una comunicacin dirigida a un objeto, que le ordena que ejecute uno de sus
mtodos con ciertos parmetros asociados al evento que lo gener.
Propiedad o atributo: contenedor de un tipo de datos asociados a un objeto (o a una
clase de objetos), que hace los datos visibles desde fuera del objeto y esto se define como
sus caractersticas predeterminadas, y cuyo valor puede ser alterado por la ejecucin de
algn mtodo.
Estado interno: es una variable que se declara privada, que puede ser nicamente
accedida y alterada por un mtodo del objeto, y que se utiliza para indicar distintas
situaciones posibles para el objeto (o clase de objetos). No es visible al programador que
maneja una instancia de la clase.
Componentes de un objeto: atributos, identidad, relaciones y mtodos.
Representacin de un objeto: un objeto se representa por medio de una tabla o entidad
que est compuesta por sus atributos y funciones correspondientes.
SASCI
Para que una definicin recursiva est completamente identificada es necesario tener un caso base
que no se calcule utilizando casos anteriores y que la divisin del problema converja a ese caso
base.
Ejemplo: La potencia recursiva
1
si n = 0
(caso base)
x =
x xn1 si n > 0
(caso general)
Otra funcin recursiva es el factorial. Como se puede ver a continuacin la definicin recursiva
es clara.
Definicin recursiva de factorial
1
si n = 0
n . (n 1)!
si n > 0
n! =
Por ejemplo calculamos el factorial con n=3. Este proceso se muestra paso a paso a continuacin:
1) 3! = 3 * 2!
2) 3! = 3 * 2!
2! = 2 * 1!
3) 3! = 3 * 2!
2! = 2 * 1!
1! = 1 * 0!
4) 3! = 3 * 2!
2! = 2 * 1!
1! = 1 * 0!
0! = 1 (caso base)
5) 3! = 3 * 2!
2! = 2 * 1!
1! = 1 * 1
1
6) 3! = 3 * 2!
2! = 2 * 1
1! = 1 * 1 = 1
7) 3! = 3 * 2
2! = 2 * 1 = 2
8) 3! = 3 * 2 = 6
16
SASCI
si n = 0
x xn1
si n > 0
int potencia(int base, int expo){
if (expo==0)
return 1;
else
return base * potencia(base,expo-1);
17
SASCI
si b = 0
1 + suma(a, b 1)
si b > 0
suma(a, b) =
si V [n] = b
si V [0] 6= b
BusquedaLineal(V, n, b) =
(V [n] == b) (b 2 {V [0], . . . , V [n 1]}) en otro caso
int BusquedaLineal(int *V, int n, int b)
{
if (n<0)
return 0;
else
if (V[n]==b)
return 1;
else
return BusquedaLineal(V,n-1,b);
}
SASCI
BusBinRec(v, i, t-1, x)
3. Al modificar los extremos puede darse que i > d, en cuyo caso el proceso termina (Fracaso).
int BusBinRec (int v[], int i, int d, int x) // v arreglo, d tamao, x valor
{
int centro;
if (i<=d) {
centro = (i+d)/2;
if (v[centro]==x) // Caso base 1
return centro;
else
if (v[centro]>x) // Buscar izda.
return BusBinRec (v,i,centro-1,x);
else // Buscar dcha.
return BusBinRec (v,centro+1,d,x);
}
else // i > d
return -1; // Caso base 2
}
19
SASCI
3.2. Pilas
Una pila (o stack) es un tipo especial de lista lineal en la que la insercin y el borrado de nuevos
elementos se realiza slo por un extremo que se denomina cima o tope (top).
20
SASCI
La pila es una estructura con numerosas analogas en la vida real: una pila de platos, una pila de
monedas, una pila de cajas de zapatos, una pila de bandeja, un a pila de libros, etc.
Dado que la operacin de insertar solo puede hacerse por un extremo, -el superior- los elementos
solo pueden eliminarse en orden inverso al que se insertaron en la pilas. El ltimo elemento que
se pone en la pila es el primero que se puede sacar; por ello, a estas estructuras se les conoce por
el nombre LIFO (Last In, First Out) o UEPS (Ultimo en Entrar, Primero en Salir).
Las pilas se pueden representar como en la figura de la izquierda y se pueden implementar en un
arreglo con un determinado tamao, como el la figura de la derecha.
Cima
P-1
Cima
n-1
Otra manera de implementar pilas es de manera dinmica a travs de nodos con punteros; sin
embargo, cualquiera que sea su implementacin, las operaciones sobre las pilas son las mismas y
deben ser transparentes para su utilizacin.
Las operaciones bsicas sobre una pila son: poner o meter un nuevo elemento y sacar o quitar un
elemento. En la siguiente lista se muestran estas y otras operaciones y su significado:
P = Cima
esVaca
Poner
Sacar
LongMax
Entre las muchas aplicaciones de las pilas estn las que se usan en ciencias de la computacin
como el rastreo de llamados a subprogramas, el control de bucles, la evaluacin de expresiones
aritmticas, etc.
Aplicacin de pila: Evaluacin de expresiones
Esta aplicacin consiste en calcular el valor de una expresin aritmtica dada; es decir, siguiendo
las reglas de la aritmtica se debe obtener un valor final. Las expresiones aritmticas,
21
SASCI
Se parte 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:
Operadores:
^, *, / , +, -
La transformacin se realiza utilizando una pila en la que se almacenan los operadores y los
parntesis izquierdos. La expresin se va leyendo carcter a carcter, los operandos 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 izquierdos siempre se meten en la pila, asignndoles la mnima prioridad. Cuando
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 de la pila, ya que
los parntesis no forman parte de la expresin postfija.
El algoritmo termina cuando no hay ms elementos en la expresin infija, y la pila esta vaca.
Sea por ejemplo la expresin infija
A+B*C/(DE)-F
22
SASCI
Items en
Proceso
Resultante
Estado de la
PILA
Pila vacia
B*
AB
Comentario
El operando A va a expresin postfija.
El operador + va a la pila, ya que est vaca.
+*
C/
ABC*
+/
ABC*
+/(
ABC*D
+/(-
D-
E)
ABC*DE-
+/
ABC*DE-/+
ABC*DE-/+F
No hay
ABC*DE-/+F-
Pila vacia
Con el fin de que el algoritmo de conversin de infija a postfija se pueda manejar mejor, es
necesario definir prioridades para los operadores y el parntesis izquierdo.
Operador
^
*, /
+, (
Prioridad
3
2
1
0 (dentro)
23
SASCI
Ejercicio.
1. Hallar el equivalente postfijo de la siguiente expresin infija:
A*(B+C(D/E^F)+G)-H
Respuesta ABC+DEF^/-G+*H2. Escribir el algoritmo para convertir una expresin infija en postfija.
3.3. Colas
Al igual que las pilas, las colas son estructuras de listas lineales pero con una disciplina diferente
de aquellas. Las colas insertan elemento por un extremo y sacan elementos por el otro. Esto se
conoce como FIFO (First In, First Out) o PEPS (Primero en Entrar, Primero en Salir).
Las eliminaciones se realizan por el comienzo de la lista (front) llamado frente, y las inserciones
se realizan por el otro extremo (rear) o final
En la vida real se tienen numerosos ejemplos de colas: la cola de un cine, la cola de atencin en
un banco, una cola de vehculos en una gasolinera, etc. En todas ellas, el primero en llegar es el
primero en ser atendido.
En el campo de informtica tambin se encuentran muchas aplicaciones de colas. Por ejemplo en
un sistema informtico suele haber una impresora que atiende las solicitudes de impresin en el
orden de una cola. Existe otra aplicacin en un sistema de tiempo compartido, donde un
procesador central atiende la peticin de proceso segn el orden de llegada, suponiendo que
existen varias terminales, y otros perifricos que demandan tiempo de procesador.
Un ejemplo bastante actual de aplicacin de colas lo constituye el proceso de atencin al pblico
por parte de bancos y otras entidades. En este caso se pueden presentar no solo una sino varias
colas, en funcin de determinados criterios de atencin o prioridad.
Eliminacin
Insercin
1
n-1
Frente
Final
Las colas se pueden implementar en forma esttica mediante arreglos, como se ve en la figura, o
bien con el uso de punteros, en forma dinmica.
Cuando se implementa en forma esttica en un arreglo se presenta el problema de que luego de
varias inserciones y eliminaciones, la cola parece viajar por el arreglo, hasta que llega a su
lmite final, en cuyo caso el estado de la cola ser aparentemente de cola llena, sin embargo, en el
24
SASCI
frente de la cola pueden haber espacios vacos. Una forma de superar esta limitacin es utilizando
el arreglo como un espacio circular que se recicla con el primer elemento, cada vez que la cola
alcanza el final del arreglo. Este problema se puede abordar de diferentes maneras.
La implementacin ms adecuada para colas es mediante las llamadas listas encadenadas,
mediante el uso de punteros. Esta implementacin se estudiar ms adelante.
Operaciones Bsicas
Crear: se crea la cola vaca.
Poner (push): se aade un
elemento a la cola. Se aade
al final de esta.
Sacar (pop): se elimina el
elemento frontal de la cola,
es decir, el primer elemento
que entr.
Frente (consultar, front): se
devuelve el elemento frontal
de la cola, es decir, el
primero elemento que entr.
Implementacin de la operaciones
Las operaciones bsicas sobre una cola son: poner o meter un nuevo elemento al final y sacar o
quitar un elemento del frente. En la siguiente lista se muestran estas y otras operaciones y su
significado:
F = Frente
R = Final
esVaca
Poner
Sacar
LongMax
Aplicaciones
Ejemplos de colas en la vida real seran: personas comprando en un supermercado, esperando
para entrar a ver un partido de futbol, esperando en el cine para ver una pelcula, una pequea
peluquera, las colas en los bancos, etc. La idea esencial es que son todos lneas de espera.
En estos casos, el primer elemento de la lista realiza su funcin (pagar comida, pagar entrada para
el partido o para el cine) y deja la cola. Este movimiento est representado en la cola por la
funcin pop o desencolar. Cada vez que otro elemento se aade a la lista de espera se aaden al
final de la cola representando la funcin push o encolar. Hay otras funciones auxiliares para ver
25
SASCI
el tamao de la cola (size), para ver si est vaca en el caso de que no haya nadie esperando
(empty) o para ver el primer elemento de la cola (front).
Las colas tambin se utilizan en muchas maneras en los sistemas operativos para planificar el uso
de los distintos recursos de la computadora. Uno de estos recursos es la propia CPU (Unidad
Central de Procesamiento).
Si esta trabajando en una sistema multiusuario, cuando le dice a la computadora que ejecute un
programa concreto, el sistema operativo aade su peticin a su cola de trabajo.
Cuando su peticin llega al frente de la cola, el programa solicitado pasa a ejecutarse.
Igualmente, las colas se utilizan para asignar tiempo a los distintos usuarios de los dispositivos
de entrada/salida (E/S), impresoras, discos, cintas y dems. El sistema operativo mantiene colas
para peticiones de imprimir, leer o escribir en cada uno de estos dispositivos.
26
SASCI
primero = primero->siguiente;
delete aux;
--elementos;
}
T consultar() const {
return primero->elemento;
}
bool vacia() const {
return elementos == 0;
}
unsigned int size() const {
return elementos;
}
};
#endif
Tipos de colas
Colas circulares (anillos): en las que el ltimo elemento y el primero estn unidos.
Colas de prioridad: En ellas, los elementos se atienden en el orden indicado por una
prioridad asociada a cada uno. Si varios elementos tienen la misma prioridad, se atendern
de modo convencional segn la posicin que ocupen. Hay 2 formas de implementacin:
1. Aadir un campo a cada nodo con su prioridad. Resulta conveniente mantener la cola
ordenada por orden de prioridad.
2. Crear tantas colas como prioridades haya, y almacenar cada elemento en su cola.
Bicolas: son colas en donde los nodos se pueden aadir y quitar por ambos extremos; se
les llama DEQUE (Double Ended QUEue). Para representar las bicolas lo podemos hacer
con un array circular con Inicio y Fin que apunten a cada uno de los extremos. Hay
variantes:
Bicolas de entrada restringida: Son aquellas donde la insercin slo se hace por el final,
aunque podemos eliminar al inicio al final.
Bicolas de salida restringida: Son aquellas donde slo se elimina por el final, aunque se
puede insertar al inicio y al final.
27
SASCI
28
SASCI
5
para i=inicio hasta fin
6
intercambia(arreglo[inicio], arreglo[i]);
7
pemuta(arreglo[ ], inicio+1, fin);
8
intercambia(arreglo[inicio], arreglo[i]);
9 fin_de_funcion;
Escribe una funcin no recursiva que genere todas las permutaciones de arreglo[ ] desde inicio
hasta fin, con la misma complejidad que la funcin que se muestra.
Aplicaciones de Cola
Problema 1. Implementar un programa qupara administrar una cola.
Problema 2.Una cola de atencin al pblico, en realidad es un conjunto de colas que son
atendidas en forma cclica segn determinada prioridad. Esta prioridad puede ser administrada
inclusive sobre la periodicidad de atencin a cada cola; es decir las colas con mayor prioridad
pueden atenderse en forma secuencial un cierto nmero de veces (segn el nmero de elementos
que tengan en ese momento).
Por otra parte, la cantidad de puntos de atencin puede ser diseada segn los requerimientos. EL
programa de ser tan flexible que permita configurar todos estos detalles.Esta aplicacin tiene
como componente principal la interfaz del usuario.
Problema 3. En tu negocio tienes una secuencia de n sillas acomodas en lnea recta y numeradas
de 1 a n, por cada persona que se siente en una silla con el nmero x, debers pagar $x al
gobierno, pero como quieres tener cmodos a los clientes, no tienes otra opcin que pedirles que
tomen asiento; sin embargo, el aprecio por el cliente an no te ha quitado la codicia, por lo que
puedes indicarle a cada cliente donde sentarse, pero el cliente deside cuando irse; desde el
momento que un cliente llega hasta el momento que se va, el cliente pasar todo el tiempo
sentado en una silla y no estar dispuesto a compartirla con nadie mas. Escribe un programa que
dado el historial de qu clientes llegan y qu clientes se van en orden cronolgico, calcule que
asientos asignarles a cada quien para que el dinero que debas pagar al gobierno sea el mnimo
posible. Tu programa deber funcionar en tiempo lineal.
Problema de Listas
Problema 1. Un verdugo es mandado a exterminar a n prisioneros de guerra. El exterminio lo
ejecuta de la siguiente manera: los prinsioneros forman un crculo al rededor del verdugo, el
verdugo elige a quien fusilar primero, una vez muerto el primero, el verdugo cuenta, a partir del
lugar donde estaba su ultima victima, k prisioneros en orden de las manesillas del reloj, y luego
fusila al k-simo prisionero despues de su ltima vctima (a los muertos no los cuenta), y repite
este proceso hasta que solo quede un prisionero. El ltimo prisionero podr ser liberado. El
verdugo tiene un amigo entre los n prisioneros, escribe un programa que dado, n, k y la ubicacin
de su amigo, le diga a quien fusilar primero, para asegurar que su amigo sea el que quede libre.
29
SASCI
4. Almacenamiento dinmico
4.1 Manejo dinmico de la memoria Los punteros
Cmo se almacena una variable?
Una computadora opera manipulando direcciones de memoria y los valores almacenados en
dichas direcciones. Un lenguaje de programacin es una herramienta que permite al programador
codificar operaciones binarias en un lenguaje ms parecido a nuestro lenguaje natural. Un
programa que realiza la traduccin de instrucciones desde un lenguaje de programacin dado al
lenguaje de maquina se llama compilador.
Una variable es un recurso, entre otros, para manipular un dato binario de modo ms legible. Una
variable es un identificador de dato, al igual que el nombre de una funcin, este NOMBRE
representa para la maquina una localidad de memoria donde el programa puede almacenar y
manipular un dato.
Una declaracin de variable como:
char xx=B;
int nn=25;
produce una asociacin entre los nombre 'xx', nn y sus correspondientes espacios de
almacenamiento en memoria. Por lo tanto hay dos elementos relacionados con el nombre de una
variable: un valor que se puede almacenar all y una direccin de memoria para la variable.
Existe una correspondencia entre el nombre de cada variable y una direccin de memoria a quien
representa; es decir, el nombre de la variable propiamente dicha (por ejemplo xx) es solo un
smbolo grfico que realmente significa una direccin. Esta asociacin podemos representarla
como una tabla virtual de variables. En consecuencia, esta tabla, luego de las anteriores
declaraciones y asignaciones, podra tener el siguiente estado:
Nombre de la variable
Direccin de memoria
xx
0012FF8B
nn
0012FF84
Realmente las direcciones de la tabla virtual existen en lo que podramos llamar el espacio real
de datos, el cual se puede representar como una tabla que podra tener el siguiente estado:
Direccin de memoria
Contenido
0012FF8B
00000042
0012FF84
00000019
25
30
SASCI
Adems del identificador "xx", tenemos la palabra "char" que nos indica el tipo (type) de la
variable. El tipo nos indica:
Cuantas celdas de memoria se reservan para ese nombre de variable; es decir cuantos bytes.
Como se interpretarn los bits contenidos en ese espacio o direccin de memoria
Para el manejo de direcciones y contenidos de variables existen dos operadores: & de direccin y
* de indireccin.
Operador de direccion &. El operador (ampersand) & aplicado como prefijo a una variable,
devuelve la direccin de memoria en la que se encuentra la variable (sea variable normal o
variable puntero).
Operador de indireccion *. El asterisco escrito como prefijo de una variable puntero o de una
direccin de memoria, permite acceder o referirse al contenido de dicho puntero o direccin de
memoria.
Por ejemplo:
&xx : devuelve la direccin en la que se encuentra la variable xx.
*xx: permite acceder al contenido de la variable xx.
Entonces, si escribimos:
*(&xx) = C;
Por otra parte se sabe que un byte es la menor unidad de informacin que pueden direccionar la
mayora de las computadoras. En la mayora de las arquitecturas el tipo char ocupa un solo byte.
Un bool admite solo dos valores diferentes, pero es almacenado como un byte. El tipo int de C++
ocupa generalmente 2 bytes, un long 4, double 8, y as con el resto de los tipos.
El otro punto es la relacin entre lo que hay en una celda de memoria y como es interpretado. Lo
que hay en un celda cuya extensin es un byte es simplemente un conjunto de ocho estados
posibles (8 bits) que a nivel hardware admiten dos estados diferenciables, estados que pueden ser
simbolizados como 'verdadero/falso', 0/1, o cualquier otro par de valores.
As, la variable xx del ejemplo anterior en el espacio de datos, tiene como contenido lo siguiente:
31
SASCI
00000042
Pero que significa este contenido?, Depende en gran medida del tipo (type) que hayamos
asociado a esa celda (y suponiendo que exista tal asociacin). Ese contenido interpretado como
un hexadecimal es 0x42, en decimal es 66, y si fue asociado al tipo char (este es el caso del
ejemplo) representara la letra 'B', cuyo codigo ASCII es igual a 66. En ninguna localidad de
memoria hay algo como la letra 'B', lo que encontramos son valores binarios que en caso de estar
asociados a char y en caso de que lo saquemos en pantalla como char har que veamos
encendidos ciertos pixeles de pantalla, en los cuales reconoceremos una representacin de la letra
'B'.
Puesto que la representacin binaria de datos ocupa demasiado espacio, es preferible utilizar el
sistema hexadecimal, que adems de ser muy fcil de traducir a binario es ms prctico.
// Puntero a char
// Puntero a entero
x = &xx;
n = &nn;
Luego de las anteriores declaraciones, la tabla virtual de variables podra tener el siguiente
estado:
Nombre de la variable
Direccin de memoria
xx
0012FF8B
nn
0012FF84
*x
0012FF80
*n
0012FF7C
32
SASCI
Tambin podemos suponer que el espacio real de datos podra tener el siguiente estado:
Direccin de memoria
Contenido
0012FF8B
00000042
0012FF84
00000019
25
0012FF80
0012FF8B
Apunta a xx
0012FF7C
0012FF84
Apunta a nn
Como se puede ver, un puntero es, en esencia, una variable cuyo contenido es una direccin de
memoria, que apunta a un tipo dado.
El siguiente programa en C++, prueba lo explicado en este apartado
#include <iostream.h>
#include <stdio.h>
main()
{
char xx='B';
int nn=25;
char *x;
int *n;
x = &xx;
n = &nn;
printf("TABLA DE VARIABLES\n\n");
printf("
Variable
Direccion \n\n");
printf("%15s ", "xx");
printf("%15p \n", &xx);
printf("%15s ", "nn");
printf("%15p \n", &nn);
printf("%15s ", "*x");
printf("%15s ", "*n");
printf("\n\n\nESPACIO DE DATOS\n\n");
printf("
Direccion
printf("%15p ", &xx);
printf("%15p ", &nn);
Contenido Comentario\n\n");
printf("%15p ", xx);
printf(" %-15c \n", xx);
printf("%15p ", nn);
printf(" %-15i \n", nn);
getchar();
}
33
SASCI
Independientemente del tamao (sizeof en C++) del objeto apuntado, el valor almacenado por el
puntero ser el de una nica direccin de memoria. En sentido estricto un puntero no puede
almacenar la direccin de memoria de un arreglo (completo), sino la de un elemento del arreglo,
y por este motivo no existen diferencias sintcticas entre punteros a elementos individuales y
punteros a arrays. La declaracin de un puntero a un tipo char y otro a un arreglo de char es
igual.
Al definir variables o arreglos hemos visto que el tipo (type) modifica la cantidad de bytes que se
usaran para almacenar tales elementos, as un elemento de tipo 'char' utiliza 1 byte, y un entero 2
o 4. No ocurre lo mismo con los punteros, el tipo no influye en la cantidad de bytes asociados al
puntero, pues todas las direcciones de memoria se pueden expresar con solo 2 bytes (o 4 si es una
direccin de otro segmento)
La forma general de declarar un puntero es la siguiente:
TipoDeDato *NombrePuntero
Ejemplos:
int * pe
// pe es un puntero a un entero
float *f
// f es un puntero a float
TMatriz *m
int **t
TRacional *r
34
SASCI
NODO
Dato
Un campo para
almacenar la
direccin de
m emoria del
siguiente nodo de
informacin si este
existe
Link
Dato
Dato
Link
El Campo de enlace
link proporciona la
direccin o referencia
del siguiente nodo de
la lista
Null
Dato
35
SASCI
Dato
Link
Dato
Link
Dato
Link
Para acceder a los elementos de la lista encadenada basta conocer la direccin de memoria del
primer nodo.
Esquema y diseo de una lista enlazada
Dependiendo de donde se aplique la lista enlazada se pueden optar por diversos diseos de
acuerdo a las necesidades del problema en particular a continuacin mostraremos algunos de los
diseos mas utilizados
a) Con un solo puntero
36
SASCI
Para agregar un elemento o llegar al ltimo elemento de la lista se tiene que navegar toda la lista
desde el inicio, este hecho se considera como una desventaja ya que representa una tardanza en el
hecho de navegar secuencialmente de nodo a nodo
Primero
Dato
Link
Dato
Link
Dato
Link
Mejora el inconveniente anterior pero ocupa ms espacio para almacenar el puntero al ltimo
nodo. Si se requiere conocer la cantidad de elementos se tendra que navegar y contar los
elementos (Mucho proceso para algo que puede ser ms simple) este hecho se considera como
una desventaja.
Primero
L
Dato
Ultimo
F
Link
Dato
Link
Dato
Link
class lista {
private :
nodo *L; // apunta al comienzo de la lista
nodo *F; // apunta al final de la lista
int tam;
public:
lista() {
L = NULL;
tam = 0;
}
void tamano();
void anadirFin(char c);
void anadirIni(char c);
void recorrer();
void insertar(int u, char c);
// inserta c despues de la posicin u.
// Si excede el tamao actual inserta al final
void eliminar(int u); // elimina de la posicin u
};
El programa completo se puede ver en clase lista)
37
SASCI
23
Ultimo
Tamao = 3
Link
60
Link
90
Link
Definicin de operaciones
Las principales operaciones que podemos realizar sobre la lista encadenada simple son:
Recorrido
Inserci n
Borrado
Bsqueda
Operacin de Recorrido
Consiste en visitar cada uno de los nodos que forman la lista. Se comienza con el primero, se
toma el valor del campo Link para avanzar al segundo nodo, as sucesivamente.
Cuando se encuentre un link = Null se habr terminado de recorrer la lista
F
x
L
5
9
0
L
5
7
P
38
SASCI
Utilizando una variable auxiliar P que se inicia en L y desde ah se comienza a navegar de nodo
en nodo utilizando el Link de cada uno de ellos. El hecho de utilizar un puntero auxiliar es para
no alterar el valor del puntero L ya que si se altera se puede perder la direccin de toda la lista
enlazada.
Operacin de Insercin
Consiste en insertar un nodo a cualquier parte de la lista, esto se realiza mediante asignacin
dinmica de memoria es decir que se reserva memoria para un nuevo nodo y luego se almacena
en l el dato para enlazarlo a la lista en el lugar deseado ya sea al principio de la lista, al final o
entre medio de la lista. En cualquiera de los casos se deben actualizar los punteros de los nodos
adyacentes para mantener la lista enlazada.
El proceso se realiza en cuatro pasos, dada una lista como la que muestra a continuacin:
L
3) Se copia el campo link del nodo apuntado por P, al campo link del nuevo nodo N:
N
P
4
9
39
SASCI
4) Por ltimo, se copia en el campo link del nodo apuntado por P, el puntero N del nuevo nodo:
N
P
4
L
Operacin de Borrado
Consiste en eliminar un nodo de lista enlazada, en este caso se debe actualizar las direcciones de
los punteros necesarios y liberar la memoria ocupada por el nodo al sistema operativo para que
pueda ser utilizado en otras operaciones.
Operacin de Bsqueda
Consiste en buscar un elemento cualquiera en la lista enlazada, este hecho se realiza recorriendo
la lista y comparando el dato de cada uno de los nodos visitados con el elemento que se est
buscando hasta que se lo encuentre. Es similar a la operacin de recorrido.
40
SASCI
5. Arboles y Grafos
5.1 Arboles binarios
Un rbol es una estructura no lineal constituida por un conjunto de elementos arreglados en forma
jerrquica, en la que cada elemento tiene un antecesor (padre) y puede tener de cero a dos
sucesores (hijos). Los elementos se denominan nodos.
Existe un nico nodo especial llamado raz que no tiene antecesor.
Si el nmero mximo de sucesores es dos, se dice que el rbol es binario.
Antes de seguir entrando en materia, ser conveniente dar unas cuantas definiciones:
El primer nodo del rbol recibe el nombre de raz, los enlaces reciben el nombre de aristas.
Se dice que un nodo B es hijo de un nodo A, si existe alguna arista que va desde A hasta B.
Por ejemplo, en la figura, 7 es hijo de 2, 4 es hijo de 9, 11 es hijo de 6, etc.
Al mismo tiempo se dice que un nodo A es padre de un nodo B si existe una arista que va
desde A hasta B. Ej. 9 es padre de 4, 6 es padre de 5 y de 11, etc.
Se dice que un nodo es hoja, si no tiene hijos. Ej. 11 y 4 son hojas, pero 6, 7, y 9 no lo son.
La rama izquierda de un nodo es el rbol que tiene como raz el hijo izquierdo de tal nodo,
por ejemplo {7, 2, 6, 5, 11} son los nodos de la rama izquierda de 2.
La rama derecha de un nodo es el rbol que tiene como raz el hijo derecho de tal nodo.
Los nodos tambien pueden ser llamados vertices.
Nivel: nmero de ramas que hay que recorrer para llegar de la raz a un nodo. Ejemplo: el
nivel del nodo 2 es 1 (es un convenio), el nivel del nodo 9 es 3.
Altura: el nivel ms alto del rbol. En el ejemplo de la figura la altura es 4.
Amplitud: es el mayor valor del nmero de nodos que hay en un nivel. En la figura, la
amplitud es 3.
Grado de un nodo: el nmero de descendientes directos que tiene. Ejemplo: 5 tiene grado 2,
2 tiene grado 0, 6 tiene grado 2.
Grado de un rbol. es el mximo grado de entre todos los nodos.
41
SASCI
Definicin de rbol
Un rbol es una estructura de datos, que puede definirse de forma recursiva como:
-
Figura 1
Mediante un diagrama encolumnado:
a
b
d
c
e
f
En computacin se utiliza mucho una estructura de datos llamada rbol binario. Estos rboles
tienen 0, 1 2 descendientes como mximo. El rbol de la figura anterior es un ejemplo vlido de
rbol binario.
42
SASCI
* Recorrido en inorden u orden central: se visita el subrbol izquierdo, el nodo actual, y despus
se visita el subrbol derecho. En el ejemplo de la figura 1 las visitas seran en este orden:
b,d,a,e,c,f.
void inorden(Tarbol *a)
{
if (a != NULL) {
inorden(a->izq);
visitar(a);
inorden(a->der);
}
}
43
SASCI
La ventaja del recorrido en postorden es que permite borrar el rbol de forma consistente. Es
decir, si visitar se traduce por borrar el nodo actual, al ejecutar este recorrido se borrar el rbol o
subrbol que se pasa como parmetro. La razn para hacer esto es que no se debe borrar un nodo
y despus sus subrboles, porque al borrarlo se pueden perder los enlaces, y aunque no se
perdieran se rompe con la regla de manipular una estructura de datos inexistente. Una alternativa
es utilizar una variable auxiliar, pero es innecesario aplicando este recorrido.
Recorrido en amplitud:
Consiste en ir visitando el rbol por niveles. Primero se visitan los nodos de nivel 1 (como mucho
hay uno, la raz), despus los nodos de nivel 2, as hasta que ya no queden ms.
Si se hace el recorrido en amplitud del rbol de la figura una visitara los nodos en este orden:
a,b,c,d,e,f
En este caso el recorrido no se realizar de forma recursiva sino iterativa, utilizando una cola (ver
Colas) como estructura de datos auxiliar. El procedimiento consiste en encolar (si no estn
vacos) los subrboles izquierdo y derecho del nodo extraido de la cola, y seguir desencolando y
encolando hasta que la cola est vaca.
En la codificacin que viene a continuacin no se implementan las operaciones sobre colas.
void amplitud(Tarbol *a)
{
tCola cola;
/* las claves de la cola sern de tipo rbol binario */
arbol *aux;
if (a != NULL) {
CrearCola(cola);
encolar(cola, a);
while (!colavacia(cola)) {
desencolar(cola, aux);
visitar(aux);
if (aux->izq != NULL) encolar(cola, aux->izq);
if (aux->der != NULL) encolar(cola, aux->der);
}
}
}
Por ltimo, considrese la sustitucin de la cola por una pila en el recorrido en amplitud. Qu
tipo de recorrido se obtiene?
44
SASCI
El subrbol b tiene un subrbol derecho, que no tiene ningn descendiente, tal y como indican los
ndices izq y der. Se ha obtenido el subrbol izquierdo completo de la raz a, puesto que b no
tiene subrbol izquierdo:
45
SASCI
Ejercicio
Realizar la implementacin de la construccin de un rbol partiendo de los recorridos en
preorden y en inorden en C++.
46
SASCI
Figura 5
Al definir el tipo de datos que representa la clave de un nodo dentro de un rbol binario de
bsqueda es necesario que en dicho tipo se pueda establecer una relacin de orden. Por ejemplo,
suponer que el tipo de datos de la clave es un puntero (da igual a lo que apunte). Si se codifica el
rbol en Pascal no se puede establecer una relacin de orden para las claves, puesto que Pascal no
admite determinar si un puntero es mayor o menor que otro.
En el ejemplo de la figura 5 las claves son nmeros enteros. Dada la raz 4, las claves del
subrbol izquierdo son menores que 4, y las claves del subrbol derecho son mayores que 4. Esto
se cumple tambin para todos los subrboles. Si se hace el recorrido de este rbol en orden
central (inorden) se obtiene una lista de los nmeros ordenada de menor a mayor.
Cuestin: Qu hay que hacer para obtener una lista de los nmeros ordenada de mayor a menor?
Una ventaja fundamental de los rboles de bsqueda es que son en general mucho ms rpidos
para localizar un elemento que una lista enlazada. Por tanto, son ms rpidos para insertar y
borrar elementos. Si el rbol est perfectamente equilibrado -esto es, la diferencia entre el
nmero de nodos del subrbol izquierdo y el nmero de nodos del subrbol derecho es a lo sumo
1, para todos los nodos- entonces el nmero de comparaciones necesarias para localizar una clave
es aproximadamente de logN en el peor caso. Adems, el algoritmo de insercin en un rbol
47
SASCI
binario de bsqueda tiene la ventaja -sobre los arrays ordenados, donde se empleara bsqueda
dicotmica para localizar un elemento- de que no necesita hacer una reubicacin de los elementos
de la estructura para que esta siga ordenada despus de la insercin. Dicho algoritmo funciona
avanzando por el rbol escogiendo la rama izquierda o derecha en funcin de la clave que se
inserta y la clave del nodo actual, hasta encontrar su ubicacin; por ejemplo, insertar la clave 7 en
el rbol de la figura 5 requiere avanzar por el rbol hasta llegar a la clave 8, e introducir la nueva
clave en el subrbol izquierdo a 8.
El algoritmo de borrado en rboles es algo ms complejo, pero ms eficiente que el de borrado en
un array ordenado.
Ahora bien, suponer que se tiene un rbol vaco, que admite claves de tipo entero. Suponer que se
van a ir introduciendo las claves de forma ascendente. Ejemplo: 1, 2, 3, 4, 5, 6.
Se crea un rbol cuya raz tiene la clave 1. Se inserta la clave 2 en el subrbol derecho de 1. A
continuacin se inserta la clave 3 en el subrbol derecho de 2.
Continuando las inserciones se ve que el rbol degenera en una lista secuencial, reduciendo
drsticamente su eficacia para localizar un elemento. De todas formas es poco probable que se de
un caso de este tipo en la prctica. Si las claves a introducir llegan de forma ms o menos
aleatoria entonces la implementacin de operaciones sobre un rbol binario de bsqueda que
vienen a continuacin son, en general, suficientes.
Existen variaciones sobre estos rboles, como los AVL o Red-Black (no se tratan aqu), que sin
llegar a cumplir al 100% el criterio de rbol perfectamente equilibrado, evitan problemas como el
de obtener una lista degenerada.
Operaciones bsicas sobre rboles binarios de bsqueda
- Bsqueda
Si el rbol no es de bsqueda, es necesario emplear uno de los recorridos anteriores sobre el rbol
para localizarlo. El resultado es idntico al de una bsqueda secuencial. Aprovechando las
propiedades del rbol de bsqueda se puede acelerar la localizacin. Simplemente hay que
descender a lo largo del rbol a izquierda o derecha dependiendo del elemento que se busca.
boolean buscar(tarbol *a, int elem)
{
if (a == NULL) return FALSE;
else if (a->clave < elem) return buscar(a->der, elem);
else if (a->clave > elem) return buscar(a->izq, elem);
else return TRUE;
}
- Insercin
La insercin tampoco es complicada. Es ms, resulta prcticamente idntica a la bsqueda.
Cuando se llega a un rbol vaco se crea el nodo en el puntero que se pasa como parmetro por
referencia, de esta manera los nuevos enlaces mantienen la coherencia. Si el elemento a insertar
ya existe entonces no se hace nada.
48
SASCI
- Borrado
La operacin de borrado si resulta ser algo ms complicada. Se recuerda que el rbol debe seguir
siendo de bsqueda tras el borrado. Pueden darse tres casos, una vez encontrado el nodo a borrar:
1) El nodo no tiene descendientes. Simplemente se borra.
2) El nodo tiene al menos un descendiente por una sola rama. Se borra dicho nodo, y su primer
descendiente se asigna como hijo del padre del nodo borrado. Ejemplo: en el rbol de la figura 5
se borra el nodo cuya clave es -1. El rbol resultante es:
3) El nodo tiene al menos un descendiente por cada rama. Al borrar dicho nodo es necesario
mantener la coherencia de los enlaces, adems de seguir manteniendo la estructura como un rbol
binario de bsqueda. La solucin consiste en sustituir la informacin del nodo que se borra por el
de una de las hojas, y borrar a continuacin dicha hoja. Puede ser cualquier hoja? No, debe ser la
que contenga una de estas dos claves:
la mayor de las claves menores al nodo que se borra. Suponer que se quiere borrar el nodo 4
del rbol de la figura 5. Se sustituir la clave 4 por la clave 2.
la menor de las claves mayores al nodo que se borra. Suponer que se quiere borrar el nodo 4
del rbol de la figura 5. Se sustituir la clave 4 por la clave 5.
49
SASCI
Codificacin: el procedimiento sustituir es el que desciende por el rbol cuando se da el caso del
nodo con descencientes por ambas ramas.
void borrar(tarbol **a, int elem)
{
void sustituir(tarbol **a, tarbol **aux);
tarbol *aux;
if (*a == NULL) /* no existe la clave */
return;
if ((*a)->clave < elem) borrar(&(*a)->der, elem);
else if ((*a)->clave > elem) borrar(&(*a)->izq, elem);
else if ((*a)->clave == elem) {
aux = *a;
if ((*a)->izq == NULL) *a = (*a)->der;
else if ((*a)->der == NULL) *a = (*a)->izq;
else sustituir(&(*a)->izq, &aux); /* se sustituye por
la mayor de las menores */
free(aux);
}
}
50
SASCI
Ficheros relacionados
Implementacin de algunas de las operaciones sobre rboles binarios.
Ejercicio resuelto
Escribir una funcin que devuelva el numero de nodos de un rbol binario. Una solucin
recursiva puede ser la siguiente:
funcion nodos(arbol : tipoArbol) : devuelve entero;
inicio
si arbol = vacio entonces devolver 0;
en otro caso devolver (1 + nodos(subarbol_izq) + nodos(subarbol_der));
fin
Adaptarlo para que detecte si un rbol es perfectamente equilibrado o no.
51
SASCI
La solucin pasa por emplear un rbol binario de bsqueda para insertar las claves. El valor de
log(20.000) es aproximadamente de 14. Eso quiere decir que localizar una palabra entre 20.000
llevara en el peor caso unos 14 accesos. El contraste con el empleo de una lista es simplemente
abismal. Por supuesto, como se ha comentado anteriormente el rbol no va a estar perfectamente
equilibrado, pero nadie escribe novelas manteniendo el orden lexicogrfico (como un
diccionario) entre las palabras, asi que no se obtendr nunca un rbol muy degenerado. Lo que
est claro es que cualquier evolucin del rbol siempre ser mejor que el empleo de una lista.
Por ltimo, una vez realizada la lectura de los datos, slo queda hacer un recorrido en orden
central del rbol y se obtendr la solucin pedida en cuestin de segundos.
Una posible definicin de la estructura rbol es la siguiente:
typedef struct tarbol
{
char clave[MAXPALABRA];
int contador; /* numero de apariciones. Iniciar a 0 */
struct tarbol *izq,
*der;
} tarbol;
Ejercicios propuestos
1.
2.
Del rbol reconstruido anteriormente graficar como queda el rbol despus de eliminar el
240, el 210, y el 60
In- Orden (30, 60, 210, 240, 250, 255, 280, 285)
Pre- Orden (60, 30, 210, 280, 250, 240, 255, 285)
Reconstruir el rbol binario.
3.
Realizar un mtodo para eliminar todos los nodos hojas existentes en un rbol binario.
4.
Realizar un mtodo para eliminar todos los nodos incompletos existentes en un rbol
binario.
5.
6.
52
SASCI
7.
8.
Realizar un mtodo para el ADT rbol que permita obtener el elemento mayor de los
menores de un elemento dado es decir el menor ms prximo a un elemento x.
9.
Realizar un mtodo para eliminar un elemento cualquiera del rbol utilizando en vez del
nodo sucesor in-orden el menor ms prximo.
10. Implementar un mtodo para eliminar todos los elementos menores a un elemento x
53
SASCI
5.3. rboles B
La administracin de un gran conjunto de datos y su almacenamiento en ficheros es una tarea
vital para los sistemas informticos. El ordenador debe recuperar un elemento del fichero y
cargarlo en memoria principal, antes de ser procesado. Una organizacin inteligente de los
datos en el fichero puede hacer que el sistema informtico minimize el nmero de accesos al
dispositivo secundario. De tal manera de optimizar su funcionamiento.
Como una propuesta inicial para la ordenacin lgica de datos se presenta la estructura de datos
Arbol Binario de Bsqueda (ABB). El cual mediante el uso de punteros permite establecer un
orden de relacin entre los datos sin importar su orden fsico.
Recordemos que en un ABB cada nodo contiene un dato, as como punteros a los subarboles
izquierdo y derecho. El primer nodo se denomina raz del rbol y aquellos nodos que estn al
final de las ramas se llaman hojas.
Para buscar un dato en el ABB se deba recorrer el rbol desde su raz y comparar el dato buscado
con el dato existente en el nodo. Si era menor al dato en el nodo se buscaba en el subarbol
izquierdo y si era mayor en el subarbol derecho. As recursivamente, hasta encontrarlo o
encontrarse con una rama vaca.
Estos rboles binarios tan simples, aunque fciles de entender y de implementar, tienen algunas
desventajas en la prctica. Si los datos no estn bien distribuidos o son aadidos de forma no
aleatoria, el rbol puede resultar bastante asimtrico, dando lugar a un aumento bastante amplio
en el tiempo total de recorrido.
Como solucin ha este problema se present la estructura de datos Arbol Binario Balanceado
(AVL), el cual tena las mismas propiedades que un ABB pero adems deba satisfacer que las
alturas de los subarboles izquierdo y derecho no difirieran en ms de uno. Esto se logra utilizando
herramientas de balanceo que se denominan rotaciones.
Ahora retomando nuestra idea inicial de tener una gran cantidad de datos almacenada en algn
dispositivo secundario (HDD, Diskette, CD, etc.). Los ABB y los AVL deben realizar un acceso
al disco cada vez que cargan en memoria un dato del fichero. Lo cual es bastante costoso si
consideramos que el tiempo de bsqueda en una cantidad N de datos es del orden de log2N ms el
tiempo de cada acceso al disco (Un acceso al diskette, por ejemplo, demora alrededor de 1 seg.)
Para optimizar esta situacin usaremos la estructura de datos Arbol B y sus mtodos de
mantenimiento. El Mtodo de Trabajo de los Arboles B sobre los datos en memoria secundaria es
abordado en el apartado Funcionamiento de un Arbol B.
Utilizacin de los Arboles B
Los Arboles B se usan en una inmensa gama de sistemas informticos. Y constituyen una herramienta muy eficiente
para administrar grandes volumenes de datos. Es por sto, que los Arboles B constituyen el ncleo de los motores de
Bsqueda de las Bases de Datos.
54
SASCI
Veamos un ejemplo real. Si como Ingenieros en Computacin se nos encarga administrar la Base
de Datos de todos los sufragantes de Chile (los cuales son cientos de miles), entonces deberamos
usar una Estructura de Datos adecuada a nuestra problemtica. Sabiendo que se nos pide Buscar
personas, Verificar domicilios, Inscribir un sufragante, Eliminar a un sufragante, etc. La manera
ms idnea de hacerlo es usar una estructura dinmica y capaz de almacenar grandes cantidades
de datos. Es por eso que elegimos los Arboles B, porque nos entregan una eficaz administracin
de los datos de muchas personas.
Otro ejemplo real y concreto, es el uso en los Sistemas Operativos con Administracin de
Memoria del Tipo Virtual.
Los algoritmos de administracin de memoria virtual y otros, deben intercambiar en memoria
ciertos procesos (programas en ejecucin) que se eligieron por algn motivo especfico. Sucede
que a veces, algunos procesos residen mucho tiempo en memoria principal. Y simultaneamente
existen otros proceoso en va de ser cargados a memoria principal. Si sto pasa, y adems el
proceso en vas de ser cargado no tiene el espacio suficiente para ser cargado por completo en
memoria principal. Entonces nuestro algoritmo de administracin de memoria decidir cargar en
memoria secundaria (generalmente HDD) el estado del proceso menos importante o sin uso. Es
decir, guardar todos los valores de variables, registros y otra informacin importante del proceso
en un dispositivo secundario. Y dnde aparecen los Arboles B?. Aqu, puesto que esta estructura
de datos permite cargar y recobrar la gran cantidad de datos almacenada en el dispositivo
secundario, debido al intercambio de procesos en la memoria de nuestro PC.
Los Arboles B son muy funcionales en todos estos tipos de problemas en los cuales se requiere
una cantidad de accesos mnimos al dispositivo secundario, para poder procesar mucha
informacin.
Funcionamiento
El Arbol B es un TDA de bsqueda equilibrado, diseado para ser usado con grandes conjuntos
de datos en almacenamiento secundario.
Generalmente se considera a los Arboles B como el mejor mtodo para implementar al TDA
dinmico en una unidad de disco.
A diferencia de los Arboles Binarios (que slo podan almacenar un dato en cada nodo,
inducindo as a realizar un acceso al disco cada vez que se carga un dato en el rbol antes de ser
procesado), el Arbol B accede al disco mediante bloques de datos, es decir, agrupa los datos en
paquetes para su lectura o escritura de as serlo.
Esta propuesta reduce bastante el nmero de accesos al dispositivo secundario, optimizando as el
rendimiento de nuestro sistema informtico.
55
SASCI
As por ejemplo, supongamos que tenemos un archivo con nueve mil registros de empleados
(RUT, nombre, apellido, direccin, cargo) de 100 Bytes cada registro, como se muestra en la
Figura 1. Adems sabemos que el bloque del disco es de 512 Bytes y que cada puntero al bloque
de disco es de 2 Bytes.
56
SASCI
Qu es un Arbol B?
A fines de los aos sesenta, R. Bayer y E. McCreight postularon un criterio muy razonable de
organizar datos en un fichero externo, lo llamaron Arbol B.
Se dice que un Arbol es B de orden n si:
1. Cada pgina contiene a lo sumo 2n elementos (llaves).
2. Cada pgina, excepto la de la raz, contiene n elementos por lo menos.
3. Cada pgina es una pgina de hoja, o sea que no tiene, descendientes o tiene m+1
descendientes, donde m es el nmero de llaves en esta pgina.
4. Todas las pginas de hoja aparecen al mismo nivel.
La Figura 2 muestra un Arbol B de orden 2 con 3 niveles. Todas las pginas tienen 2, 3 o 4
elementos; la excepcin es la raz que puede contener un solo elemento nicamente. Todas las
pginas de hoja aparecen en el nivel 3.
Bsqueda
Examinemos una pgina como la de la Figura 3 y un argumento de bsqueda x.
SASCI
1. ki-1 < x < ki+1 para 1 <= i < m. Proseguimos la bsqueda en la pgina p i
2. km < x La bsqueda prosigue en la pgina pm
3. x < k1 La bsqueda prosigue en la pgina p0
Si en algn caso el apuntador desigando es NULL, esto es, si no hay pgina de hijo, entonces
tampoco existe un elemento con la llave x en el Arbol B y la bsqueda finaliza.
Insercin
Es intersante sealar que la insercin en un Arbol B de orden n es relativamente sencilla. Si hay
que insertar un elemento en una pgina con m<2n elementos, el proceso de insercin queda
limitado a esa pgina.
Para analizar esta situacin, considrese la Figura 4(a) que muestra un Arbol B de orden 2.
Puesto que cada pgina en un Arbol B de orden n (excepto la raz ) contiene entre n y 2n
elementos, cada pgina del ejemplo tiene entre 2 y 4 elementos. En cada pgina debe existir un
indicador (que no est reflejado en la figura) para informar sobre el nmero de elementos que
tiene la pgina. Primero se procede a Buscar desde la raz hasta localizar la pgina apropiada para
la insercin. Entonces se realiza la insercin. Refirindonos a la Figura 4(a), uno puede ver que
cuando se inserta el elemento 24, la Bsqueda termina sin xito en la segunda hoja. Puesto que la
hoja puede alojar otro elemento, se inserta el elemento nuevo simplemente, dando lugar al Arbol
que se muestra en la Figura 4(b).
Figura 4. (a) Un Arbol B de orden 2, y (b) el mismo rbol tras la insercin del elemento 24
La otra situacin que se presenta y la ms problemtica, es cuando se inserta un elemento en una
pgina ya llena. Esto puede afectar la Estructura del Arbol y ocasionar asignacin de pginas
nuevas.
Para comprender lo que sucede en este caso, analizemos la Figura 5 que ilustra la insercin de la
llave 22 en un Arbol B de orden 2. La accin se realiza en los siguientes pasos:
1.
2.
3.
Se descubre que falta la llave 22; la insercin en la pgina C es imposible porque C ya est llena.
La pgina C se divide en dos pginas (esto es, se asigna una nueva pgina D).
Las 2n + 1 llaves se distribuyen uniformemente en C y D, y la llave de la mitad se sube un nivel hacia la
pgina madre A.
58
SASCI
Borrado
Se distinguen dos casos:
1.
2.
En cualquier caso, despus de la eliminacin, debe seguir una comprobacin del nmero de
elementos restantes en la pgina, pues si m < n se tiene se estara violando las Propiedades para el
Arbol B de orden n y entonces, se requiere reorganizar el Arbol.
Para analizar el caso 1 (el ms sencillo), considrse el Arbol B de orden 2 que se muestra en la
Figura 6(a).
SASCI
donde fu eliminado dicho elemento cumple con las Propiedades de Arbol B de orden 2, entonces
se queda como est. En caso contrario, se debera realizar una combinacin de pginas. En
nuestro caso slo debemos eliminarlo y volver a ordenar los elmentos de la pgina. El Arbol que
se obtiene despus del borrado del elemento con valor 14 se muestra en la Figura 6(b).
Figura 6. (b) El mismo Arbol B de la Figura 6(a) tras el borrado del elemento 14
El caso 2 lo analizaremos atravs el ejemplo de la Figura 7(a), en el cual se muestra un Arbol B
de orden 2. El elemento que deseamos borrar es el 88, y se encuentra ubicado en una pgina que
no es hoja.
60
SASCI
61
SASCI
La Tabla 1 muestra cmo puede ser de razonable el costo logartmico, incluso para archivos de
gran tamao. Por ejemplo, en un Arbol B de orden 50 que contenga las claves que indexan a un
fichero de un milln de registros, se puede realizar una operacin de Bsqueda, Insercin o
Borrado con 4 accesos como mucho.
Tamao de la
pgina (n)
10
50
100
150
103
104
106
107
3
2
2
2
4
3
2
2
5
3
3
3
6
4
3
3
7
4
4
4
Casos especiales
Bsqueda
Caso peor
Esta situacin se presenta cuando el elemento que se est buscando se encuentra al final de una
pgina hoja del Arbol B.
Caso mejor
El mejor caso es claramente evidente, y se presenta cuando el elemento buscado es el primer dato
de la raz del Arbol.
Insercin
Caso peor
Ocurre cuando se inserta un elemento una pgina hoja que ya est completa. Y adems su pgina
padre tambin est completa. Esto conlleva, irremediablemente, a que el Arbol aumente su altura.
Caso mejor
Esta situacin se presenta cuando se est insertando un elemento en la raz del Arbol, que an no
est completa.
Borrado
Caso peor
Esta situacin se presenta cuando el elemento que se desea borrar se encuentra al final de una
pgina hoja con 2n elementos.
62
SASCI
Caso mejor
El mejor caso es cuando el elemento borrado es el primer dato de la raz del Arbol. que adems
tiene un solo dato.
Conclusin
Despus de realizar un exhaustivo estudio de la Estructura de Datos Arbol B. Su utilizacin, las
variantes, su mantenimiento y mucho ms... Hemos podido concluir lo siguiente:
Que existe una inmensa gama de sistemas de informacin computacional, en los cuales se debe
administrar eficientemente grandes volmenes de datos en archivos externos. Por ejemplo, en el
caso de las Bases de Datos, se deben realizar las operaciones de Actualizacin, Bsqueda,
Borrado e Incorporacin de nuevos datos de la forma ms eficiente que se pueda. Este ejemplo de
las BDs a su vez comprende una serie de subtemas, como por ejemplo la Administracin de
Memoria, Los Diccionarios, etc. Todos ellos requieren la utilizacin de Tipos de Datos
Abstractos adecuados. Es decir, que permitan la manipulacin eficiente de un gran cantidad de
informacin. Bajo sta problemtica es que nacen o se fueron creados, los Arboles B. (Ver Cmo
nacieron el Arbol B)
Los Arboles B constituyen la Estructura de Datos ptima para administrar grandes cantidades de
datos en ficheros externos. Gracias a su Estructura, el tiempo de Buscar, Insertar y Borrar datos
es mnimo.
Otra ventaja de los Arboles B es que dichas operaciones de mantenimiento son de fcil
entendimiento lgico. Sin embargo, al momento de ser implementadas comienzan a surgir
bastantes detalles, a veces son engorrosos (Ver Simulacin)
Otra caracterstica a tomar en cuenta cuando se trabaja con los Arboles B es: la versatilidad que
stos tienen. (Vase Tipos de Arboles B)
Los Costos de Buscar, Insertar y Borrar son el punto fuerte de los Arboles B. La mayora de los
Arboles Binarios requieren en promedio unos logN accesos al dispositivo de almacenamiento de
datos, para realizar operaciones de Bsqueda, Insercin y Borrado. Donde N es el nmero de
datos. En cambio los Arboles B, solamente necesitan lognN accesos. (Vase Costos). Donde n
es la cantidad mxima de datos que caben en una pgina (Vase Introduccin). Esto reduce
significativamente el nmero de accesos, ya que si incrementamos n, entonces log nN decrece.
Tal vez, el nico defecto que tiene el Arbol B que nosotros estudiamos es que a veces sus pginas
estn solamente utilizadas al 50% de su capacidad. Lo que puede ser un desperdicio de memoria
considerable si se tiene una cantidad de datos demasiado grande.
En resumen, gracias a su estructura y comportamiento, los Arboles B costituyen el TDA ms
ptimo para administrar datos en forma dinmica a gran escala.
63
SASCI
TRABAJOS PRACTICOS
Trabajo prctico N 1
1. Identifique los Tipos Abstractos de Datos que hubiera utilizado o desarrollado en los semestres anteriores
2. Disear un T.A.D. para representar y manejar nmeros quebrados
3. Crear un T.A.D que represente un tipo de dato Conjunto y todas sus operaciones Unin, Interseccin, Diferencia
simtrica, etc.
4. Disear los T.A.D. necesarios para modelar el problema de una agenda en la cual cada registro de la agenda
puede tener n e-mails, identificar las siguientes operaciones
a) Adicin de registros de personas.
b) Eliminacin de registros
c) Bsqueda de registros
d) Listado de personas ordenadas por nombres.
e) Listado de personas ordenados por e-mail.
Trabajo prctico con recursividad N 4
1.- Realizar un algoritmo recursivo para verificar si un nmero tiene al menos un dgito cero.
2.- Realizar un algoritmo recursivo para contar cuantos dgitos tiene un nmero
3.- Realizar un algoritmo recursivo para fusionar dos nmeros enteros positivos en un tercer nmero.
4.- Realizar un algoritmo recursivo para inicializar una lista con N elementos 0 y 1 intercalados. Ejemplo si N = 5, la
lista debe contener [0,1,0,1,0,1]
5.- Realizar un algoritmo recursivo para eliminar un elemento x de una lista
6.- Realizar el algoritmo de ordenacin quick-sort para la lista enlazada simple.
7.- Realizar un algoritmo recursivo para obtener la suma de los elementos impares de una lista.
8.- Realizar un algoritmo recursivo para obtener la suma de los elementos de una sub-lista definida por las
posiciones (j,k) desde la posicin j hasta k.
9.- Realizar un algoritmo recursivo para invertir los elementos de una lista doblemente enlazada
10.- Realizar un algoritmo recursivo fusionar dos listas en una tercera lista ejemplo L1 =(2,3,5) L2 = (5,4,7,2,3) L3 =
L1+ L2 = (2,3,5,5,4,7,2,3)
Trabajo prctico N 2
1.
Realizar un programa que resuelva un ecuacin de segundo grado con una incgnita utilizando solo
punteros (No debe utilizar variables que no sean punteros)
64
SASCI
2.
Realizar un programa para resolver un sistema de ecuaciones de 3 incgnitas con tres variables utilizando
solo punteros.
3.
Realizar un programa para obtener el mayor elemento de N nmeros introducidos por el usuario utilizando
solo punteros.
4.
Realizar un programa para calcular cuntos dgitos impares tiene un numero entero positivo utilizando solo
punteros.
5.
Realizar un modulo en c++ que permita almacenar nmeros aleatorios a un StringGrid pasado como
parmetro en todo caso utilizar solo punteros.
6.
Realizar un algoritmo obtener los resultados de la serie de fibonaci en un ListBox pasado como parmetro.
7.
Realizar un programa que permita crear un edit en tiempo de ejecucin utilizando solo punteros.
8.
Realizar un programa que permita almacenar en un vector N nmeros enteros, Debe asignarse memoria
dinmicamente segn la cantidad exacta que el usuario necesita almacenar en el vector.
9.
Para las estructuras de datos Listas estticas realizar un procedimiento para buscar el nmero ms repetido
del vector (Utilizar solo punteros) y el acceso a los elementos del vector no realizar de la forma V[i], buscar otra
alternativa considerando que V es un puntero.
10.
Realizar un procedimiento para invertir una cadena utilizando punteros a char.
Trabajo prctico N 3
1.
Escribir un procedimiento que aada un nuevo elemento en la lista enlazada a partir del elemento i-simo.
2.
Escribir un procedimiento que elimine un elemento de la lista enlazada, indicado por un parmetro
(Posicin).
3.
Dada un lista enlazada de nmeros enteros, escribir las rutinas necesarias,
para que la liste este ordenada en orden creciente la ordenacin se debe hacer de al menos 3 mtodos de
ordenacin.
4. Se quiere representar un tipo abstracto de datos conjunto de tal forma que los elementos estn almacenados en
la lista enlazada, escribir una unidad para implementar el TAD conjunto mediante listas enlazadas.
5. Realizar un mtodo para la clase Tconjunto que permita realizar la UNIN INTERSECCIN Y DIFERENCIA DE
CONJUNTOS sobre la estructura de datos.
6. Implementar un mtodo para obtener el conjunto potencia de un conjunto.
7. Implementar un mtodo para realizar la diferencia simtrica de dos conjuntos.
8. Implementar el mtodo para encontrar el complemento de un conjunto.
9. Realizar una estructura para representar un juego de bingo sobre listas enlazadas.
10. Realizar un mtodo que permite generar y almacenar N cartones para un bingo.
65
SASCI
Expresin postfija
_____________________________
c) 6-5/(6 10*5/6) ^ 3.
Expresin postfija
_____________________________
d) ((10 (10*5/6) ^ 3)^2)*2 + 5.
Expresin postfija
_____________________________
e) (15/2*(8 + 10- 5 / 2) ^ 2)^3.
Expresin postfija
_____________________________
2.- Definir el ADT para implementar una aplicacin que permita evaluar expresiones aritmticas introducidas por el
usuario en formato cadena.
3.- Definir un ADT para implementar una aplicacin que permita graficar cualquier funcin en el plano de
coordenadas X,Y la funcin debe ser introducida por el usuario.
4.- Implementar el mtodo para evaluar la expresin en formato cadena de la notacin infija a la notacin postfija
utilizando listas.
5.- Implementar el mtodo para evaluar la expresin en formato postfija de de la lista en funcin a una valor par a la
variable X de la funcin f(x)
66
SASCI
BIBLIOGRAFA
Sisa Alberto Jaime (2002). Estructuras de Datos y Algoritmos, Pearson Educacin de
Colombia LTDA.
Jorge A. Villalobos S. (1996). Diseo y Manejo de Estructuras de Datos en C. MacGraw Hill.
Jorge A. Villalobos S, Alejandro Quintero, Estructuras de Datos- Un enfoque de Tipos
Abstractos de Datos. MacGraw Hill
Galve, Gonzales, Sanches, (1998). Velsquez, Algoritmia, MacGraw Hill.
Horowitz, Ellis y Sahni Sartaj (1981) Data Structure Mc Graw Hill
Joyanes, Aguilar, Luis: Estructura de datos, Ed. McGraw-Hill Interamericana de Espaa, 1998.
(Signatura topogrfica: 005.73 J84)
Joyanes, Aguilar, Luis, C++ a su alcance, Ed. McGraw-Hill Interamericana de Espaa, 1994.
(Signatura topogrfica: 005.1 J84)
Ceballos, Javier, Curso de programacin C++, 1991. (Signatura topogrfica: 005.1 C32)
Deitel, H.M. C++ como programar, 1999. (Signatura topogrfica: 005.1 D36 c.2)
67