Professional Documents
Culture Documents
1-
funciones
asociadas
cada
estructura
son
relativamente
Modelo Matemtico
Algoritmo Informal
ADT
Estruct. de Datos
Prog. Pseudocdigo
Programa
Paso 2. ADT:
Tipo de dato abstracto MATRIZ y sus valores sern
Sea M1, M2, M3 de tipo matriz y R de tipo real
Las operaciones son: multiplicar (M1, M2, M3)
Sumar (M1, M2, M3)
Determinante M1
Leer Matriz M1
Paso 2.1 Pseudo cdigo o Algoritmo:
Inicio
Leer matriz (A)
Leer matriz (B)
Leer matriz (C)
Multiplicar (B,C y M1)
Sumar (A, M1, M2)
Poner en R el determinante (M2)
Imprimir R
Fin
Paso 3. Estructura de Datos:
Arreglo de 2 dimensiones.
Paso 3.1 Implementacin de programa
Unit matriz
Interfase
Const n = 20; {orden de la matriz}
0 = 5e-13;
Type
Matriz = array [1..n,1n] of Real;
Procedure multiplicar (M1, M2: matriz; VAR M3: matriz);
Procedure sumar (M1, M2: matriz; VAR M3: matriz);
Function determinante (M1: matriz) of Real;
Procedure leer matriz (VAR M1:matriz);
Implementation:
Var
I, j, k: Integer;
procedure multiplicar;
begin
for j: =1 to n do
M3 [I, j]:=0;
for k: =1 to n do begin
M3 [I, j]:=M3 [I, j] +M1 [I, j]*M2 [k, j]
end
end; {multiplicar}
procedure sumar;
begin
for i: =1 to n do
for j: =1 to n do
M3 [I, j]:=M1 [I, j] +M2 [I, j]
end; {sumar}
procedure leer matriz;
begin
end; {leer matriz}
end
PROGRAM Ejemplo;
USES
Matriz;
VAR
A,B,C,M1;M2,matriz
R: Real;
Begin
Leer matriz(A);
Leer matriz(B);
Leer matriz(C);
Multiplicar(B,C,M1);
Sumar(A,M1,M2);
4
R:=determinante(M2);
writeln(El resultado es: ;R)
End
Ejercicio: Aplicar los pasos para la solucin de un problema utilizando la PC
que permita resolver una ecuacin de segundo grado.
ejecucin T (n) = cn
= l, tomando j = n si el
2-
RECURSIVIDAD
1 es nmero natural.
el siguiente nmero de un nmero natural es un nmero natural
-3 Fib(1) = 1 ; Fib(0) = 0
(2) Fib(n) = Fib(n-1) + Fib(n-2) si n >= 2
Cuantas llamadas recursivas se producen para Fib(6)?.
Codificar un programa que calcule Fib(n) de forma iterativa.
Nota: no utilizar estructuras de datos, puesto que no queremos almacenar los
nmeros de Fibonacci anteriores a n; s se permiten variables auxiliares.
10
11
int numeros[5] = {2,0,-1,1,3};
int N = 5;
printf(%d\n,sumarray(numeros, 0, N));
Notar que la condicin de parada se cumple cuando se llega al final del array.
Otra alternativa es recorrer el array desde el final hasta el principio (de derecha
a izquierda):
int sumarray(int numeros[], int posicion)
{
if (posicin == 0)
return numeros[posicin];
else
return numeros[posicin] + sumarray(numeros, 12osicin-1);
}
12
int numeros[5] = {2,4,1,-3,-1};
printf(%d\n,sumarray(numeros, 0));
La razn por la que se incluye este ejemplo se debe a que en general no se
conocer el nmero de elementos de la estructura de datos sobre la que se
trabaja. En ese caso se introduce un centinela como la constante 1 de este
ejemplo o la constante NULO para punteros, u otros valores como el mayor o
menor entero que la mquina pueda representar para indicar el fin de la
estructura.
- Dado un array constituido de nmeros enteros y que contiene N elementos
siendo N >= 1, devolver el elemento mayor.
Int mayor(int numeros[], int posicion)
{
int aux;
if (Posicin == 0)
return numeros[Posicin];
else {
aux = mayor(numeros, Posicin-1);
if (numeros[Posicin] > aux)
return numeros[Posicin];
else
return aux;
}
}
13
2.
16
3-
El TAD LISTA
esto
tambin
puede
hacerse
con
vectores,
pero
en
las
implementaciones mas comunes estas operaciones son O(n) para los vectores,
mientras que son O(1) para las listas. El poder de las listas es tal que la familia
de lenguajes derivados del Lisp, que hoy en da cuenta con el Lisp, Common
Lisp y Scheme, entre otros, el lenguaje mismo est basado en la lista (Lisp
viene de list processing).
Descripcin matemtica de las listas Desde el punto de vista abstracto, una lista
es una secuencia de cero o ms elementos de un tipo determinado, que en
general llamaremos elem_t, por ejemplo int o double. A menudo representamos
una lista en forma impresa como una sucesin de elementos entre parntesis,
separados
por
comas
(a0
a1,
an1
que
en
el
caso
de
conjuntos, estos
seran
iguales.
Otra
diferencia con los conjuntos es que puede haber elementos repetidos en una
lista, mientras que en un conjunto no.
17
Decimos
que
el
elemento
ai
est
en
la
posicin
i.
Tambin
pensar
en
las
posiciones
como
entidades abstractas, no
19
LOCATE: X, L
Da la posicin de x en la lista , es decir localiza un determinado valor o
elemento en la lista si x aparece mas de una vez dar la posicin de la primera
ocurrencia de x en la lista si x no aparece el resultado coincide con fin L.
RETRIEVE: P, L
Da el elemento que se encuentra en la posicin P de la lista L. Si P= Fin L o no
existe la posicin P en la lista L el resultado s indefinido.
DELETE: P,L
Extrae el elemento que se encuentra n la posicin P de la lista L es decir si L es
la lista el resultado ser indefinido cuando P =fin L o no existe la posicin Pen
la lista L. Borra la informacin que se encuentra n la posicin P de la listaL.
NEXT P,L
Da la posicin que sucede ala posicin P en la lista L. Si P es la posicin del
ultimo elemento de la lista L entonces Next P,L retornara el valor Fin L mientras
que queda indefinida si P es Fin L o la lista L no tiene la posicin P es decir
regresa la posicion P+1.
PREVIUS L
Regresa la posicin anterior a la posicin P. Da la posicin que precede a la
posicin P en la lista L. Si P es la posicin del primer elemento de la lista L
entonces Previus P,L queda indefinido as como si la posicin P no existe en la
L.
MAKENULL L
Hace que L se convierta en una lista vaca para inicializar se utiliza una variable
de tipo Lista
FIRST L
Da la posicin del primer elemento de la lista L si L es una lista vaca devuelve
la posicin Fin L
20
SWAP P,Q,L
Intercambian los elementos que se encuentran en la posicin P y Q de la lista L
si alguna de estas posiciones no existe o es Fin L su accin quedara indefinida.
LENGTH L
Da la cantidad elementos que tiene la lista L
EMPTY L
Da TRUE si y solo si Les una lista vaca.
Algunas observaciones con respecto a estas funciones son
. Posiciones invlidas: Un elemento a tener en cuenta es que las funciones
que modifican la lista como insert and erase, convierten en invlidas
algunas de las posiciones de la lista, normalmente desde el punto de
insercin/supresin en adelante, incluyendo end(). Por ejemplo,
1 iterator_t p,q,r;
2 list L;
3 elem_t x,y,z;
4 //...
5 // p es una posicion dereferenciable
6 q = L.next(p);
7 r = L.end();
8 L.erase(p);
9 x = *p;
// incorrecto
10 y = *q;
// incorrecto
11 L.insert(r,z); // incorrecto
Ya que p,q,r ya no son validos (estn despus de la posicin borrada p. La
forma correcta de escribir el cdigo anterior es
1 iterator_t p,q,r;
2 list L;
3 elem_t x,y,z;
21
4 //...
5 // p es una posicion dereferenciable
6 p = L.erase(p);
7 x = *p;
// correcto
8 q = L.next(p);
9 y = *q;
// correcto
10 r = L.end();
11 L.insert(r,z); // correcto
. Las posiciones slo se acceden a travs de funciones de la clase: Las nicas
operaciones vlidas con posiciones son
Asignar:
p = L.begin();
q = L.end();
Avanzar:
q = L.next(p);
Acceder al elemento:
x
L.retrieve(p);
L.retrieve(q) = y;
Copiar:
q = p;
Comparar: Notar que slo se puede comparar por igualdad o desigualdad, no
por opera- dores de comparacin, como < o >.
q == p
r != L.end();
22
Desventaja.
Esta forma de almacenamiento tiene la desventaja de que al insertar o extraer
un nodo en una posicin intermedia e la lista es necesario hacer corrimiento
fsico de informacin ya sea para hacer espacio cuando se va a insertar un
nuevo elemento o compactar la lista si se extrajo un elemento.
Ventaja
Estas operaciones e hacen muy eficientes cuando e trata de la ultima posicin
o del ultimo nodo de la lista respectivamente.
IMPLEMENTACION MEDIANTE PUNTEROS.
En esta implementacin consideremos que cada nodo de la lista contiene un
campo adicional que es de tipo puntero el cual se utilizara para enlazar con el
prximo nodo obtenindose una lista simplemente enlazada. Esto nos evitara
tener que almacenar todos los nodos de la lista en localizaciones contiguas o
hacer corrimiento fsico cuando se va a extraer o insertar en posiciones
intermedios de la lista.
Esta implementacin mediante punteros tiene la desventaja que consume
memoria adicional de dichos punteros.
23
4-
p->anterior->siguiente = p->siguiente;
if (p->siguiente != NULL)
p->siguiente->anterior = p->anterior;
free(p);
}
Donde los trazos contnuos denotan la situacin inicial y los punteados la final.
El ejemplo visto se ajusta a la supresin de un elemento o celda de una lista
situada en medio de la misma. Para obviar los problemas derivados de los
elementos extremos (primero y ltimo) es prctica comn hacer que la
cabecera de la lista doblemente enlazada sea una celda que efectivamente
complete el crculo, es decir, el anterior a la celda de cabecera sea la ltima
celda de la lista y la siguiente la primera. De esta manera no necesitamos
chequear para NULL en el anterior procedimiento borrar.
Por consiguiente, podemos realizar una implementacin de listas doblemente
enlazadas con cabecera tal que tenga una estructura circular en el sentido de
que dado un nodo y por medio de los punteros siguientes podemos volver
hasta l como se puede observar en la figura (de forma anloga para anterior).
25
26
5-
GRAFOS
27
arcos o aristas.
28
Dados
1.
y
2.
grafos no dirigidos:
donde n=|V|
29
30
Un camino se dice simple cuando todos sus arcos son distintos y se dice
elemental cuando no utiliza un mismo vrtice dos veces. Por tanto todo camino
elemental es simple y el recproco no es cierto.
Un camino se dice Euleriano si es simple y adems contiene a todos los arcos
del grafo.
Un circuito(o ciclo para grafos no dirigidos) es un camino en el que coinciden
los vrtices inicial y final. Un circuito se dice simple cuando todos los arcos que
lo forman son distintos y se dice elemental cuando todos los vrtices por los
que pasa son distintos. La longitud de un circuito es el nmero de arcos que lo
componen. Un bucle es un circuito de longitud 1(estn permitidos los arcos de
la forma (i,i) y notemos que un grafo antisimtrico carecera de ellos).
Un circuito elemental que incluye a todos los vrtices de un grafo lo llamaremos
circuito Hamiltoniano.
Un grafo se denomina simple si no tiene bucles y no existe ms que un camino
para unir dos nodos.
Diremos que un grafo no dirigido es bipartido si el conjunto de sus vrtices
puede ser dividido en dos subconjuntos(disjuntos) de tal forma que cualquiera
de las aristas que componen el grafo tiene cada uno de sus extremos en un
subconjunto distinto. Un grafo no dirigido ser bipartido si y slo si no contiene
ciclos con un nmero de aristas par.
Dado un grafo G=(V,A),diremos que G'=(V,A') con
es un grafo parcial de
el conjunto de todas aquellas aristas que unan en el grafo G dos vrtices que
estn en V'. Se podran combinar ambas definiciones dando lugar a lo que
llamaremos subgrafo parcial
31
32
Dado un grafo G, diremos que dos vrtices estn conectados si entre ambos
existe un camino que los une.
Llamaremos componente conexa a un conjunto de vrtices de un grafo tal que
entre cada par de vrtices hay al menos un camino y si se aade algn otro
vrtice esta concicin deja de verificarse. Matemticamente se puede ver como
que la conexin es una relacin de equivalencia que descompone a V en
clases de equivalencia, cada uno de los subgrafos a los que da lugar cada una
de esas clases de equivalencia constituira una componente conexa. Un grafo
diremos que es conexo si slo existe una componente conexa que coincide con
todo el grafo.
33
6- MATRIZ DE ADYACENCIA.
Grafos dirigidos.
G=(V,A) un grafo dirigido con |V|=n .Se define la matriz de adyacencia o
booleana asociada a G como Bnxn con
Como se ve, se asocia cada fila y cada columna a un vrtice y los elementos b i,j
de la matriz son 1 si existe el arco (i,j) y 0 en caso contrario.
Grafos no dirigidos.
G=(V,A) un grafo no dirigido con |V|=n .Se define la matriz de adyacencia o
booleana asociada a G como Bnxn con:
34
EJEMPLO:
35
7-
LISTAS DE ADYACENCIA.
En esta estructura de datos la idea es asociar a cada vrtice i del grafo una
lista que contenga todos aquellos vrtices j que sean adyacentes a l. De esta
forma slo reservar memoria para los arcos adyacentes a i y no para todos los
posibles arcos que pudieran tener como origen i. El grafo, por tanto, se
representa por medio de un vector de n componentes (si |V|=n) donde cada
componente va a ser una lista de adyacencia correspondiente a cada uno de
los vrtices del grafo. Cada elemento de la lista consta de un campo indicando
el vrtice adyacente. En caso de que el grafo sea etiquetado, habr que aadir
un segundo campo para mostrar el valor de la etiqueta.
36
38
REPRESENTACION PROPUESTA.
La eleccin de una estructura idnea para representar el TDA grafo no es una
tarea fcil ya que existen dos representaciones totalmente contrapuestas: por
un lado tenemos la matriz de adyacencias que es muy eficiente para
comprobar si existe una arista uniendo dos vrtices pero que sin embargo
desperdicia una gran cantidad de espacio si el grafo no es completo o esta
lejos de serlo, adems no tiene la posibilidad de aadir nuevos vrtices; y por
otra parte est la lista de adyacencias que no tiene el problema de la anterior
respecto al espacio pero que sin embargo no es tan eficiente a la hora de ver si
existe una arista entre dos nodos determinados.
Teniendo en cuenta estas consideraciones se ha optado por realizar una
mezcla de ambas representaciones intentando aprovechar de alguna forma las
ventajas que ambas poseen. Por otra parte siguiendo con la idea de tratar tanto
los grafos dirigidos como los no dirigidos bajo una misma estructura, la
estructura elegida posee dos apariencias ligeramente diferentes para tratar de
forma adecuada cada uno de estos dos tipos de grafos.
La estructura consiste (en el caso de que tengamos un grafo dirigido en una
lista de vrtices donde cada uno de estos posee dos listas, una de aristas
incidentes a l y otra de adyacentes. Cada vez que se aade una arista al grafo
se inserta en la lista de aristas adyacentes del vrtice origen y en la de
incidentes del vrtice destino. De esta forma la estructura desplegada se
asemejara a una matriz de adyacencia en la cual hay una arista por cada 1 y el
ndice de la matriz es la posicin dentro de la lista de vrtices.
Grficamente la estructura para un grafo dirigido queda como se puede
apreciar en la siguiente figura. El puntero que de la estructura arco que apunta
al destino se ha sustituido por la etiqueta del nodo destino en el grafico para
simplificarlo y hacerlo mas claro.
39
Esta estructura no seria la mas idnea si trabajamos con solo con grafos no
dirigidos ya que por cada arista no dirigida tendramos que insertar en la
estructura una misma arista dirigida repetida dos veces (una con un vrtice
como origen y el otro como destino y al contrario). En muchos problemas si
asumimos el desperdicio de espacio podra, de todas formas, resultar
interesante representar un grafo no dirigido como un grafo dirigido simtrico, el
40
41
8-
ADT CONJUNTO
CONJLETRAS
[A, E, I, O, U]
CONJALUM
[JUANJAVIER]
CONJNUM
[1..10]
EXPRESION
A+B
A*B
RESULTADO
Es un conjunto (es la unin de los conjuntos A y B)
Es un conjunto (es la interseccin de los conjuntos
A-B
A y B)
Es un conjunto (es la diferencia entre los conjuntos
A=B
A y B)
Valor booleano (verdadero si el conjunto A es igual
AB
al conjunto B)
Valor booleano (verdadero si el conjunto A no es
A<=B
igual al conjunto B)
Valor booleano (verdadero si el conjunto A es un
A>=B
<=
>=
AB
43
[110]
[2,4,6,8,10]
[1,3,5,7,9]
RESULTADO
E=[1..10,20,30,40]
E=[1..10] = A
E=[1,3,5,7,9] = C
44
E
B*C
E
A-B
E
A-C
(20D)
(20A)
(4C)
(4B)
(8 (B*A))
(3 (A-B))
(3 (A-C))
(A>=B)
(A>=D)
((B*C)= [ ])
(A<=C)
(C<=A)
((B+C))A
REPRESENTACION EN MEMORIA
Un conjunto se representa en memoria por medio de su funcin caracterstica
la cual es un arreglo cuyo elemento i-esimo indica la presencia o ausencia del
elemento i en el conjunto (considerando el tipo base). El tamao del arreglo lo
determina el cardinal del tipo base del conjunto.
EJEMPLO:
Sea CONJ el conjunto formado por los nmeros entre 1 y 10 inclusive:
CONJ = CONJUNTO DE 1:10
Supngase ahora que se asigna a CONJ los valores del 1 al 5:
CONJ [15]
La representacin en memoria del conjunto CONJ ser una secuencia de bits
donde cada bits indicara la presencia o ausencia de un elemento en CONJ. En
este caso la representacin queda como se muestra en la siguiente figura:
45
46
9-
El TAD PILA
47
REPRESENTACION DE PILAS:
Las pilas no son estructuras fundamentales de datos, es decir, no estn
definidas como tales en los lenguajes de programacin (como lo estn por
ejemplo los arreglos). Las pilas pueden representarse mediante el uso de:
Arreglos
Listas Enlazadas.
48
Pila
Max
Tope
4
3
2
1
444
333
222
111
111
1
222
333
444
Max
tope
Representacin de pilas.
Al utilizar arreglos para implementar pilas se tiene las limitaciones de memoria
reservada, propia de los arreglos. Una vez dado un mximo de capacidad a la
pila, no es posible insertar un nmero de elementos mayor al mximo fijado. Si
la pila estuviera llena y se intentara insertar un nuevo valor, se tendra un error
conocido con el nombre de desbordamiento (overflow). Por ejemplo, si en la
pila presentada en la figura a), donde TOPE = MAX, que se quisiera insertar
otro elemento, se tendra un error de desbordamiento. La pila est llena y el
espacio reservado de memoria es fijo. No puede expandirse o contraerse.
a)
Tope
999
49
...
3
2
1
333
222
111
Una posible solucin a este tipo de errores consiste en definir pilas de gran
tamao, pero esto resultara ineficiente y costoso, si slo se utilizaran algunos
elementos. No siempre es posible saber con exactitud cul es el nmero de
elementos a tratar, por lo tanto siempre la posibilidad de cometer un error de
desbordamiento (si se reserva menos especio del que efectivamente se usar)
o bien de hacer uso ineficiente de la memoria (si se reserva ms espacio del
que se emplear).
Existe otra alternativa de solucin a este problema. Consiste en usar espacios
compartidos de memoria para la implementacin de pilas. Supngase que se
necesitan dos pilas, cada una de ellas con un tamao mximo de N elementos.
Se definir un solo arreglo de 2 * N elementos, en lugar de dos arreglos de N
elementos cada uno.
PILA 1
PILA 2
2 3
N N+1
Tope 1
2N-1 2N
Tope 2
50
Ejemplo.
A)
PILA 1
PILA 2
2 3
N N+1 N+2
2N-1
Tope 1
2N
tope 2
PILA 2
2 3
N-1 N N+2
Tope 1
tope 2
2N-1
2N
En la figura B), podra ocurrir lo mismo que en la A), la PILA 2 al querer ocupar
ms espacio y que la PILA 1 tuviera lugares disponibles.
51
Considerando que se tiene una pila que puede almacenar un mximo nmero
de elementos y que el ltimo de ellos est indicado por TOPE, los algoritmos
para poner y quitar elementos son los siguientes:
Algoritmo PONE
PONE (PILA, MAX, TOPE, DATO)
{Este algoritmo pone el elemento DATO en la pila. Actualiza el valor de TOPE,
MAX, es el mximo nmero de elementos que puede almacenar PILA}.
1. si TOPE MAX { Verifica que haya espacio libre}
Entonces
Hacer TOPE
PILA [TOPE]
DATO
52
Algoritmo QUITA
QUITA (PILA, TOPE, DATO)
{Este algoritmo saca el ltimo elemento de PILA y lo guarda en DATO, Actualiza
el valor de TOPE}
1. Si TOPE 0 {Verifica que la PILA no este vaca}
Entonces.
Hacer DATO
PILA [TOPE] y
TOPE
Si no
Escribir subdesbordamiento
2. {Fin del condicional del paso 1}
Ejemplos de Insercin y eliminacin.
Si se supieran los elementos lunes, martes, mircoles, jueves y viernes, en
este orden en PILA, la estructura quedara como lo indica la figura:
PILA
MAX
...
TOPE
5
4
3
2
1
Viernes
Jueves
Mircole
Martes
Lunes
53
como en el
siguiente ejemplo:
PILA
MAX
...
TOPE
4
3
2
1
Viernes
Jueves
Mircole
Martes
Lunes
PILA
MAX
PILA
PILA
MAX
MAX
TOPE 3
2
1
Mircoles
Martes
TOPE
Martes
Lunes
Lunes
54
TOPE 1
Lunes
PRACTICA DE PILAS:
1. Realizar el programa de pilas con las operaciones push, pop, insertar, ver.
PROGRAMA DE PILAS:
# include <conio.h>
# include <iostream.h>
# include <stdlib.h>
# include <sprinf.h>
Class pila
{
Int items [50];
Int top;
Public:
Void push (int x);
Void pop ( );
Void iniciar ( );
Void ver ( );
};
Void pila :: iniciar ( )
{
Top = 1;
}
Void pila :: push (int x)
{
++ top;
Items [top] = x;
Return;
}
55
}
return;
}
Void main ( )
{
Pila p;
Int sel, x;
p. iniciar ( )
clrscr ( );
do
{
Cout << Men principal;
Cout << endl;
Cout << 1. Agregar datos;
Cout << endl;
Cout << endl << 2. Remover datos;
Cout << endl << 3. ver datos de pila;
Cout << 4. salir;
56
Case 1:
Cout << Introduzca los datos:;
Cin >> x;
P. push (x);
Break;
Case 2:
p. pop ( );
getch ( );
break;
Case 3:
p. ver ( );
getch ( );
break;
Case 4:
-exit (0);
Default:
Cout << endl << error de seleccin;
Getch ( );
}
} while (sel = 4);
Getch ( );
}
3. Probar dicho programa con los siguientes juegos de datos:
1.
b) Insertar 23,56,78,34,67
2.
3.
b) eliminar de la pila
4.
5.
6.
APLICACIONES.
Las pilas son una estructura de datos muy usada en la solucin de diversos
tipos de problemas. Entre estos es usado en:
Llamadas a subprogramas.
Recursin
Tratamiento de Expresin Aritmtica
Ordenacin.
Llamadas a Subprogramas:
Recursin:
58
59
EJEMPLO:
Expresin infija: X + Z * W
PASO
0
1
2
EXPRESIN
X+Z*W
X+ZW*
XZW*+
TOPE + 1 y
PILA [TOPE]
smbolo
Sino
3.1.1.
2.1.1.1
Hacer EPOS
TOPE
PILA [TOPE] y
TOPE 1
1.1.2. {Fin del ciclo del paso 2.1.1.1}
60
TOPE 1
Sino
2.1.1.3. Si smbolo es un operando
Entonces
Agregar smbolo a EPOS
Sino {Es un operador}
2 1.1.3. A Repetir mientras TOPE 0 y la prioridad del operador sea menor o
igual que la prioridad del operador que est en la cima de PILA
Hacer EPOS
TOPE
TOPE + 1 y
smbolo
3.2.
4.
5.
6.
7.
Escribir EPOS.
61
TOPE-1
2.
3.
Si se lee un operando:
a)
4.
5.
Si se lee un operador:
a)
b)
6.
a)
62
EXAMINAR
)
0
%
)
K
*
N
M
(
/
Z
*
T
+
X
(
(
PILA
)
))
))
))%
))%)
))%)
))%)*
))%)*
))%)))%)))%
))%/
))%/
))%/*
))%/*
))+
))+
)
VACIO
EXPRESIN
O
O
O
OK
OK
OKN
OKN*
OKN*M
OKN*MOKN*MOKN*M-Z
OKN*M-Z
OKN*M-ZT
0KN*M-ZT*/%
OKN*M-ZT*/%X
OKN*M-ZT*/%X+
OKN*M-ZT*/%X+
63
2-
3-
4-
5-
6-
7-
b) Aadir 0 a pila.
8-
Fin de la condicional.
9-
10-
11-
12-
13-
14-
Salir.
64
Smbolo examinado
(
X
+
T
*
Z
/
(
M
N
*
K
)
%
O
Pila
(
((
((
((+
((+*
((+*
((+/
((+/(
((+/(
((+/(((+/(((+/
((+/
((+/
((+%
((+%
Expresin P
X
X
XT
XT
XTZ
XTZ*
XTZ*
XTZ*M
XTZ*M
XTZ*MN
XTZ*MN
XTZ*MNK
XTZ*MNK*XTZ*MNK*-/
XTZ*MNK*-/O
CLASE PRCTICA:
Sobre las aplicaciones de las pilas en la conversin de expresiones
resuelva.
((a+b/c)*(5*42)-7)
((8/3*4)-(52-4)*9)
B)
a)
((X2)+(4*X)-3)
b) ((273)+(8*X2)+3)
65
10-
El TAD COLA
Por contraposicin con la pila, la cola es un contenedor de tipo FIFO (por First
In First Out, el primero en entrar es el primero en salir). El ejemplo clsico es la
cola de la caja en el supermercado. La cola es un objeto muchas veces usado
como buffer o pulmn, es decir un contenedor donde almacenar una serie de
objetos que deben ser procesados, manteniendo el orden en el que ingresaron.
La cola es tambin, como la pila, un subtipo de la lista llama tambin a ser
implementado como un adaptador.
Intercalacin de vectores ordenados Ejemplo:
66
int n=a.size();
int x = a[j];
int k = j;
a[k+1 ] = x;
8
9
}
}
67
11-
RBOLES GENERALES
Hasta ahora las estructuras de datos que hemos estudiado eran de tipo lineal,
o sea, exista una relacin de anterior y siguiente entre los elementos que la
componan (cada elemento tendr uno anterior y otro posterior, salvo los casos
de primero y ltimo).Pues bien, aqu se va a estudiar una estructuracin de los
datos ms compleja: los rboles.
Este tipo de estructura es usual incluso fuera del campo de la informtica. El
lector seguramente conoce casos como los rboles gramaticales para analizar
oraciones, los rboles genealgicos, representacin de jerarquas, etc...La
estructuracin en rbol de los elementos es fundamental dentro del campo de
la informtica aplicndose en una amplia variedad de problemas como veremos
ms adelante.
En principio podemos considerar la estructura de rbol de manera intuitiva
como una estructura jerrquica. Por tanto, para estructurar un conjunto de
elementos ei en rbol, deberemos escoger uno de ellos e 1 al que llamaremos
raz del rbol. Del resto de los elementos se selecciona un subconjunto e 2,...,ek
estableciendo una relacin padre-hijo entre la raz y cada uno de dichos
elementos de manera que e1 es llamado el padre de e 2,de e3,...ek y cada uno de
ellos es llamado un hijo de e1. Interactivamente podemos realizar la misma
operacin para cada uno de estos elementos asignando a cada uno de ellos un
nmero de 0 o ms hijos hasta que no tengamos ms elementos que insertar.
El nico elemento que no tiene padre es e 1,la raz del rbol. Por otro lado hay
un conjunto de elementos que no tienen hijos aunque s padre que son
llamados hojas. Como hemos visto la relacin de paternidad es una relacin
uno a muchos.
Para tratar esta estructura cambiaremos la notacin:
Las listas tienen posiciones. Los rboles tienen nodos.
Las listas tienen un elemento en cada posicin. Los rboles tienen una etiqueta
en cada nodo (algunos autores distinguen entre rboles con y sin etiquetas. Un
rbol sin etiquetas tiene sentido aunque en la inmensa mayora de los
68
problemas necesitaremos etiquetar los nodos. Es por ello por lo que a partir de
ahora slo haremos referencia a rboles etiquetados).
Usando esta notacin, un rbol tiene uno y slo un nodo raz y uno o ms
nodos hoja.
Desde un punto de vista formal la estructura de datos rbol es un caso
particular de grafo, ms concretamente, en la teora de grafos se denota de
forma similar como rbol dirigido. A pesar de ello, la definicin formal ms usual
de rbol en ciencias de la computacin es la recursiva:
El caso bsico es un rbol con un nico nodo. Lgicamente este nodo es a la
vez raz y hoja del rbol.
Para construir un nuevo rbol a partir de un nodo n r y k rboles A1 ,A2,...,Ak de
races n1,n2,...,nk con N1,N2,...,Nk elementos cada uno establecemos una
relacin padre-hijo entre nr y cada una de las races de los k rboles. El rbol
resultante de N=1 + N1 + ... + Nk nodos tiene como raz el nodo n r, los nodos
n1,n2,...,nk son los hijos de nr y el conjunto de nodos hoja est formado por la
unin de los k conjuntos hojas iniciales. Adems a cada uno de los Ai se les
denota subrboles de la raz.
Ejemplo: Consideremos el ejemplo de la siguiente figura.
70
nos
referiremos
un
rbol
como
un
rbol
no-ordenado.
71
RECORRIDOS DE UN RBOL.
En una estructura lineal resulta trivial establecer un criterio de movimiento por
la misma para acceder a los elementos, pero en un rbol esa tarea no resulta
tan simple. No obstante, existen distintos mtodos tiles en que podemos
sistemticamente recorrer todos los nodos de un rbol. Los tres recorridos ms
importantes se denominan preorden, inorden y postorden aunque hay otros
recorridos como es el recorrido por niveles.
Si consideramos el esquema general de un rbol tal como muestra la figura
siguiente, los recorridos se definen como sigue:
72
1.
listado en post-orden.
Si el rbol tiene una estructura como muestra la figura 2,el
El listado por niveles es: desde i=0 hasta la altura h del rbol,
listar de izquierda a derecha los elementos de profundidad i. Como podemos
observar, un nodo n1 aparece antes que n2 en el listado por niveles si la
profundidad de n1 es menor que la profundidad de n2 usando el orden de los
nodos definido anteriormente para el caso en que tengan la misma
profundidad.
Listado preorden.
A=Ar=rAvAs=rvAuAwAs= rvuAwAs=rvuwAxAyAzAs=
73
vuwxAyAzAs=rvuwxyA zAs=rvuwxyzAs
=rvuwxyzsApAq=rvuwxyzspAq=rvuwxyzspq.
Listado postorden.
A=Ar=AvAsr=AuAwvAsr= uAwvAsr=uAxAyAzwvAsr=
uxAyAzwvAsr=uxyAzwvAsr=uxyzwvAsr=
uxyzwvApAqsr=uxyzwvpAqsr=uxyzwvpqsr.
Listado inorden.
A=Ar=AvrAs=AuvAwrAs= uvAwrAs=uvAxwAyAzrAs=uvxw
AyAzrAs=uvxwyAzrAs=uvxwyzrAs= uvxwyzrApsAq=uvxwyzrpsAq=uvxwyzrpsq.
Por ltimo, el listado por niveles de este rbol es el siguiente: r,v,s,u,w,p,q,x,y,z.
Finalmente es interesante conocer que un rbol no puede, en general,
recuperarse con uno solo de sus recorridos. Por ejemplo: Dada la lista en
inorden: v w y x z r t u p s q, los rboles de la figura 4 tienen ese mismo
recorrido en inorden.
74
12-
#include<stdio.h>
#include<stdlib.h>
#define NULL 0
/* ESTRUCTURA LISTA */
struct listnode {
char data;
struct listnode *nextPtr;
};
typedef struct listnode LISTNODE;
typedef LISTNODE *LISTNODEPTR;
/* ESTRUCTURA COLA */
struct cola_nodo {
char dato;
struct cola_nodo *nextPtr;
};
typedef struct cola_nodo COLANODO;
typedef COLANODO *COLANODOPTR;
/* ESTRUCTURA PILA.*/
struct pilaNodo {
int dato;
struct pilaNodo *nextPtr;
};
typedef struct pilaNodo PILANODO;
typedef PILANODO *PILANODOPTR;
/* FUNCIONES DE LISTA */
/* Funcion que Inserta los Caracteres. */
void insert (LISTNODEPTR *sPtr, char value)
{
LISTNODEPTR newPtr, previousPtr, currentPtr;
newPtr = malloc ( sizeof(LISTNODE));
if (newPtr != NULL) { /* is space available */
newPtr->data = value;
newPtr->nextPtr = NULL;
previousPtr = NULL;
currentPtr = *sPtr;
75
76
{
return sPtr == NULL;
}
/* Impreme el orden de la lista */
void printList (LISTNODEPTR currentPtr)
{
if (currentPtr == NULL)
printf(" LA LISTA ESTA VACIA.\n\n");
else {
printf(" LISTA :\n");
while (currentPtr != NULL) {
printf("%c -->", currentPtr->data);
currentPtr = currentPtr->nextPtr;
}
printf(" NULL\n\n");
}
}
77
78
return;
}
int pop(PILANODOPTR *topePtr)
{
PILANODOPTR tempPtr;
int popValor;
tempPtr = *topePtr;
popValor = (*topePtr)-> dato;
*topePtr = (*topePtr)->nextPtr;
free(tempPtr);
return popValor;
}
void imprimir_pila(PILANODOPTR currentPtr)
{
if(currentPtr == NULL)
printf("LA pila esta Vacia.\n\n");
else {
printf(" PILA: \n");
while (currentPtr != NULL) {
printf("%d --> ",currentPtr -> dato);
currentPtr = currentPtr -> nextPtr;
}
printf("NULL\n\n");
}
}
int isEmpty_pila(PILANODOPTR topePtr)
{
return topePtr == NULL;
}
void menu(void)
{
printf("
\n
***** MENU PRINCIPAL ***** \n\n"
"
**** ESTRUCTURA LISTA **** \n "
" 1 Insertar CARACTERES en la LISTA.\n"
" 2 Sacar CARACTERES de la Lista. \n\n"
"
**** ESTRUCTURA COLA ****\n"
" 3 Insertar CARACTERES en la COLA. \n"
" 4 Sacar CARACTERES de la Cola.\n\n "
"
**** ESTRUCTURA PILA **** \n"
" 5 Insertar NUMEROS en la PILA.\n"
" 6 Sacar Numeros de la Pila.\n"
" 7 FIN DEL PROGRAMA.\n");
return;
79
80
break;
case 3:
printf("Digite el caracter");
scanf("\n%c",&item);
insertar_cola(&headPtr , &tailPtr , item);
imprimir_cola(headPtr);
break;
case 4:
if (!isEmpty (headPtr)){
item = eliminar_cola(&headPtr , &tailPtr);
printf("%c NO ESTA EN LA COLA.\n",item);
}
imprimir_cola(headPtr);
break;
case 5:
printf("Digite el Numero: ");
scanf("%d",&valor);
push(&pilaPtr,valor);
imprimir_pila(pilaPtr);
break;
case 6:
if(!isEmpty(pilaPtr))
printf(" Numero eliminado: %d.\n",
pop(&pilaPtr));
imprimir_pila(pilaPtr);
break;
default:
printf(" Eleccion Invalida.\n\n");
menu();
break;
}
printf("? ");
scanf("%d",&choice);
}
printf("Fin \n");
getch();
}
81
if(n==1)
break;
else {
printf("\nDIGITE LOS HIJOS:");
for(i=1;i<n;++i) {
scanf("%d",&numero);
insertarnodo(&arbol,numero);
}
}
}
else {
printf("\nDIGITE LOS HIJOS:");
for(i=0;i<n;++i) {
scanf("%d",&numero);
insertarnodo(&arbol,numero);
}
}
getch();
break;
case 2:
if(arbol!=NULL) {
printf("\n\n\t\tARBOL LIBERADO.");
arbol=NULL;
}else {
printf("\n\n\t\tNO EXISTE ELEMENTS EN EL ARBOL.");
}
getch();
break;
case 3:
if(arbol!=NULL) {
printf("\n\n\t\tEL ARBOL EN POSTORDEN:");
posorden(arbol);
}else {
printf("\n\n\t\tNO EXISTEN ELEMENTOS EN EL ARBOL.");
}
getch();
break;
case 4:
if(arbol!=NULL) {
printf("\n\n\t\tEL ARBOL EN PREORDEN:");
preorden(arbol);
}else{
printf("\n\n\t\tNO EXISTEN ELEMENTOS EN EL ARBOL.");
}
83
getch();
break;
case 5:
if(arbol!=NULL) {
printf("\n\n\t\tEL ARBOL BINARIO.");
enorden(arbol);
}else{
printf("\n\n\t\tNO EXISTE ELEMENTOS EN EL ARBOL.");
}
getch();
break;
case 6:
break;
default:
printf("\n\n\t\tERROR -->ENTER PARA CONTINUAR.\n");
getch();
}//FIN DEL SWITCH
}//FIN DEL WHILE
salida();
return;
}
void entrada(void)
{
clrscr();
gotoxy(25,9);printf("\"BIENVENIDO AL PROGRAMA DE
ARBOLES\"");
gotoxy(25,10);printf("-----------------------------------");
gotoxy(25,15);printf("ENTER PARA ENTRAR AL PROGRAMA");
getch();
return;
}
int menu(void)
{
int seleccion;
clrscr();
printf("\n\t\tMENU PRINCIPAL\n\t\t");
printf("\n\t\t1-AADIR ELEMENTOS DEL ARBOL\n\t\t");
printf("\n\t\t2-LIBERAR ELEMENTOS DEL ARBOL\n\t\t");
printf("\n\t\t3-VER RECORRIDO EN POST_ORDEN\n\t\t");
printf("\n\t\t4-VER RECORRIDO EN PRE_ORDEN\n\t\t");
printf("\n\t\t5-VER RECORRIDO EN ORDEN\n\t\t");
printf("\n\t\t6-PARA SALIR DEL PROGRAMA\n\t\t");
printf("\n\t\tINTRODUZCA SU ELECCION->\n\t\t");
scanf("%d,&seleccion");
84
return(seleccion);
}
void insertarnodo(arbolbinario *arbol,int numero)
{
if(*arbol==NULL) {
*arbol=malloc(sizeof(treenode));
if(arbol!=NULL) {
(*arbol)->numero=numero;
(*arbol)->leftp=NULL;
(*arbol)->rightp=NULL;
}else
printf("%d NO INSERTADO.NO HAY MEMORIA
DISPONIBLE.\n",numero);
}else if(numero<(*arbol)->numero)
insertarnodo(&((*arbol)->leftp),numero);
else if(numero>(*arbol)->numero)
insertarnodo(&((*arbol)->rightp),numero);
else
printf("\nDATO%d YA EXISTENTE EN EL
ARBOL\n",numero);
return;
}
void posorden(arbolbinario arbol)
{
if(arbol!=NULL) {
posorden(arbol->leftp);
posorden(arbol->rightp);
printf("%d",arbol->numero);
}
return;
}
void preorden(arbolbinario arbol)
{
if(arbol!=NULL) {
printf("%d",arbol->numero);
preorden(arbol->leftp);
preorden(arbol->rightp);
}
return;
}
void enorden (arbolbinario arbol)
{
if(arbol!=NULL) {
enorden(arbol->leftp);
printf("%d",arbol->numero);
enorden(arbol->rightp);
85
}
return;
}
int vacio(arbolbinario arbol)
{
return(arbol==NULL);
}
void salida(void)
{
clrscr();
gotoxy(25,15);printf("ENTER PARA SALIR DEL PROGRAMA ");
getch();
return;
}
86
13 Mtodos de ordenacin
Definicin:
Los mtodos de ordenacin de datos consiste en disponer un conjunto de
datos, o una estructura en un determinado orden con respecto a alguno de sus
campos.
Debido a que las estructuras de datos son utilizadas para almacenar informacin, para
poder recuperar esa informacin de manera eficiente es deseable que aquella est
ordenada. Existen varios mtodos para ordenar las diferentes estructuras de datos
bsicas.
ms
eficientes
en
cuestin
de
tiempo
de
ejecucin.
87
ORDENAMIENTO.
Uno de los procedimientos ms comunes y tiles en el procesamiento de
datos, es la clasificacin u ordenacin de los mismos. Se considera
ordenar al proceso de reorganizar un conjunto dado de objetos en una
secuencia determinada. Cuando se analiza un mtodo de ordenacin,
hay que determinar cuntas comparaciones e intercambios se realizan
para el caso ms favorable, para el caso medio y para el caso ms
desfavorable.
La ordenacin de una lista de objetos a partir de algn orden lineal,
como por ejemplo <= para el caso de los nmeros, es un problema que
suele presentarse con mucha frecuencia al intentar la solucin
88
Clave:
Es el campo por el cual se ordena un elemento, osea es donde podemos
decidir desde donde se realiza la ordenacin.
89
Concepto:
Una lista de datos esta ordenada por una clave K(la cual permite ordenar la
informacin) , si la lista esta en orden con respecto a la calve anterior esta
puede ser en orden: ascendente (i<j) entonces (k[i]<=k[j])
Desendente: (i>j) entonces (k[i]>=k[j])
Hay numerosos mtodos de ordenamiento que difieren en eficiencia:
-Anlisis de algoritmo orientado a las comparaciones realizadas por cada
uno.
-Las comparaciones sern funciones de n siendo n el tamao del
vector a ordenar.
Por su importancia, nos centraremos en los esquemas de clasificacin
interna y veremos los principales algoritmos dentro de la misma,
agrupndolos segn la tcnica de ordenacin seguida (comparacin,
intercambio, seleccin, insercin, mezcla, etc), as como por la
complejidad computacional de los mismos.
En casi todos los casos, la aplicacin manual del algoritmo hace
evidente la medida del costo apropiada.
Veamos algunos de los mtodos ms representativos, atendiendo a las
tcnicas de ordenacin que los caracterizan.
90
METODOS DE ORDENACION
Ordenacin interna: Los datos se encuentran en memoria
(ya
siguiente:
93
Fcil implementacin.
Muy lento.
94
x[i]=temp;
}
return; }
Este tambin es uno de los mtodos de ordenacin ms simples. Su
principio de funcionamiento es la ordenacin por intercambio de objetos
adyacentes. La idea bsica es imaginar que los objetos a ordenar estn
en un arreglo "vertical" y que a tal sentido, los objetos con claves
menores son "ms ligeros" y por tanto "suben a la superficie"
primeramente. De ah, el sugerente nombre del mtodo. El arreglo es
recorrido varias veces de abajo hacia arriba. En cada pasada, ante un
par de elementos adyacentes se verifica si el ms "ligero" est debajo y,
en tal caso, se invierten. Tras haberse realizado el primer recorrido del
arreglo y haber aplicado sucesivamente lo anterior, el efecto resultante
es que el elemento "ms ligero" del arreglo, o sea el menor, ocupe la
primera posicin del mismo, o sea, alcanz la "superficie". En el
segundo recorrido la segunda clave menor ocupar la segunda posicin
del arreglo, y as sucesivamente. En el segundo recorrido, no es
necesario llegar hasta la posicin 1 del arreglo pues tenemos la certeza
de que en ella est el objeto de menor clave, en general, a partir de la
estrategia de ordenacin seguida, en el recorrido i no se intenta llegar
ms all de la posicin i del arreglo.
95
96
98
99
for j=2 to n do
begin
key = A[j]
i=j1
while i > 0 and A[i] > key do
begin
A[i + 1] = A[i]
i=i-1
end
A[i + 1] = key
end
Este mtodo en cualquiera de sus variantes es O(n) para el caso mejor y
O(n2) para el caso promedio y para el caso peor. Ya habamos
comentado que era estable.
Como hemos visto los tres mtodos estudiados tienen un tiempo de ejecucin
O(n2) y consumirn un tiempo (n2) en una buena parte de las secuencias de
entrada de n elementos.
Insercion
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#define N 10000
int a[N];
void insercion()
{
int ifi = 0, pos, num, imov;
srand(time(0));
for(; ifi<N; ifi++)
{
num = rand() % 20000;
pos = 0;
while(pos ifi && num > a[pos])
pos = pos + 1;
imov = ifi;
while(imov > pos)
{
a[imov] = a[imov-1];
imov = imov - 1;
}
a[pos] = num;
}
return;
}
100
void main(void)
{
srand(time(0));
for(int i = 0; i < N; i++)
a[i] = random(20000);
printf("Arreglo desordenado.\n");
for(i = 0; i < N; i++)
printf("%d\n", a[i]);
getch();
insercion();
printf("Arreglo ordenado.\n");
for(i = 0; i < N; i++)
printf("%d\n", a[i]);
getch();
}
Insercin binaria
Es el mismo mtodo que la insercin directa, excepto que la bsqueda del
orden de un elemento en la sublista ordenada se realiza mediante una
bsqueda binaria (ver algoritmos de bsqueda), lo que en principio supone un
ahorro de tiempo. No obstante, dado que para la insercin sigue siendo
necesario un desplazamiento de los elementos, el ahorro, en la mayora de los
casos, no se produce, si bien hay compiladores que realizan optimizaciones
que lo hacen ligeramente ms rpido.
101
end
intercambia(A[i] con A[indice_del_menor])
end
end
printf("%d\n", a[i]);
getch();
seleccion();
printf("Arreglo ordenado.\n");
for(i = 0; i < N; i++)
printf("%d\n", a[i]);
getch();
}
Tambin es otro de los mtodos ms sencillos y su principio de
funcionamiento es tambin el intercambio de objetos, pero en este caso
se intercambian objetos no necesariamente adyacentes. El mtodo
asume que los elementos a ordenar estn dispuestos sobre un arreglo.
En la primera pasada se halla el mnimo de los n elementos y se coloca
en la primera posicin del arreglo. En la segunda pasada se halla el
mnimo de los n-1 elementos restantes y se coloca en la segunda
posicin, y as sucesivamente, hasta que solo se considere una lista en
la que queden solo dos elementos a ordenar lo cual se logra
comparando los mismos en intercambindolos si fuera necesario.
Siguiendo esta estrategia, nos damos cuenta que tras i pasadas, los i
elementos menores estarn ordenados y ocuparan las posiciones
A[1] ... A[i] del arreglo.
El siguiente esquema ilustra el mtodo:
105
}
}
}
Corrida de ordenacin shell:
Void ordenacin shell (double a[], int n)
{ int i, j, k, intervalo = n/2;
while (intervalo > 0)
{ for (i = intervalo ; i <= n, i++)
j = i intervalo;
while (j >=0)
{k = j + intervalo;
if (a [j] <=a [k]) j = - 1;
else { double temp}
}
}
}
108
srand(time(0));
for(int i = 0; i < N; i++)
a[i] = random(20000);
printf("Arreglo desordenado.\n");
for(i = 0; i < N; i++)
printf("%d\n", a[i]);
getch();
shellSort();
printf("Arreglo ordenado.\n");
for(i = 0; i < N; i++)
printf("%d\n", a[i]);
getch();
}
Anlisis de Shellsort
El algoritmo funciona debido a que en el ltimo paso (con h = 1), una ordinaria
ordenacin por insercin se ejecuta para todo el arreglo. Pero como los datos
son previamente semiordenados, solo son necesarios algunos pasos del
Insertion sort. Con cunta exactitud realiza la ordenacin se mostrar a
continuacin. La secuencia de hs (denotada como h-secuencia) es solo una
de las posibles; de hecho, la eficiencia de Shellsort depende de qu hsecuencia es utilizada.
109
111
113
114
void imprime()
{
int i;
for(i = 0; i < n; i++)
{
printf("%d ", aux -> valor);
aux = aux -> sig;
}
printf("\n");
getch();
}
RAPIDORECURSIVO(A, N)
{El algoritmo ordena los elementos del arreglo utilizando el mtodo rpido, de
manera recursiva. A es un arreglo de N elementos}
1. Llamar al algoritmo REDUCERECURCIVO CON 1 y N
Observe el algoritmo rpido recursivo requiere para su funcionamiento de otro
algoritmo, que presentamos a continuacin.
115
116
117
entonces
Hacer BAND =
FALSO
Si no
Hacer AUX =
A[POS], A[POS] =
A [IZQ]
A[IZQ]
= AUX y POS =
IZQ
2.3.4 {Fin del condicional del paso 2.3.3}
2.4 {Fin del condicional del paso 2.3}
2. {Fin del ciclo del paso 2}.
SECUENCIALCONLISTAS (P,X)
{Este algoritmo busca secuencialmente al elemento X en la lista cuyo nodo
inicial esta apuntado por P}
{Q es una variable de tipo puntero. BANDERA es una variable de tipo
booleano}
1. Hacer Q = P y BANDERA
FALSO
2. Repetir mientras (Q NIL) y (BANDERA = FALSO) y (X Q^ .INFO)
2.1 SI Q^.INFO = X
Entonces
Hacer BANDERAS = VERDADERO
Si no
Hacer Q =
Q^.LIGA
Si
la
lista
estuviera
ordenada,
debera
modificarse
el
algoritmo
118
elementos, de forma que slo aumenta el contador del array del que sale el
elemento siguiente para el array-suma. Si quisiramos sumar los arrays {1,2,4}
y {3,5,6}, los pasos seran:
bsqueda. Analice la complejidad del mtodo secuencial.
Ordenacin por Intercalacin:
Inicialmente: i1=0, i2=0, is=0.
Primer elemento: mnimo entre 1 y 3 = 1. Suma={1}. i1=1, i2=0, is=1.
Segundo elemento: mnimo entre 2 y 3 = 2. Suma={1,2}. i1=2, i2=0, is=2.
Tercer elemento: mnimo entre 4 y 3 = 3. Suma={1,2,3}. i1=2, i2=1, is=3.
Cuarto elemento: mnimo entre 4 y 5 = 4. Suma={1,2,3,4}. i1=3, i2=1, is=4.
Como no quedan elementos del primer array, basta con poner los elementos
que quedan del segundo array en la suma:
Suma={1,2,3,4}+{5,6}={1,2,3,4,5,6}
int i1,i2,is;
int array1[N1],array2[N2],suma[N1+N2];
for(i1=i2=is=0;i1<N1 && i2<N2;is++) // Mientras no se me acabe ni array1 ni
array2:
{
if(array1[i1]<array2[i2]) // Si el elemento de array1 es menor:
{
suma[is]=array1[i1]; // se utiliza el de array1.
i1++;
}
else
// Pero si el elemento de array2 es menor:
{
suma[is]=array2[i2]; // se utiliza el de array2.
i2++;
}
}
for( ;i1<N1;i1++,is++) // Aadir los elementos de array1 (si quedan).
suma[is]=array1[i1];
for( ;i2<N2;i2++,is++) // Aadir los elementos de array2 (si quedan).
suma[is]=array2[i2];
Caractersticas
119
capacidad para almacenar todos los elementos de ambas listas A y B). Sean
los contadores ap, bp y cp con valor inicial 0 (se ponen al inicio de sus arreglos
respectivos). Lo que hace intercalar es copiar el menor de A[ap] y B[bp] en
C[cp] y avanzar los contadores apropiados. Cuando se agota cualquier lista de
entrada (A o B), los datos que quedan en la otra lista se copian en C.
Esperemos que al leer el codigo, el lector entienda los detalles menores tanto
de la rutina recursiva del algoritmo de recursin como de la rutina intercala ().
Void ord intercalacin (Dato * A, Dato * Temp., int izq, int der); /*funcion
recursiva! A es el array de datos. Tmp debe ser un array del tamao mayor o
120
igual a A. Izq y der son los extremos del subarreglo sobre el cual trabajaremos
en esta recursin. * /
Void intercalar ( Dato * A, Dato * Temp. Int izq, int centro, int der );
/* lo que hace esta rutina es intercalar las particiones [A[izq*, ..., A[centro_1] ] y
[ A [centro],..., A[der] ] (que deberan estar ya ordenadas) en el subarray.
[ tmp[izq], ..., tmp[der] ] y luego copiar los elementos nuevamente a A, en el
subarray [ A [izq], ..., A[der] ] * / void
que A */
Ord_intercalacin (A,Temp.,O,N_1);
}
void
ord_intercalacin (Dato * A, Dato Temp., int izq, int der)
{
if (izq < der)
/* Este if comprueba el caso base que es cuando la participacion pasada no
tiene elementos. */
{
/* Dividimos a la mitad el subarray [A[izq],...,A[der] ]
*/
void
Intercalar(Dato * tmp, int izq, int centro, int der)
{
/*Participacion seran [izq,,centro -1] y
[Centro, .der]*/
/*Contadores para la primera mitad la segunda y paga la
Intercalacin respectivamente.*/
int ap = izq, bp=centro, cp=izq;
while ((ap < centro)&&(bp<=der))
{
if (A[ap]<=A[bp])
{
tmp[cp]=A[ap];
ap++;
}
else
{
tmp[cp]=A[bp];
bp++;
}
cp++;
}
/*Terminamos de intercalary, ahora metemos los elementos de la lista que aun
no ha terminado de ser procesada.*/
while(ap<centro)
{
tmp[cp]=A[ap];
cp++;
ap++;
}
while(bp<=der)
{
tmp[cp]=A[bp];
cp++;
122
bp++;
}
/*Ahora que tenemos la intercalacion finalizada en tmp, la pasamos a A */
for(ap=izq; ap<=der; ap++)
A[ap]=tmp[ap];
}
Observar como la funcion principal mergesort() solamente es un manejador de
la funcion ord_intercalacin() en la cual se realiza todo el trabajo
recursivamente.
Si bien el algoritmo puede parecer largo es mas facil (desde nuestro punto de
vista) entenderlo que otros algoritmos mas cortos pero mas complejos como
por ejemplo la ordenacin de shell. La unica parte difcil es entender como
funciona la recurcion ya que el algoritmo intercalar es bastante facil.
que
se
tienen
estas
dos
listas
de
enteros
ordenadas
ascendentemente:
lista 1: 1 -> 3 -> 5 -> 6 -> 8 -> 9
lista 2: 0 -> 2 -> 6 -> 7 -> 10
Tras mezclarlas queda:
lista: 0 -> 1 -> 2 -> 3 -> 5 -> 6 -> 6 -> 7 -> 8 -> 9 -> 10
Esto se puede realizar mediante un nico recorrido de cada lista, mediante dos
punteros que recorren cada una. En el ejemplo anterior se insertan en este
orden -salvo los dos 6 que puede variar segn la implementacin-: 0 (lista 2), el
123
1 (lista 1), el 2 (lista 2), el 3, 5 y 6 (lista 1), el 6 y 7 (lista 2), el 8 y 9 (lista 1), y
por llegar al final de la lista 1, se introduce directamente todo lo que quede de
la lista 2, que es el 10.
En la siguiente implementacin no se crea una nueva lista realmente, slo se
modifican los enlaces destruyendo las dos listas y fusionndolas en una sola.
Se emplea un centinela que apunta a s mismo y que contiene como clave el
valor ms grande posible. El ltimo elemento de cada lista apuntar al
centinela, incluso si la lista est vaca.
struct lista
{
int clave;
struct lista *sig;
};
struct lista *centinela;
centinela = (struct lista *) malloc(sizeof(struct lista));
centinela->sig = centinela;
centinela->clave = INT_MAX;
...
struct lista *fusion(struct lista *l1, struct lista *l2)
{
struct lista *inic, *c;
if (l1->clave < l2->clave) { inic = l1; l1 = l1->sig; }
else { inic = l2; l2 = l2->sig; }
c = inic;
while (l1 != centinela && l2 != centinela) {
if (l1->clave < l2->clave) {
c->sig = l1; l1 = l1->sig;
}
else {
c->sig = l2; l2 = l2->sig;
}
c = c->sig;
}
if (l1 != centinela) c->sig = l1;
else if (l2 != centinela) c->sig = l2;
return inic;
}
124
- Segunda parte: divide y vencers. Se separa la lista original en dos trozos del
mismo tamao (salvo listas de longitud impar) que se ordenan recursivamente,
y una vez ordenados se fusionan obteniendo una lista ordenada. Como todo
algoritmo basado en divide y vencers tiene un caso base y un caso recursivo.
Ordenar(lista L)
inicio
si tamao de L es 1 o 0 entonces
Devolver L
si tamao de L es >= 2 entonces
Separar L en dos trozos: L1 y L2.
L1 = Ordenar(L1)
L2 = Ordenar(L2)
L = Fusionar (L1, L2)
Devolver L
fin
El algoritmo funciona y termina porque llega un momento en el que se obtienen
listas de 2 3 elementos que se dividen en dos listas de un elemento (1+1=2) y
en dos listas de uno y dos elementos (1+2=3, la lista de 2 elementos se volver
125
Dada: 3 -> 2 -> 1 -> 6 -> 9 -> 0 -> 7 -> 4 -> 3 -> 8 (lista original)
se divide en:
3 -> 2 -> 1 -> 6 -> 9 (lista 1)
0 -> 7 -> 4 -> 3 -> 8 (lista 2)
se divide en:
128
return l;
}
/* operaciones de lista */
void crearLCC(struct listacc *LCC)
{
LCC->cabecera = (struct lista *) malloc(sizeof(struct lista));
LCC->centinela = (struct lista *) malloc(sizeof(struct lista));
LCC->cabecera->sig = LCC->centinela;
LCC->centinela->sig = LCC->centinela;
}
/* inserta un elemento al comienzo de la lista */
void insertarPrimero(struct listacc LCC, int elem)
{
struct lista *nuevo;
nuevo = (struct lista *) malloc(sizeof(struct lista));
nuevo->clave = elem;
nuevo->sig = LCC.cabecera->sig;
LCC.cabecera->sig = nuevo;
}
int main(void)
{
struct listacc LCC;
crearLCC(&LCC);
centinela = LCC.centinela;
centinela->clave = INT_MAX;
insertarPrimero(LCC, 8);
insertarPrimero(LCC, 3);
insertarPrimero(LCC, 4);
insertarPrimero(LCC, 7);
insertarPrimero(LCC, 0);
insertarPrimero(LCC, 9);
insertarPrimero(LCC, 6);
insertarPrimero(LCC, 1);
insertarPrimero(LCC, 2);
insertarPrimero(LCC, 3);
LCC.cabecera = ordenfusion(LCC.cabecera->sig);
return 0;
}
Ordenacin por montculos (Heapsort)
Recordemos que un montculo Max es un arbol binario completo cuyos elementos estan
ordenados del siguiente modo: para cada subrbol se cumple que la raiz es mayor que
129
ambos hijos. Si el montculo fuera Min, la raiz de cada subrbol tiene que cumplir con
ser menor que sus hijos.
Recordamos que, si bien un montculo se define como un arbol, para
representar este se utiliza un array de datos, en el que se acceden a padres e
hijos utilizando las siguientes transformaciones sobre sus indices. Si el
montculo esta almacenado en el array A, el padre de A[i] es A[i/2] (truncando
hacia abajo), el hijo izquierdo de A[i] es A[2*i] y el hijo derecho de A[i]es
A[2*i+1].
Caractersticas:
130
Bsqueda secuencial
Consiste en recorrer y examinar cada uno de los elementos del array hasta
encontrar el o los elementos buscados, o hasta que se han mirado todos los
elementos del array.
131
for(i=j=0;i<N;i++)
if(array[i]==elemento)
{
solucion[j]=i;
j++;
}
Este algoritmo se puede optimizar cuando el array est ordenado, en cuyo caso
la condicin de salida cambiara a:
for(i=j=0;array[i]<=elemento;i++)
o cuando slo interesa conocer la primera ocurrencia del elemento en el array:
for(i=0;i<N;i++)
if(array[i]==elemento)
break;
En este ltimo caso, cuando slo interesa la primera posicin, se puede utilizar
un centinela, esto es, dar a la posicin siguiente al ltimo elemento de array el
valor del elemento, para estar seguro de que se encuentra el elemento, y no
tener que comprobar a cada paso si seguimos buscando dentro de los lmites
del array:
array[N]=elemento;
for(i=0;;i++)
if(array[i]==elemento)
break;
Si al acabar el bucle, i vale N es que no se encontraba el elemento. El nmero
medio de comparaciones que hay que hacer antes de encontrar el elemento
buscado es de (N+1)/2.
132
133
Bsqueda Binaria.
La bsqueda binaria es el mtodo ms eficiente para encontrar
elementos en un arreglo ordenado. El proceso comienza comparando el
elemento central del arreglo con el valor buscado. Si ambos coinciden
finaliza la bsqueda. Si no ocurre as, el elemento buscado ser mayor o
menor en sentido estricto que el central del arreglo. Si el elemento
buscado es mayor se procede a hacer Bsqueda binaria en el subarray
superior, si el elemento buscado es menor que el contenido de la casilla
central, se debe cambiar el segmento a considerar al segmento que est
a la izquierda de tal sitio central.
ALGORITMO:
{Este algoritmo busca el elemento X en el arreglo ordenado V de N
componentes}
{izq, cen, der, var, tipo entero. Bandera. Booleano}
1. Hacer izq1.DerN y BanderaFalso.
2. Repetir mientras(izq<=Der) y (Bandera. Falso)
Hacer CENPARTE ENTERA((izq+Der)/2)
2.1 Si X=V[CEN]
Entonces
Hacer banderaVERDADERO
Sino{Redefinir intervalo de busqueda}
2.1.1 Si X>V[CEN]
134
entonces
Hacer izqCEN+1
Si no
Hacer DERCEN-1
2.1.2{Fin del condicional del paso 2.1.1}
2.2 {Fin del condicional del paso 2.1}
3{Fin del ciclo del paso 2}
4 Si BANDERA=VERDADERO
entonces
Escribir El elemento esta en la posicin CEN
Sino
Escribir El elemento no esta en el arreglo
Fin del condicional del paso 4.
TABLAS HASH
INTRODUCCIN.
Una aproximacin a la bsqueda radicalmente diferente a las anteriores
consiste en proceder, no por comparaciones entre valores clave, sino
encontrando alguna funcin h(k) que nos d directamente la localizacin
de la clave k en la tabla.
La primera pregunta que podemos hacernos es si es fcil encontrar tales
funciones h. La respuesta es, en principio, bastante pesimista, puesto
que si tomamos como situacion ideal el que tal funcin d siempre
localizaciones distintas a claves distintas y pensamos p.ej. en una tabla
de tamao 40 en donde queremos direccionar 30 claves, nos
encontramos con que hay 4030 = 1.15 * 1048 posibles funciones del
conjunto de claves en la tabla, y slo 40*39*11 = 40!/10! = 2.25 * 10 41 de
ellas no generan localizaciones duplicadas. En otras palabras, slo 2 de
cada 10 millones de tales funciones serian 'perfectas' para nuestros
propsitos. Esa tarea es factible slo en el caso de que los valores que
vayan a pertenecer a la tabla hash sean conocidas a priori. Existen
135
necesitamos
una
funcin
que
transforme
uniformemente
sobre
el
intervalo
[0..M-1].
Las
dos
136
Hasing Multiplicativo.
Esta tcnica trabaja multiplicando la clave k por s misma o por una
constante, usando despus alguna porcin de los bits del producto como
una localizacin de la tabla hash.
Cuando la eleccin es multiplicar k por s misma y quedarse con alguno
de los bits centrales, el mtodo se denomina el cuadrado medio. Este
metodo an siendo simple y pudiendo cumplir el criterio de que los bits
elegidos para marcar la localizacin son funcin de todos los bits
originales de k, tiene como principales inconvenientes el que las claves
con muchos ceros se reflejarn en valores hash tambin con muchos
ceros, y el que el tamao de la tabla est restringido a ser una potencia
de 2.
Otro mtodo multiplicativo, que evita las restricciones anteriores consiste
en calcular h(k) = Int[M * Frac(C*k)] donde M es el tamao de la tabla y
0 <= C <= 1, siendo importante elegir C con cuidado para evitar efectos
negativos como que una clave alfabtica K sea sinnima a otras claves
obtenidas permutando los caracteres de k. Knuth (ver bibliografa)
prueba que un valor recomendable es:
137
3. RESOLUCIN DE COLISIONES.
El segundo aspecto importante a estudiar en el hasing es la resolucin
de colisiones entre sinnimos. Estudiaremos tres mtodos basicos de
resolucin de colisiones, uno de ellos depende de la idea de mantener
listas enlazadas de sinnimos, y los otros dos del clculo de una
secuencia de localizaciones en la tabla hash hasta que se encuentre que
se encuentre una vaca. El anlisis comparativo de los mtodos se har
en base al estudio del nmero de localizaciones que han de examinarse
hasta determinar donde situar cada nueva clave en la tabla.
Para todos los ejemplos el tamao de la tabla ser M=13 y la funcin
hash h1(k) que utilizaremos ser:
HASH = Clave Mod M
y los valores de la clave k que consideraremos son los expuestos en la
siguiente tabla:
138
139
141
que genere una secuencia de valores distinta para dos claves distintas
aunque tenga el mismo valor de funcin hash, y por ltimo
143
4. BORRADOS Y REHASING.
Cuando intentamos borrar un valor k de una tabla que ha sido generada
por direccionamiento abierto, nos encontramos con un problema. Si k
precede a cualquier otro valor k en una secuencia de pruebas, no
podemos eliminarlo sin ms, ya que si lo hiciramos, las pruebas
siguientes para k se encontrarian el "agujero" dejado por k por lo que
podramos concluir que k no est en la tabla, hecho que puede ser
falso.Podemos comprobarlo en nuestro ejemplo en cualquiera de las
tablas. La solucin es que necesitamos mirar cada localizacin de la
tabla hash como inmersa en uno de los tres posibles estados: vacia,
ocupada o borrada, de forma que en lo que concierne a la busqueda,
una celda borrada se trata exectamente igual que una ocupada.En caso
de inserciones, podemos usar la primera localizacin vacia o borrada
que se encuentre en la secuencia de pruebas para realizar la operacin.
Observemos que este problema no afecta a los borrado de las listas en
el encadenamiento separado. Para la implementacin de la idea anterior
podria pensarse en la introduccin en los algortmos de un valor etiqueta
para marcar las casillas borradas, pero esto sera solo una solucin
parcial ya que quedara el problema de que si los borrados son
144
145
ln(1-)
BF=1/(1-)
con valores medios cuando -> 1 de M y M/2, respectivamente.
Para facilitar la comprensin de las frmulas podemos construir una
tabla en la que las evaluemos para distintos valores de :
La eleccin del mejor mtodo hash para una aplicacin particular puede
no ser fcil. Los distintos mtodos dan unas caractersticas de eficiencia
similares. Generalmente, lo mejor es usar el encadenamiento separado
para reducir los tiempos de bsqueda cuando el nmero de registros a
procesar no se conoce de antemano y el hash doble para buscar claves
cuyo nmero pueda, de alguna manera, predecirse de antemano.
146
TablaHash CrearTablaHash ()
{
tLista *t;
register i;
t=(tLista *)malloc(NCASILLAS*sizeof(tLista));
if (t==NULL)
error("Memoria insuficiente.");
for (i=0;i<NCASILLAS;i++)
t[i]=crear();
return t;
}
148
return(valor%NCASILLAS);
}
Y funciones del tipo MiembroHash, InsertarHash, BorrarHash pueden
ser programadas:
int MiembroHash (char *cad,TablaHash t)
{
tPosicion p;
int enc;
int pos=Hash(cad);
p=primero(t[pos]);
enc=O;
while (p!=fin(t[pos]) && !enc) {
if (strcmp(cad,elemento(p,t[pos]))==O)
enc=1;
else
p=siguiente(p,t[pos]);
}
return enc;
}
void InsertarHash (char *cad,TablaHash t)
{
int pos;
if (MiembroHash(cad,t))
return;
pos=Hash(cad);
insertar(cad,primero(t[pos]),t[pos]);
}
void BorrarHash (char *cad,TablaHash t)
{
tPosicion p;
int pos=Hash(cad);
p=primero(t[pos]);
while (p!=fin(t[pos]) && !strcmp(cad,elemento(p,t[pos])))
p=siguiente(p,t[pos]));
if (p!=fin(t[pos]))
borrar(p,t[pos]);
}
149
etc...
150
implementacin
del
Hasing
Abierto.
funciones
del
tipo
151
rboles B
Son rboles de bsqueda de n ramas (no binarios).Desarrollados por
RudolfBayer yEduard M. McCreight (Boeing).
Son uno de los sistemas ms utilizados para indexar informacin
almacenada en ficheros.
Solucionan los problemas de los ABB.
Caractersticas de los rboles B
Orden de un rbol B: nmero mximo de ramas que pueden partir
153
rboles-B
Podemos limitar el nmero mximo de consultas al hacer una
bsqueda imponiendo una profundidad mxima hemos de
aumentar el orden.
El tamao de un nodo debera ser lo ms prximo posible al
tamao de un cluster (aunque menor).
Sobre la eficiencia y el orden:
Estos rboles se suelen usar para indexar datos en disco:
Mayor orden
Menor profundidad
El orden se calcula en funcin del tamao de un cluster de disco.
tamao la mitad
Funcin Busq_Bin_Rec (x:tipoelem; A:lista; ini,fin:tipoposicion): tipoposicion;
Variables
mitad: tipoposicion;
Inicio
Si (fin > ini)
Entonces Bus_Bin_Rec _ posicion_nula
Si_No
Si (ini = fin)
Entonces Si A[ini] = x
Entonces Bus_Bin_Rec _ ini
Si_No Bus_Bin_Rec _ posicion_nula
Fin_Si
Si_No mitad _ pos_central(A, ini, fin);
Si x <= A[mitad]
Entonces Bus_Bin_Rec _ Bus_Bin_Rec (x,A,ini,mitad)
Si_No Bus_Bin_Rec _ Bus_Bin_Rec (x,A,mitad+1,fin);
Fin_Si
Fin_Si
Fin_Si
Fin.
155
156
157
158
F2: 27 8 5 15
Ahora se funden los archivos F1 y F2 formando pares ordenados:
F: 19 27 2 8 5 36 15 20 6
Se vuelve a dividir F en partes iguales y en secuencias de longitud 2
F1: 19 27 5 36 6
F2: 2 8 15 20
F1 y F2 se funden utilizando las secuencias de longitud 2:
F: 2 8 19 27 5 15 20 36 6
Se dobla la longitud de la secuencia (4) y se vuelve a dividir F
F1: 2 8 19 27 6
F2: 5 15 20 36
La fusin de las secuencias de 4 elementos producen el nuevo archivo F.
F: 2 5 8 15 19 20 27 36 6
Se realiza una nueva particin con secuencias de longitud 8.
F1: 2 5 8 15 19 20 27 36
F2: 6
Por ltimo la fusin dar:
F: 2 5 6 8 15 19 20 27 36
159
F1:06 09 18 20 35
F2:10 16 25 28 66 82 87
F3:06 09 10
El proceso continua hasta que en uno u otro archivo se detecte el fin de archivo
en tal caso solo tendrn que transcribir las claves del archivo no vaco al
archivo de
Salida F3.Este es el resultado final de la intercalacin entre los archivos F1 y
F2:
F3:06 09 10 16 18 20 25 28 35 66 82 87
Ahora analcese el algoritmo de intercalacin de archivos.
160
Algoritmo Intercalacin
INTERCALACIN(F1,F2,F3)
{El algoritmo intercala los elementos de dos archivo ya ordenado F1 y F2 y
almacena el resultado en el archivo F3 }
{R1 y R2 son variables de tipo entero BAND variable de tipo booleano}
1.Abrir los archivo F1 y F2 para lectura
2.Abrir el archivo F3 para escritura
3.leer R1 de F1 y R2 de F2
{R1y R2 son las primera claves de F1 y F2 respectivamente }
4. Repetir mientras (no sea el fin del archivo de F1) y (no sea el fin de archivo
de F2)
4.1 si R1< R2
entoces
Escribir R1 en F3
Leer R1 de F1
Si no
Escribir R2 en F3
Leer R2 de F2
4.2{fin del condicional del paso 4.1}
5. {fin del ciclo del paso 4}
6. hacer BAND
FALSO
leer R2 de F2
Escribir R2 en F3
7.1.1.2 {fin del ciclo del paso 7.1.1.1}
Hacer BAND VERDADERO
Si no
Escribir R2 en F3
Leer R1 de F2
7.1.2 {Fin del condicional del paso 7.1.1}
si no
7.1.3 si R1 < R2
entonces
Escribir R1 en F3
Leer R1 de F1
Si no
Escribir R2 en F3
Escribir R1 en F3
7.1.3.1 Repetir mientras (no se el fin de archivo de F1)
Leer R1 de F1
Escribir R1 en F3
7.1.3.2
Hacer BAND
7.1.4
7.2
VERDADERO
162
1. ADMINISTRACIN DE MEMORIA.
MS-DOS , es un sistema operativo monotarea, usualmente un usuario lanza un
programa escribiendo el nombre del archivo ejecutable luego del indicador de
comandos del COMMAND. El cargador es disponible a travs de la funcin 4Bh
de la INT 21h, el despachador del DOS. Este asigna al programa un bloque de
memoria suficientemente grande para alojarlo, copia en el una imagen del
programa obtenida del archivo ejecutable, actualiza los registros de la CPU y
algunas estructuras del sistema, y por ultimo da el control de ejecucin al
programa.
La asignacin de memoria en los segmentos es responsabilidad de diferentes
componentes en diferentes etapas en el sistema, a saber la etapa de
compilacin (compiladores), en lace (enlazadores o linkers)y carga (cargador).
163
ENLACE
En esta etapa se reagrupan todos los archivos objetos pertenecientes al
programa y se genera un solo archivo ejecutable. Las referencias externas son
resueltas aqu, as como las llamadas a funciones de biblioteca del sistema.
CARGA
Durante esta etapa se carga en memoria el programa ejecutable, reservndose
primero espacio de memoria suficiente mente grande para la imagen del
programa. Luego de algunas actualizaciones de estructuras del sistema,
comienza la ejecucin del programa. El mecanismo de administracin de
memoria podra permitir la comparticin de algunos bloques de memoria
comunes entre diferentes procesos, en particular aquellos que contiene cdigo
164
165
166
167
cola de espera con muchos procesos mientras que otra particin pudiera estar
vaca, a este problema se le denomina
Fragmentacin externa.
Una mejora a este esquema podra conseguirse permitindose que si una
particin se vaca, se le asigne un proceso asociado a otra particin.
Este esquema de administracin contempla la proteccin de las particiones,
que permita proteger cada de las particiones de las particiones adyacentes,
esto significa que cada proceso de usuario, as como el propio sistema
operativo debe estar confiado que no se vera perturbado por otro proceso. En
este caso, como en la mayora de los esquemas de administracin de memoria,
la proteccin debe estar apoyada en las particularidades del hardware. Un
mecanismo de proteccin, que a su vez garantiza relocalizacin dinmica se
tiene mediante el uso de dos registros de CPU, un registro llamado base y un
registro llamado limite. El registro base indica la direccin absoluta de inicio de
la particin y el registro limite indica el tamao de la particin. El espacio de
direcciones virtuales de un programa va de la direccin de comienzo 0 hasta
una direccin mxima(siempre menor que limite).
Cuando un programa genera una direccin de memoria (perteneciente al
espacio de direcciones virtuales del programa.), esta se compara con el
contenido del registro lmite, si es mayor o igual el hardware genera una
trampa, sino se suma al contenido del registro base para obtener la direccin
absoluta resultante (que estar en la propia particin). Entonces no es
necesario relocalizar el programa en ningn momento, incluso es posible mover
un programa de una particin a otra.
Cuando el proceso se hace activo tambin la particin donde reside
asignndose a los registrndose base y limite los valores correspondiente a
esta particin. A continuacin se muestra de que manera actan estos
registros.
R. Limite
168
ERROR
CPU
>
Direccin Particin
+
R.Base
los que
la
memoria
soporta,
principalmente
sistemas
169
170
Con este criterio se otorga al proceso solicitndole aquella particin libre que
mejor se ajuste a los requerimientos de memoria del proceso, es decir, el
menor bloque disponible de entre todos los que satisfaga las necesidades del
proceso.
Este criterio consiste en otorgar aquella particin mas grande que pueda
contener el proceso solicitante, el argumento que fundamenta este criterio es
que el bloque sobrante de esta particin puede ser utilizada para ser asignada
a otro proceso.
Otro aspecto importante que caracteriza a este modelo de administracin de
memoria es que tambin adolece de fragmentacin externa, esta ocurre en el
continuo ingreso y salida de procesos y de memoria, este fenmeno genera
que se produzca huecos libres en la memoria que individualmente no son
suficientes para contener a los procesos que requieren ejecutarse. En el pero
de los casos, existirn muchos pequeos huecos libres
esparcidos en la
Para solucionar este problema se puede tener dos listas enlazadas, una para
los huecos y otra para los procesos, sin embargo, esto obliga a mantener
estas dos listas actualizadas, es decir deben actualizarse ambas cuando un
proceso termina y cuando se otorga memoria a un proceso
A continuacin se presenta un ejemplo de cmo funciona este
mecanismo:
1
P
2
0
3 4 5 6
3
7 8
9 10 11 12 13 14 15 16 17 18 19 20
13 2
1.3 PAGINACIN.
173
Marco 1.
Pag 2.
Marco 2.
Pag 3.
Marco 3.
Pag 4.
Marco 4.
Pag 5.
Marco 5.
ESPACIO DE
DIRECCIONAMIENTO.
LGICO.
ESPACIO DE
DIRECCIONAMIENTO
REAL
174
175
TABLAS DE PGINAS.
176
La MMU traduce las direcciones virtuales en reales con el apoyo de una tabla
de pginas. La tabla de paginas es un arreglo que es diseccionado por la
primera parte de la direccin virtual, dicho campo se usa como un ndice a la
tabla de paginas. Cada entrada en la tabla de pginas por lo menos en el
nmero de marco de pginas asociado a la pgina. Es frecuente que exista un
bit denominado Presente, que indica si la pgina se encuentra presente o no en
la memoria. Si el bit esta en 1, entonces la pagina tienen asociado un marco de
pagina en memoria. Este bit es til para implementar el mecanismo de memoria
virtual.
Las tablas de pginas usualmente se almacenan en memoria privilegiada. Por
lo general existe un registro de tabla de pgina que actualiza cuando se hace
activo un proceso y que contiene la direccin base de la tabla de pginas del
proceso. Esta direccin es parte del bloque de control de proceso y se guarda
en cada conmutacin de contexto. El contenido de este registro es utilizado por
MMU para traduccin de direcciones. Usualmente el hardware proporciona
registros asociativos o memorias cache de alta velocidad de acceso para
almacenar las entradas de tablas de pginas recientemente usadas.
Esto acelera los accesos a memorias, pues normalmente por cada acceso a
memoria de un programa, el hardware hace dos accesos, uno par ubicar el
marco dentro de la tabla de pginas y otro para acceder a la direccin
generada por el programa.
Cuando las pginas lineales resultan muy grandes, algunos sistemas
proporcionan una jerarqua de 2,3 o ms niveles de tablas de pginas.
Una entrada de una tabla de pginas contiene el nmero de marco de pgina
que almacena la pgina correspondiente de un proceso. Adems, es comn
que se almacenen otras informaciones para identificar el estado de la pgina.
Entre estos datos:
178
Sin embargo, puede ocurrir que el sistema no posea marcos de pginas libres
o bien el nmero de marcos libres sea inferior a los exigidos para el buen
funcionamiento del sistema. En este caso el sistema debe ejecutar alguna
accin que le permita liberar marcos de pginas para asignrselos a las
pginas que lo necesitan. Las pginas que tienen asociados marcos de
pginas que se elijan como donadoras de marcos deben ser guardadas en
disco. De aqu es necesario que el sistema implemente estrategia eficiente que
le permitan reemplazar pginas de
que la primera pagina de la lista sea la de uso mas reciente y la ultima sea la
de uso menos reciente. Entonces cuado una pagina es referenciada se le
coloca en la cabecera de la lista. El principal problema de este esquema
consiste en que la lista debe ser actualizada continuamente despus de cada
referencia a memoria y esto conlleva a demasiada sobrecarga en el sistema.
Otras variantes de implementacin pueden ser proporcionadas por el hardware.
Una de estas soluciones consiste en tener un contador por paginas (podra
estar incorporado a una entrada en la tabla de paginas) el cual se incrementa
despus que la pagina es referenciada. Luego, cuado ocurre un fallo de pagina
se elige aquella pagina que posea el contador con menor valor numrico.
LRU es un algoritmo de muy buenos resultados que ha sido muy usado en la
prctica.
Tambin son conocidas algunas aproximaciones a LRU como LFU y otros.
CLASE DE REFERENCIA.
Otra solucin al problema de seleccionar una pagina victima y de fcil
implementacin, se apoya en el uso de los bits de referencia y modificado para
caracterizar 4 clases de referencia a paginas. Este algoritmo consiste en
reemplazar aquellas pginas que no han sido utilizadas ltimamente.
El bit de referencia es activado cuando se hace referencia la pgina y el bit
modificado es activado cuando la pgina es modificada. El bit de referencia es
desactivado peridicamente para poder diferenciar las pginas de uso reciente
de las de uso no tan reciente.
La definicin de las clases es la siguiente:
180
Algoritmo FIFO.
Como su nombre sugiere, la idea del algoritmo es seleccionar como pagina
victima a la pgina que tenga ms tiempo de carga en memoria. Este algoritmo
es de fcil implementacin pero de un desempeo inestable. Una posible
implementacin puede ser de llevar a cabo mediante el uso de una lista que
enlace todas las pginas que estn en memoria. Dicha lista estar ordenada
segn el orden de cargadas, es decir, la primera pagina de la lista es la mas
antigua y la ultima la mas recientemente cargada.
Cuando ocurre un fallo de pagina se elige otra como victima la primera pagina
de la lista, uno de los inconvenientes de este algoritmo es que no considera la
importancia de las paginas ni con que frecuencia se estn utilizando.
Es posible que la primera pgina pertenezca un bloque de rutinas de uso
comn. En tal caso la razn de fallos de pginas puede ser muy alta.
ALGORITMO DE LA SEGUNDA OPORTUNIDAD
Este algoritmo introduce una mejora al algoritmo FIFO, se apoya en el uso del
bit de referencia de las pginas. Con esta mejora se toma en cuenta la
frecuencia del uso de las pginas en alguna medida.
El algoritmo acta de la siguiente manera: cuando ocurre un fallo de pgina se
revisa la lista de pginas desde la mas antigua hasta la mas nueva. Si el bit de
referencia de la pgina ms antigua es 0, entonces se reemplaza esta pgina
pero si este bit es 1, entonces se coloca el bit de referencia en 0 y se coloca la
pagina al final de la lista, luego se consulta la siguiente pgina mas antigua y
as sucesivamente.
A este algoritmo se le llama de segunda oportunidad porque se le da a cada
pgina una segunda oportunidad de quedarse en memoria si es que ha sido
181
Por lo general, los procesos no requieren tener todas sus instrucciones ni datos
en memoria sino que tanto los datos como las instrucciones se necesitan por
ciertos periodos de tiempo. Esto significa que por lo general, en un periodo de
tiempo, el proceso solo requiere un conjunto de sus pginas en memoria.
A esta caracterstica de los procesos se le denomina localidad de referencia.
Al conjunto de pginas que requieren un proceso en un intervalo de tiempo de
su ejecucin se le conoce como conjunto de trabajo. Lgicamente, si un
proceso tiene su conjunto de trabajo en memoria determinado momento,
entonces el proceso no genera fallos de pginas.
Dadas las caractersticas de los conjuntos de trabajo t de las ventajas del
conocimiento de los conjuntos de trabajo de un proceso, muchos sistemas
intentan llevar un registro de los conjuntos de trabajo de los procesos de tal
manera que la siguiente vez que se ejecute el proceso, las paginas asociadas a
sus conjuntos de trabajo puedan ser cargadas antes de que se necesiten. A
este mecanismo se le conoce como prepaginacin.
Por otro lado, el concepto de conjunto de trabajo puede ser utilizado por un
algoritmo de reemplazo de pginas, pues adems de ejecutar el criterio de
seleccin implcito en el algoritmo se puede ver si la pagina seleccionada
pertenece o no al conjunto de trabajo, si pertenecen entonces la pgina no se
reemplaza.
Tamao de la paginacin:
usuario, es decir, donde las tareas que no son lanzadas por el sistema, son
lanzadas por el usuario que esta operando el sistema. Puede ocurrir que
existan varias copias de texto de un programa del cual estn cargadas varias
instancias en memoria. Esta situacin puede conllevar a un gasto innecesario
de espacio de memoria.
En estas condiciones el sistema debera permitir compartir las pginas
asociadas al cdigo de la aplicacin. En general, texto de un programa no
debera automatizarse, para evitar conflictos entre las diferentes instancias. Por
ejemplo, con el CPU 386 los segmentos de cdigo de los programas se
marcan, por lo general, de solo ejecucin.
Suponga, por ejemplo, que dos usuarios, P y R, de un sistema, estn usando el
mismo editor de texto, el sistema debera marcar como compartidas las
paginas que estn relacionadas con el cdigo ejecutable de la aplicacin y las
paginas de datos del editor de cada uno de los usuarios
deberan ser
1.5 SEGMENTACION.
Uno de los problemas fundamentales de la paginacin es que no se adecua a
la visin que el usurario tiene de sus programas y de la memoria real. Con la
paginacin, el espacio de direcciones virtuales de un programa es un bloque de
localizaciones consecutivas cuya direccin inicial relativa es 0. En ese espacio
se agrupan todos los elementos del programa: variables, pila y texto. En
general, este esquema ofrece muchas ventajas al desarrollador del sistema, la
implementacin es sencilla, proporciona un mecanismo de relocalizacin
dinmica y permite implementar el mecanismo de memoria virtual de una
manera limpia y sencilla, pero se aleja de la perspectiva del usuario con
respecto al programa y a la forma en que se almacena el programa en
memoria.
La visin que tiene un usuario con respecto a un programa toma en cuenta que
un programa es una coleccin de varios elementos funcionalmente distintos.
Entre estos elementos se cuentan, en general, los datos, las pilas y las
entidades de cdigo. Dividir un programe en partes de igual tamao no es
184
Bit Presente.
Bits de referencia/Modificado.
Cuando una direccin virtual (formada por dos valores, el numero de segmento
y el desplazamiento dentro del segmento) es generada por un programa, la
MMU obtiene la entrada de la tabla de segmentos cuyo ndice coincide con el
numero de segmento, verifica que la operacin que se realizara es permitida,
de lo contrario se produce una trampa al sistema, compara el desplazamiento
con el limite, si es mayor o igual se produce una direccin base del segmento
para producir la direccin fsica correspondiente.
SEGMENTACIN PURA
La implantacin de la segmentacin difiere del caso de la paginacin en un
sentido esencial: las pginas tienen un tamao fijo y los segmentos no. La
figura 14 muestra un ejemplo de memoria fsica que contiene al principio 5
segmentos. Consideremos que el segmento 1 se elimina y su lugar se ocupa
por el segmento 7, que es menor. El rea que queda entre el segmento 7 y el 2
es un hueco. Luego, el segmento 4 se reemplaza por el segmento 5 y el
segmento 3 es reemplazado por el segmento 6. Despus de que el sistema
est en ejecucin durante cierto tiempo, la memoria quedar dividida en varios
bloques, algunos con segmentos y otros con huecos.
Comparacin de paginacin y segmentacin.
Considerando
Necesita
programador
saber
si
el
Paginacin
Segmentacin
No
est
186
Muchos
No
No
No
de direcciones existen?
Puede el espacio total de
direcciones
exceder
tamao
la
de
el
memoria
fsica?
Pueden
distinguirse
los
adecuarse
las
tablas
con
con
tamaos fluctuantes?
Se
facilita
el
uso
de
procedimientos compartidos
entre los usuarios?
Para qu se invent esta Para
tcnica?
obtener
un Para
permitir
que
los
en
espacios
memoria direcciones
fsica
de
y
poder
proporcionar la proteccin y
uso de objetos compartidos
187
188
189
348
458
670
1023
Bloque 1
Bloque 2
Bloque 3
Espacio libre
(Tamao = 348)
(Tamao = 110)
(Tamao = 212)
(Tamao = 354)
348
458
670
Bloque 1
Espacio libre
Bloque 3
Espacio libre
(Tamao =348)
(Tamao =110)
(Tamao =212)
(Tamao =354)
Hay ahora 464 palabras de espacio libre; no obstante, dado que el espacio libre
esta dividido en bloques no continuos, una peticin de un bloque de 400
palabras no podra ser satisfecha. Suponiendo que el bloque numero tres fuese
liberado ahora. Es claro que no se desea retener tres bloques libres de
110,212, y 354 palabras. En lugar de ellos se deber combinar los bloques en
un solo bloque grande de 676 palabras de manera que pueda ser satisfechas
peticiones grandes posteriores.
BLOQUE 1
ESPACIO LIBRE
Tamao =348
(Tamao = 676)
disponible,
presente peticiones de
190
Asignand
125
Libre
325
500
Asignand
(1)
(2)
750
Libre
800
850
950
Asig.
Asig.
Asig.
(3)
(4)
(5)
1023
Libre
Antes de la compactacin
Una variable freepoint contiene la direccin de la primera localidad que sigue al
ltimo nodo asignado. Freepoint es igual a 950 note que todas la localidades de
memoria entre freepoint y la direccin mayor de la memoria esta libre. Cuando
se libre un bloque, freepoint permanece
Intacta y no ocurren combinaciones de espacios libres. Cuando se asigna un
bloque de tamao, freepoint se incrementa en n. Estos continua hasta que se
pida un bloque de tamao n y freepoint +n-1 sea mayor que la direccin mayor
de la memoria.
La peticin no puede ser satisfecha sin que ocurra algo antes.
En ese momento se interrumpen las rutinas de los usuarios y se llama a una
rutina de compactacin. Una rutina de este tipo copia todos los nodos
191
Asig.(1)
125
300
350
400
Asig.(3)
Asig.(4)
Asig.(5)
Asig.(2)
500
Libre
Despus de la compactacin
Freepoint=500
Cuando se copia los bloques asignados en porciones mas pequeas, hay que
tener especial cuidado
Para que los apuntadores mantengan sus valores correctos.
As, con el objeto de que la compactacin sea exitosa, tiene que haber un
mtodo para determinar si los contenidos de una localidad dada son
direcciones.
Una alternativa es un sistema que calcule direcciones como desplazamiento de
alguna direccin base. En ese caso solo tiene que ser cambiados los
contenidos de esa direccin base y el desplazamiento en la memoria en la
memoria no necesita ser alternado.
Una rutina de compactacin requiere de un mtodo mediante el cual puede ser
determinado el tamao de un bloque y su estado (asignado o libre).
La compactacin es similar a la recoleccin de basura en que el
procesamiento de todos los usuarios de detiene cuando el sistema toma
el tiempo para limpiar su memoria. Por
192
125
300
350
400
500
650
1
Asignado Asignado Asignado Asignado Asignado Asignado Libre
(1)
(2)
(3)
(4)
(5)
(6)
cantidad
de memoria
contigua (por
tal
193
de
un
mdulo.
// por apent.
cout << *apent ; // Despliega el contenido del objeto // apuntado por
apent. delete apent ; // Libera el espacio de memoria manejado // por
apent. }
194
Listado
6.4.-
Aplicacin
de
new
delete.
porque
existe
espacio
suficiente
en
el
montculo.
6.5.-
Reservacin
de
memoria
para
una
variable
dinmica.
195
de
tipo
doble;
al
tiempo
que
se
le
asigna
25
elementos
de
tipo
double.
el
valor
NULL
nulo
).
196
197
Un uso frecuente de fixed consiste en apuntar a objetos de tipos para los que
se puedan declarar punteros pero que estn almacenados en tablas, ya que
ello no se puede hacer directamente debido a que las tablas se almacenan en
memoria dinmica. Por ejemplo, copiar usando punteros una tabla de 100
elementos de tipo int en otra se hara as:
class CopiaInsegura
{
public unsafe static void Main()
{
int[] tOrigen = new int[100];
int[] tDestino = new int[100];
fixed (int * pOrigen=tOrigen, pDestino=tDestino)
{
for (int i=0; i<100; i++)
pOrigen[i] = pDestino[i];
}
Como puede deducirse del ejemplo, cuando se inicializa un puntero con una
tabla, la direccin almacenada en el puntero en la zona <declaraciones> del
fixed es la del primer elemento de la tabla (tambin podra haberse hecho
pOrigen = &tOrigen[0]), y luego es posible usar la aritmtica de punteros para
acceder al resto de elementos a partir de la direccin del primero ya que stos
se almacenan consecutivamente.
Al igual que tablas, tambin puede usarse fixed para recorrer cadenas. En este
caso lo que hay que hacer es inicializar un puntero de tipo char * con la
direccin del primer carcter de la cadena a la que se desee que apunte tal y
198
199
LISTAS GENERALES
CONCEPTO:
Es un tipo de dato abstracto con una secuencia simple de objetos llamados
Elementos, asociados a cada elemento de la lista hay un valor,
Caracterstica de las listas generales:
200
Operaciones Abstracta
1- La operacin head (list2) , que se va implantar a lista generales , se
implanta solamente a la lista que no este vaca. Al primer elemento le
damos el nombre de cabeza.
2- Luego el segundo elemento es el cuerpo cola, retorna siempre la
cabeza de la lista.
3- La cabeza de una lista siempre va hacer un elemento y la cola va hacer
una lista en general. Se puede hacer combinadas tanto el head y tail.
Ejemplo:
List2=(5, (3,2(14,9,3), ( ),4),2,(6,3,10) )
1- head (tail (list2))= 3
2- head ( tail (tail (tail (list2))))= 6
3- head (tail (tail ( head (tail (list2))))= (14,9,3).
201
1- firts (list)
2- info (element)
3- nodetype (elemt)
L1
L2
null
null
L1
null
202
Ejemplo 1:
1) L = Crlist (2, Crlist (9, 7), 6, 4);
2) L1 = tail (tail (L));
3)Sethead (L1, L);
4) L2 = head (tail (L));
5) L2 = tail (L2);
6) Sethead (L2, L);
1) Y 2)
L1
6
9
4
7
null
null
3)
L1
2
null
null
L2
9
null
4)
L1
2
L
9
L2
203
null
5)
L1
2
null
L
9
null
L2
6)
L1
2
null
L
9
null
L2
Ejemplo 2:
List1 = (4, (2, (a, b), (3,(z, (4, y, x), m ), k), 20), s, d)
4
null
null
204
null
4
3
List1
20
null
b
Head ( tail( tail ( list1))) = S
null
Ejemplo 3:
(a, 5, y, (b, 6), 23, w, (23,g), t)
head (tail (tail (list))) = y
tail (tail (tail ( list))) = (b, 6), 23, w, (23, g), t
205
null
LENGUAJES DE PROGRAMACIN.
En informtica, cualquier lenguaje artificial que puede utilizarse para definir una
secuencia de instrucciones para su procesamiento por un ordenador o
computadora. Es complicado definir qu es y qu no es un lenguaje de
programacin. Se asume generalmente que la traduccin de las instrucciones a
un cdigo que comprende la computadora debe ser completamente
sistemtica. Normalmente es la computadora la que realiza la traduccin.
Lenguajes de bajo nivel:
Vistos a muy bajo nivel, los microprocesadores procesan exclusivamente
seales electrnicas binarias. Dar una instruccin a un microprocesador
supone en realidad enviar series de unos y ceros espaciadas en el tiempo de
una forma determinada. Esta secuencia de seales se denomina cdigo
mquina. El cdigo representa normalmente datos y nmeros e instrucciones
para manipularlos. Un modo ms fcil de comprender el cdigo mquina es
dando a cada instruccin un mnemnico, como por ejemplo STORE, ADD o
JUMP. Esta abstraccin da como resultado el ensamblador, un lenguaje de muy
bajo nivel que es especfico de cada microprocesador.
Los lenguajes de bajo nivel permiten crear programas muy rpidos, pero que
son a menudo difciles de aprender. Ms importante es el hecho de que los
programas escritos en un bajo nivel sean altamente especficos de cada
206
Intrpretes y compiladores
La traduccin de una serie de instrucciones en lenguaje ensamblador (el cdigo
fuente) a un cdigo mquina (o cdigo objeto) no es un proceso muy
complicado y se realiza normalmente por un programa especial llamado
compilador. La traduccin de un cdigo fuente de alto nivel a un cdigo
mquina tambin se realiza con un compilador, en este caso ms complejo, o
207
En informtica, lenguaje
de
programacin de
ordenadores o
es
un
lenguaje
muy
utilizado
en
Inteligencia
Artificial.
calculusdesarrollado por
El hecho de que tanto los programas como los datos compartan una misma
estructura, las listas, hace que los propios programas se puedan modificar a si
mismo.
En LISP se pueden crear con gran facilidad lenguajes o estructura de dato
adaptados al tipo de problema del que se trate.
Las armas fundamentales para esta flexibilidad son los macro y la capacidad
para crear funciones en tiempo de ejecucin.
El LIPS proporciona un entorno de muy alto nivel (en trminos de
programacin), ya que le Common LISP proporciona un conjunto de mas de
700 funciones primitivas, lo que permite despreocuparse
de numerosos
EJERCICIOS PROPUESTOS
I- IMPLEMENTE LAS RUTINAS HEAD Y TAIL
1- list= (b, 8, z, (c, 6), 58, (h, 10 ) , 8 )
head (tail (tail (list)))
tail (tail (tail ( list)))
2 list = (s, 2, 3, (l, 2), 7)
Tail (head(tail(list)))
Head(head(tail(list))
II- GRAFIQUE
1- List(4,2,5,(p,2),( ))
2- List(2, 1,(j,5),(b, k),4)
210
211
RECOLECCION DE BASURA
Como hemos visto con anterioridad, existen lenguajes que ofrecen liberacin
implcita de memoria. Aquellos bloques de memoria que no sean accesibles
desde ninguna referencia (puntero) del programa reciben el
nombre de basura (garbage)
La memoria basura deber ser liberada por un lenguaje con liberacin implcita
de memoria heap. Este proceso de liberacin implcita de memoria recibe el
nombre de recoleccin de basura (garbage collection)
La recoleccin de basura es un proceso dinmico.
En el caso de un compilador, deber generar cdigo encargado de realizar esta
operacin.
Ejemplo
El siguiente programa Java posee bloques inaccesibles (basura) en el punto
de ejecucin indicado.
class Lista {
int valor;
Lista sig;
public Lista(int v,
Lista s) {
valor=v;
sig=s;
}
}
class Arbol {
int valor;
Arbol izq,der;
212
public Arbol(int v,
Arbol i,Arbol d) {
valor=v;
izq=i;
der=d;
}
}
public class Basura {
static Lista crearLista() {
Lista l=new Lista(1,null),
l2=new Lista(2,l);
l.sig=l2;
return l;
}s
tatic Arbol crearArbol() {
return new Arbol(3,
new Arbol(4,null,null),
new Arbol(5,null,null));
}p
ublic static void main(
String[] args) {
crearLista();
Arbol a=crearArbol();
}
}
12345
a
Variables
Heap
Punto de Ejecucin Basura
Veremos las siguientes tcnicas de recoleccin de
basura.
1-Marcar y borrar (mark and sweep)
213
2- Contadores de referencias
3- Recoleccin con copia (copying collection)
4- Recoleccin generacional
5- Recoleccin incremental y concurrente
Se ejecutan cuando se solicita un bloque de memoria y se detecta que sta
es escasa.
El grado de escasez es parametrizable en funcin del algoritmo
Si despus de llamar a la recoleccin de basura no se obtiene beneficio, se
debe pedir ms memoria al sistema operativo
Marcar y Borrar
Los bloques heap en memoria forman un grafo dirigido
Las variables locales y globales de un programa de tipo referencia (puntero)
constituyen la raz de dicho grafo.
El algoritmo de marcar y borrar realiza un recorrido en profundidad del grafo
de bloques. Parte de las races (variables)
Todo nodo del grafo que haya visitado lo marca como no basura
Una vez finalizado el recorrido del grafo, todos aquellos nodos que no hayan
sido marcados son basura
stos son incluidos en la lista de bloques libres
Ejemplo.
12345
a
Variables
Heap
Bloques Libres
214
Caractersticas de Algoritmo
1- El algoritmo de marcar y borrar posee una complejidad proporcional al
nmero total de bloques de la memoria heap
2- El nico modo que tiene para controlar la fragmentacin externa es mediante
la fusin de bloques.
3- No requiere elevadas cantidades de memoria heap para ser implementada.
Implementaciones
Contador de Referencias
La primera parte del algoritmo marcar y borrar detecta si los bloques heap son
accesibles desde las variables referencia. El algoritmo de contador de
referencias se basa mantener esta informacin a lo largo de la ejecucin del
programa. Todo bloque es aumentado con un campo contador de referencias
Cada vez que a una referencia se le asigne el valor de un
bloque, su contador ser incrementado.
Contador de referencias
Este algoritmos es sencillo de implementar pero posee dos graves
inconvenientes.
1. No elimina los bloques basura que tengan referencias mutuas directas o
indirectas (cclicas).
215
La
216
Se recorre el grafo partiendo de sus races. Cada vez que se visita un nodo
(accesible) se mueve a la zona destino. Las referencias (puntero) al bloque
medido son actualizadas a la nueva direccin.
Una vez finalizado el proceso el bloque origen posee toda su memoria libre
(basura) el bloque destino
a) tiene toda la memoria asignada,
b) no posee basura
c) no est fragmentada
En este momento el bloque destino para a ser origen y el origen destino
(cambio de roles).
Ejemplo Recoleccin con Copia
1234
5
a
Variables
Origen Destino
345
a
Variables Destino Origen
Recoleccin con copia
Caractersticas del Algoritmo
El algoritmo de recoleccin con copia posee una complejidad proporcional al
nmero de bloques accesibles (marcar y borrar era proporcional al nmero total
de bloques).
217
Recoleccin Generacional
En esta tcnica la memoria heap es dividida en generaciones (Gi)
En Go estn los bloques ms jvenes. Todo bloque que Gj posee es mayor
a los bloques Gj-1.
Un criterio emprico comnmente empleado es utilizar tamaos de
generaciones exponencialmente mayores que el tamao de la generacin
anterior.
Cuando se solicita la asignacin de memoria y no
existen bloques libres en G0,
Caso Especial
Existe un caso especial a tener en cuenta que provoca que bloques accesibles
sean identificados como basura.
Este caso se da cuando hay una referencia de otra generacin apuntando a un
bloque de G0.
218
219