Professional Documents
Culture Documents
La resolución práctica de un problema exige por una parte un algoritmo o método de resolución
y por otra un programa o codificación de aquel en un ordenador real.
A efectos prácticos o ingenieriles, nos deben preocupar los recursos físicos necesarios para que
un programa se ejecute.
Aunque puede haber muchos parámetros, los mas usuales son el tiempo de ejecución y la
cantidad de memoria (espacio).
Ocurre con frecuencia que ambos parametros están resolver en T segundos y/o con M bytes de
memoria?
En lo que sigue nos centramos casi siempre en el parametro tiempo de ejecución, si bien las
ideas desarrolladas son fácilmente aplicables a otro tipo de recursos.
Para cada problema determinaremos un medida N de su tamaño (por fijados por otras razones
y se plantea la pregunta inversa: ¿cual es el tamano del mayor problema que puedo número de datos)
e intentaremos hallar respuestas en función de dicho N.
Así, para un vector se suele utizar como N su longitud; para una matriz, el número de elementos
que la componen; para un grafo, puede ser el número de nodos (a veces es mas importante considerar
el número de arcos, dependiendo del tipo de problema a resolver), en un archivo se suele usar el
número de registros, etc.
Es imposible dar una regla general, pues cada problema tiene su propia lógica de costo.
Tiempo de Ejecución
Una medida que suele ser útil conocer es el tiempo de ejecución de un programa en función de
N, lo que denominaremos T(N).
Esta función se puede medir físicamente (ejecutando el programa, reloj en mano), o calcularse
sobre el código contando instrucciones a ejecutar y multiplicando por el tiempo requerido por cada
instrucción.
1
S1; for (int i= 0; i < N; i++) S2;
Requiere
T(N)= t1 + t2*N
Siendo t1 el tiempo que lleve ejecutar la serie “S1” de sentencias, y t2 el que lleve la serie “S2”.
Prácticamente todos los programas reales incluyen alguna sentencia condicional, haciendo que
las sentencias efectivamente ejecutadas dependan de los datos concretos que se le presenten.
Esto hace que más que un valor T (N) debamos hablar de un rango de valores
Los extremos son habitualmente conocidos como: “caso peor” y “caso mejor”.
Cualquier fórmula T(N) incluye referencias al parámetro N y a una serie de constantes “Ti” que
dependen de factores externos al algoritmo como pueden ser la calidad del código generado por el
compilador y la velocidad de ejecución de instrucciones del ordenador que lo ejecuta.
Dado que es fácil cambiar de compilador y que la potencia de los ordenadores crece a un ritmo
vertiginoso (en la actualidad, se duplica anualmente), intentaremos analizar los algoritmos con algun
nivel de independencia de estos factores; es decir, buscaremos estimaciones generales ampliamente
válidas.
Memoria Estática
Para que un objeto pueda ser almacenado en memoria estática su tamaño (número de bytes
necesarios para su almacenamiento) ha de ser conocido en tiempo de compilación, como consecuencia
de esta condición no podrán almacenarse en memoria estática:
2
A partir de una posición señalada por un puntero de referencia se aloja el objeto X, y se avanza
el puntero tantos bytes como sean necesarios para almacenar el objeto X.
La asignación de memoria puede hacerse en tiempo de compilación y los objetos están vigentes
desde que comienza la ejecución del programa hasta que termina.
En los lenguajes que permiten la existencia de subprogramas, y siempre que todos los objetos
de estos subprogramas puedan almacenarse estáticamente se aloja en la memoria estática un registro
de activación correspondiente a cada uno de los subprogramas.
Estos registros de activación contendrán las variables locales, parámetros formales y valor
devuelto por la función.
Dentro de cada registro de activación las variables locales se organizan secuencialmente. Existe
un solo registro de activación para cada procedimiento y por tanto no están permitidas las llamadas
recursivas. El proceso que se sigue cuando un procedimiento p llama a otro q es el siguiente:
Dado que las variables están permanentemente en memoria es fácil implementar la propiedad
de que conserven o no su contenido para cada nueva llamada
Memoria Dinámica
3
podemos saber en tiempo de compilación dónde nos dará huecos el sistema operativo (en la memoria
de nuestro PC).
Memoria Dinámica.
Sobre el tratamiento de memoria, GLib dispone de una serie de instrucciones que sustituyen a
las ya conocidas por todos malloc, free, etc. y, siguiendo con el modo de llamar a las funciones en GLib,
las funciones que sustituyen a las ya mencionadas son g_malloc y g_free.
Reserva de memoria.
La función g_malloc posibilita la reserva de una zona de memoria, con un número de bytes que
le pasemos como parámetro. Además, también existe una función similar llamada g_malloc0 que, no
sólo reserva una zona de memoria, sino que, además, llena esa zona de memoria con ceros, lo cual nos
puede beneficiar si se necesita un zona de memoria totalmente limpia.
Existe otro conjunto de funciones que nos permiten reservar memoria de una forma parecida a
cómo se hace en los lenguajes orientados a objetos.
Liberación de memoria.
Cuando se hace una reserva de memoria con g_malloc y, en un momento dado, el uso de esa
memoria no tiene sentido, es el momento de liberar esa memoria. Y el sustituto de free es g_free que,
básicamente, funciona igual que la anteriormente mencionada.
Realojamiento de memoria
Asignación dinámica
El proceso de compactación del punto anterior es una instancia particular del problema de
asignación de memoria dinámica, el cual es el cómo satisfacer una necesidad de tamaño n con una lista
de huecos libres. Existen muchas soluciones para el problema. El conjunto de huecos es analizado para
determinar cuál hueco es el más indicado para asignarse. Las estrategias más comunes para asignar
algún hueco de la tabla son:
4
Primer ajuste: Consiste en asignar el primer hueco con capacidad suficiente. La búsqueda puede
iniciar ya sea al inicio o al final del conjunto de huecos o en donde terminó la última búsqueda. La
búsqueda termina al encontrar un hueco lo suficientemente grande.
Mejor ajuste: Busca asignar el espacio más pequeño de los espacios con capacidad suficiente.
La búsqueda se debe de realizar en toda la tabla, a menos que la tabla esté ordenada por tamaño. Esta
estrategia produce el menor desperdicio de memoria posible.
Peor ajuste: Asigna el hueco más grande. Una vez más, se debe de buscar en toda la tabla de
huecos a menos que esté organizada por tamaño. Esta estrategia produce los huecos de sobra más
grandes, los cuales pudieran ser de más uso si llegan procesos de tamaño mediano que quepan en
ellos.
Se ha demostrado mediante simulacros que tanto el primer y el mejor ajuste son mejores que
el peor ajuste en cuanto a minimizar tanto el tiempo del almacenamiento. Ni el primer o el mejor
ajuste es claramente el mejor en términos de uso de espacio, pero por lo general el primer ajuste es
más rápido.
Definición:
Son aquellas que solo tiene 2 operaciones, Push(Inserción) y Pop(Eliminación) la cual solo se
puede efectuar por un extremo llamado Top. Sin Embargo se le pueden aplicar todas las operaciónes al
igual que a las listas.
1.- Recorrido
Definición:
Ya que las pilas son LIFO(Last in - First Out) el Recorrido se hace sacando el ultimo dato que se inserto
hasta que no encuentre ningún otro.
Detalle:
Apuntador toma el Top, después ve si la condición cumple para efectuar un Ciclo mientras Apuntador
sea diferente de Nulo, si cumple lo que hace es que despliega el contenido de la Pila(Pila[Apuntador]),
después Apuntador se le resta 1. Este proceso se repite hasta que Apuntador sea igual Nulo(Cuando
llega a este punto la Pila ya fue Recorrida).
Algoritmo:
Recorrido(Pila, Top)
Apuntador ←- Top
Repetir mientras Apuntador ≠ Nulo
Imprimir Pila[Apuntador]
Apuntador ←- Apuntador - 1
Fin del ciclo
Salir
Diagrama:
5
Corrida:
Push
Definición:
Push es simplemente el método por el cual va agregando un Dato nuevo a la Pila tomando en cuenta la
Capacidad Máxima (Max) de almacenar un dato.
Detalle:
Compara en un principio el Top con Max, si la condición no cumple es imposible insertar mas datos a la
Pila, de otra forma lo que hace es Incrementar el valor de Top, y copia el valor de Elemento en
Pila[Top]. De esta forma el dato ya esta insertado.
Algoritmo:
Diagrama:
6
Corrida:
Pop
Definición:
Pop es simplemente el método por el cual va sacando el ultimo Dato de la Pila, basándose únicamente
en el Top.
Detalle:
Compara para determinar si la pila esta vacio, de otra forma lo que hace es Imprimir el valor de
Pila[Top] (Que es el dato que esta apunto de Eliminar) y enseguida a Top le resta 1, de esta forma el
dato ya no existe.
Algoritmo:
Pop(Pila, Top)
Si Top ≠ Nulo
Imprimir Pila[Top]
Top ←- Top - 1
Si no:
Imprimir “Pila Vacía”
Salir
Diagrama:
7
Corrida:
Búsqueda
Definición:
Este método usa el recorrido para encontrar Elemento y desplegar un mensaje si la búsqueda es
exitosa.
Detalle:
El algoritmo compara para determinar si la Pila tiene algún dato, si no simplemente desplegara Lista
Vacía y saldrá. De otra manera hará un Recorrido y comparara con cada uno de los Datos de la Pila
hasta encontrar el dato que desea buscar. Si lo encuentra desplegara “El Dato fue encontrado” de otra
manera “El Dato no se encontró”.
Algoritmo:
8
Imprimir “El Dato no se encontró”
Si no:
Imprimir “Pila Vacía”
Salir
Diagrama:
Corrida:
Eliminacion
Definición:
Este método busca un Dato dentro de la pila y lo elimina.
Detalle:
El algoritmo compara para determinar si la Pila tiene algún dato, si no simplemente desplegara Pila
Vacía y saldrá. De otra manera hará un Recorrido y comparara con cada uno de los Datos de la Pila
hasta encontrar el dato que desea eliminar, mientras hace esto copia cada uno de los datos a un
arreglo Temp para cuando encuentre el Dato regresar esos valores a la Pila. Si lo encuentra desplegara
“Eliminado el Dato” y le restara 1 a Top, de otra manera “El Dato no encontrado”.
Algoritmo:
9
Apuntador1 ←- Top
Repetir mientras Apuntador1 ≠ Nulo
Si Pila[Apuntador1] = Elemento
Imprimir “Eliminando el Dato…”
Repetir mientras Apuntador2 ≠ Nulo
Pila[Apuntador1]=Temp[Apuntador2]
Fin del ciclo
Top ←- Top - 1 y Salir
Si No:
Temp[Apuntador2+ ←- Pila[Apuntador1]
Apuntador1 ←- Apuntador1 - 1
Apuntador2 ←- Apuntador2 + 1
Fin del ciclo
Imprimir “Dato no encontrado”
Si no:
Imprimir “Pila Vacía”
Salir
Diagrama:
Corrida:
10
Programa click here
PROGRAMACION PILAS ESTRUCTURAS DE DATOS
**#include <stdio.h>**
#include <conio.h>
#include <string.h>
#include <iomanip.h>
#include <iostream.h>
class Alumno
private:
int Pila[10],Top,Max;
char Pila1[10][10];
public:
Alumno()
int i,j;
Max=9;
Top=-1;
for(i=1;i<9;i++)
Pila[i]=0;
strcpy(Pila1[i],Nulo);
11
}
if(Top!=Max)
Top++;
strcpy(Pila1[Top],Elem);
else
cout<<"Pila Llena"<<endl;
if(Top!=Max)
Top++;
Pila[Top]=Elem;
else
cout<<"Pila Llena"<<endl;
if(Top!=Max)
12
{
Top++;
Pila[Top]=Elem;
else
cout<<"Pila Llena"<<endl;
if(Top!=Max)
Top++;
Pila[Top]=Elem;
else
cout<<"Pila Llena"<<endl;
void Pop(void)
if(Top!=-1)
Top--;
13
}
else
void Recorrido(void)
if(Top!=-1)
for(int i=Top;i!=-1;i--)
cout<<Pila[i]<<endl;
else
cout<<"Pila Vacia...";
for(int i=Top;i!=-1;i--)
if((strcmp(Elem,Pila1[i]))==0)
return;
cout<<"Dato no encontrado..."<<endl;
14
for(int i=Top;i!=-1;i--)
if(Elem==Pila[i])
return;
cout<<"Dato no encontrado..."<<endl;
for(int i=Top;i!=-1;i--)
if(Elem==Pila[i])
return;
cout<<"Dato no encontrado..."<<endl;
for(int i=Top;i!=-1;i--)
if(Elem==Pila[i])
15
cout<<"Dato "<<Pila[i]<<" encontrado..."<<endl;
return;
cout<<"Dato no encontrado..."<<endl;
char Temp[10][10];
int i=0,j=Top;
if(Top==-1)
return;
while(j!=-1)
if((strcmp(Elem,Pila1[j]))==0)
cout<<"Dato Eliminado...";
for(i--;i!=-1;j++,i--)
strcpy(Pila1[j],Temp[i]);
Top--;
return;
16
else
strcpy(Temp[i],Pila1[j]);
i++;
j--;
return;
int Temp[10],i=0,j=Top;
if(Top==-1)
return;
while(j!=-1)
if(Elem==Pila[j])
cout<<"Dato Eliminado...";
17
for(i--;i!=-1;j++,i--)
Pila[j]=Temp[i];
Top--;
return;
else
Temp[i]=Pila[j];
i++;
j--;
return;
int Temp[10],i=0,j=Top;
if(Top==-1)
return;
while(j!=-1)
18
{
if(Elem==Pila[j])
cout<<"Dato Eliminado...";
for(i--;i!=-1;j++,i--)
Pila[j]=Temp[i];
Top--;
return;
else
Temp[i]=Pila[j];
i++;
j--;
return;
int Temp[10],i=0,j=Top;
if(Top==-1)
19
{
return;
while(j!=-1)
if(Elem==Pila[j])
cout<<"Dato Eliminado...";
for(i--;i!=-1;j++,i--)
Pila[j]=Temp[i];
Top--;
return;
else
Temp[i]=Pila[j];
i++;
j--;
return;
20
}tec;
main()
int res,op=0;
while(op!=6)
clrscr();
gotoxy(1,1);
cin>>op;
gotoxy(1,10);
switch (op)
case 1:
tec.Recorrido();
break;
case 2:
cin>>res;
tec.Busqueda(res);
break;
case 3:
21
cout<<"Que Numero quieres Insertar?"<<endl;
cin>>res;
tec.Push(res);
break;
case 4:
tec.Pop();
break;
case 5:
cin>>res;
tec.Borrar(res);
break;
case 6:
cout<<"Salida...";
break;
default:
cout<<"Opcion Erronea"<<endl;
break;
getch();
22
Son aquellas que solo tiene 2 operaciones, Push(Inserción) y Pop(Eliminación). Push solo se puede
efectuar por un extremo llamado Frente y Pop por el extremo Llamado Final. Sin Embargo se le pueden
aplicar todas las operación al igual que a las listas.
Recorrido
Definición:
Ya que las colas son FIFO(First in - First Out) el Recorrido se hace sacando el primer dato que se inserto
hasta que llegue al extremo llamado Final.
Detalle:
En un principio se compara para saber si tiene algún dato en la Cola, si no es así desplegara “Cola
Vacía…”. De otra forma compara si Frente es mayor o igual a Final, de esta forma simplemente hace un
Recorrido lineal como los anteriores. De otra forma usar Max como bandera para saber cuando
empezar a contar de 0 a Final (Ya que sabemos que el Frente después del nodo Final).
Algoritmo:
Si Frente ≠ Nulo
Imprimir Cola[Apuntador]
Apuntador <-- 0
Imprimir Cola[Apuntador]
Si no:
23
Imprimir "Cola Vacía"
Salir
Diagrama:
Corrida:
Push
Definición:
Push es simplemente el método por el cual va agregando un Dato nuevo a la Cola tomando en cuenta
el Tamaño Máximo de Capacidad (Max), el Frente y el Final de la Cola.
Detalle:
Primer nos aseguramos que la Cola no este Llena, para que de esta manera sea capaz de insertar un
Elemento nuevo. Si no desplegara Cola Llena. Después compara para determinar las posiciones de
Frente y Final y de esta manera poder moverlo con libertad. Ya que determina los valores de Frente y
Final, nos Indica que Cola[Final] tomara el valor de Elemento.
Algoritmo:
24
Si Frente = 0 y Final =9, o si Frente = (Final + 1)
Si Frente = Nulo
Frente <-- 0
Final <-- 0
Final <-- 0
Si no:
Cola[Final] = Elemento
Salir
Diagrama:
Corrida:
25
Pop
Definición:
Pop es simplemente el método por el cual va sacando el primer Dato de la Cola (esto se comprueba ya
que las Colas son FIFO), para esto toma en cuenta el Frente.
Detalle:
Compara para determinar si la cola esta vacía, de otra forma lo que hace es Imprimir “Eliminando el
Dato…”. Después se hacen una series de comparaciones para determinar la nueva posición de Frente,
de esa forma el Dato que existía en Frente es Eliminado.
Algoritmo:
Si Frente ≠ Nulo
Si Frente = Final
Frente = Nulo
Final = Nulo
Frente = 0
Si no:
Si no:
Salir
26
Diagrama:
Corrida:
Búsqueda
Definición:
Este método usa el recorrido para encontrar Elemento y desplegar un mensaje si la búsqueda es
exitosa.
Detalle:
El algoritmo usa básicamente la misma estructura del Recorrido, la única diferencia es que compara
cada uno de los Datos con Elemento, de esta forma se da cuenta si este Dato existe en la Cola.
Algoritmo:
Si Frente ≠ Nulo
27
Si Elemento = Cola[Apuntador]
Apuntador <-- 0
Si Elemento = Cola[Apuntador]
Si no:
Salir
Diagrama:
28
Corrida:
Eliminacion
Definición:
Este método busca un Dato dentro de la cola y lo elimina.
Detalle:
Este Método es la mezcla de todos en uno, Recorrido, Búsqueda, Pop y Push. Debido que a busca el
Dato haciendo un Recorrido, y en el proceso copia todos los Datos que no son en un Arreglo Temp,
para después meterlos a la Cola original, esto lo hace hasta encontrar el dato deseado que
posteriormente lo Elimina.
Diagrama:
29
Corrida:
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <iomanip.h>
#include <iostream.h>
class Alumno
private:
30
int Cola[10],Frente,Final,Max;
char Cola1[10][10];
public:
Alumno()
int i,j;
Frente=-1;
Final=-1;
Max=9;
for(i=1;i<9;i++)
Cola[i]=0;
strcpy(Cola1[i],Nulo);
if((Frente==0&&Final==9)||(Frente==(Final+1)))
cout<<"Cola Llena"<<endl;
return;
if(Frente==-1)
31
{
Frente=0;
Final=0;
else if(Final==Max)
Final=0;
else
Final++;
strcpy(Cola1[Final],Elem);
if((Frente==0&&Final==9)||(Frente==(Final+1)))
cout<<"Cola Llena"<<endl;
return;
if(Frente==-1)
Frente=0;
Final=0;
else if(Final==Max)
32
Final=0;
else
Final++;
Cola[Final]=Elem;
if((Frente==0&&Final==9)||(Frente==(Final+1)))
cout<<"Cola Llena"<<endl;
return;
if(Frente==-1)
Frente=0;
Final=0;
else if(Final==Max)
Final=0;
else
Final++;
Cola[Final]=Elem;
33
{
if((Frente==0&&Final==9)||(Frente==(Final+1)))
cout<<"Cola Llena"<<endl;
return;
if(Frente==-1)
Frente=0;
Final=0;
else if(Final==Max)
Final=0;
else
Final++;
Cola[Final]=Elem;
void Pop(void)
if(Frente!=-1)
if(Frente==Final)
34
{
Frente=-1;
Final=-1;
else if(Frente==Max)
Frente=0;
else
Frente++;
else
void Recorrido(void)
int i;
if(Frente!=-1)
if(Frente<=Final)
for(i=Frente;i<=Final;i++)
cout<<Cola[i]<<endl;
else if(Frente>Final)
for(i=Frente;i!=Final;i++)
if(i>Max)
35
i=0;
cout<<Cola[i]<<endl;
else
cout<<"Cola Vacia...";
int i;
if(Frente!=-1)
if(Frente<=Final)
for(i=Frente;i<=Final;i++)
if((strcmp(Elem,Cola1[i]))==0)
return;
else if(Frente>Final)
for(i=Frente;i!=Final;i++)
if(i>Max)
36
i=0;
if((strcmp(Elem,Cola1[i]))==0)
return;
else
cout<<"Dato no encontrado...";
int i;
if(Frente!=-1)
if(Frente<=Final)
for(i=Frente;i<=Final;i++)
if(Elem==Cola[i])
return;
else if(Frente>Final)
37
for(i=Frente;i!=Final;i++)
if(i>Max)
i=0;
if(Elem==Cola[i])
return;
else
cout<<"Dato no encontrado...";
int i;
if(Frente!=-1)
if(Frente<=Final)
for(i=Frente;i<=Final;i++)
if(Elem==Cola[i])
38
cout<<"Dato "<<Cola[i]<<" encontrado..."<<endl;
return;
else if(Frente>Final)
for(i=Frente;i!=Final;i++)
if(i>Max)
i=0;
if(Elem==Cola[i])
return;
else
cout<<"Dato no encontrado...";
int i;
if(Frente!=-1)
if(Frente<=Final)
39
for(i=Frente;i<=Final;i++)
if(Elem==Cola[i])
return;
else if(Frente>Final)
for(i=Frente;i!=Final;i++)
if(i>Max)
i=0;
if(Elem==Cola[i])
return;
else
cout<<"Dato no encontrado...";
40
char Temp[10][10];
int i,j;
if(Frente!=-1)
if(Frente<=Final)
for(j=0,i=Frente;i<=Final;i++,j++)
if((strcmp(Elem,Cola1[i]))==0)
if(Frente==Final)
Frente=-1;
Final=-1;
return;
else if(Frente==Max)
Frente=0;
else
Frente++;
for(j--,i=Frente;j!=-1;i++,j--)
strcpy(Cola1[i],Temp[j]);
return;
41
strcpy(Temp[j],Cola1[i]);
else if(Frente>Final)
for(j=0,i=Frente;i!=Final;i++,j++)
if(i>Max)
i=0;
if((strcmp(Elem,Cola1[i]))==0)
if(Frente==Max)
Frente=0;
else
Frente++;
for(j--,i=Frente;j!=-1;i++,j--)
if(i>Max)
i=0;
strcpy(Cola1[i],Temp[j]);
return;
strcpy(Temp[j],Cola1[i]);
42
}
cout<<"Dato no Encontrado...";
else
int Temp[10],i,j;
if(Frente!=-1)
if(Frente<=Final)
for(j=0,i=Frente;i<=Final;i++,j++)
if(Elem==Cola[i])
if(Frente==Final)
Frente=-1;
Final=-1;
return;
else if(Frente==Max)
43
Frente=0;
else
Frente++;
for(j--,i=Frente;j!=-1;i++,j--)
Cola[i]=Temp[j];
return;
Temp[j]=Cola[i];
else if(Frente>Final)
for(j=0,i=Frente;i!=Final;i++,j++)
if(i>Max)
i=0;
if(Elem==Cola[i])
if(Frente==Max)
Frente=0;
else
Frente++;
for(j--,i=Frente;j!=-1;i++,j--)
44
if(i>Max)
i=0;
Cola[i]=Temp[j];
return;
Temp[j]=Cola[i];
cout<<"Dato no Encontrado...";
else
int Temp[10],i,j;
if(Frente!=-1)
if(Frente<=Final)
for(j=0,i=Frente;i<=Final;i++,j++)
if(Elem==Cola[i])
45
if(Frente==Final)
Frente=-1;
Final=-1;
return;
else if(Frente==Max)
Frente=0;
else
Frente++;
for(j--,i=Frente;j!=-1;i++,j--)
Cola[i]=Temp[j];
return;
Temp[j]=Cola[i];
else if(Frente>Final)
for(j=0,i=Frente;i!=Final;i++,j++)
if(i>Max)
i=0;
if(Elem==Cola[i])
46
cout<<"Eliminado el Dato "<<Cola[i]<<endl;
if(Frente==Max)
Frente=0;
else
Frente++;
for(j--,i=Frente;j!=-1;i++,j--)
if(i>Max)
i=0;
Cola[i]=Temp[j];
return;
Temp[j]=Cola[i];
cout<<"Dato no Encontrado...";
else
int Temp[10],i,j;
if(Frente!=-1)
47
{
if(Frente<=Final)
for(j=0,i=Frente;i<=Final;i++,j++)
if(Elem==Cola[i])
if(Frente==Final)
Frente=-1;
Final=-1;
return;
else if(Frente==Max)
Frente=0;
else
Frente++;
for(j--,i=Frente;j!=-1;i++,j--)
Cola[i]=Temp[j];
return;
Temp[j]=Cola[i];
48
else if(Frente>Final)
for(j=0,i=Frente;i!=Final;i++,j++)
if(i>Max)
i=0;
if(Elem==Cola[i])
if(Frente==Max)
Frente=0;
else
Frente++;
for(j--,i=Frente;j!=-1;i++,j--)
if(i>Max)
i=0;
Cola[i]=Temp[j];
return;
Temp[j]=Cola[i];
cout<<"Dato no Encontrado...";
49
else
}tec;
main()
int res,op=0;
while(op!=6)
clrscr();
gotoxy(1,1);
cin>>op;
gotoxy(1,10);
switch (op)
case 1:
tec.Recorrido();
break;
case 2:
cin>>res;
50
tec.Busqueda(res);
break;
case 3:
cin>>res;
tec.Push(res);
break;
case 4:
tec.Pop();
break;
case 5:
cin>>res;
tec.Borrar(res);
break;
case 6:
cout<<"Salida...";
break;
default:
cout<<"Opcion Erronea"<<endl;
break;
getch();
51
}
Diagrama:
Programa:
#include <conio.h>
#include <iostream.h>
52
void Recorrido(char Info[8][2],int Indice[8],int Inicio,int Disp);
void main()
{" "},{"T"}};
int Indice[8]={5,7,6,1,-999,3,-999,4};
int Inicio=0,Disp=2;
Recorrido(Info,Indice,Inicio,Disp);
getch();
int Apuntador=Inicio;
while(Apuntador!=-999)
cout<<Info[Apuntador];
Apuntador=Indice[Apuntador];
Corrida:
53
Búsqueda
Definición:
La Búsqueda su objetivo es encontrar un dato en el arreglo Info, si lo encuentra lo desplegara en la
pantalla, si no lo encuentra no desplegara nada ya que el dato no se encuentra en el arreglo Info.
Explicación:
Apuntador toma el valor de Inicio, después ve si la condición cumple para efectuar un Ciclo mientras
Apuntador sea diferente de 0, si cumple lo que hace a continuación es la comparación de Elemento (El
dato que vamos a buscar) con Info[Apuntador], cuando lo encuentre lo despliega y sale del método. Si
no, regresa el valor de Apuntador para así saber que no se encontró el dato.
Algoritmo:
Diagrama:
Programa:
54
#include <conio.h>
#include <iostream.h>
int Busqueda(int Info[8],int Indice[8],int Inicio,int Disp,int Elemento);
void main()
{
int Info[8]={12,10,0,9,5,3,0,20};
int Indice[8]={5,7,6,1,-999,3,-999,4};
int Inicio=0,Disp=2,Elemento,Res;
cout<<"Que Numero deseas buscar?";
cin>>Elemento;
Res=Busqueda(Info,Indice,Inicio,Disp,Elemento);
if(Res==-999)
cout<<"Dato No Encontrado...";
getch();
}
int Busqueda(int Info[8],int Indice[8],int Inicio,int Disp,int Elemento)
{
int Apuntador=Inicio;
while(Apuntador!=-999)
{
if(Elemento==Info[Apuntador])
{
cout<<"Numero "<<Info[Apuntador]<<" encontrado...";
return Apuntador;
}
Apuntador=Indice[Apuntador];
}
return Apuntador;
}
CORRIDA:
55
Inserción al Principio
Definición:
La Inserción al Principio básicamente busca si existe algún lugar disponible en el arreglo Info y lo agrega
como primer Nodo si es que es posible.
Explicación:
Hace una comparación para ver si es posible insertar otro Elemento al arreglo Info, para esto checa si
Disp es Diferente de Nulo. Si no cumple con la condición se desplegar “Sobre Carga” ya que no se
puede insertar un Nuevo Elemento. Si es cierto Apuntador toma el valor de Inicio, Disp cambia a
Indice[Disp] ya que el primer Disp tomara el valor del Nuevo Elemento, después de esto solo copia la
información de Elemento al arreglo Info en la posición que guarda Apuntador, Indice[Apuntador] toma
el valor de Inicio y finalmente Inicio toma el valor de Apuntador.
Algoritmo:
Diagrama:
56
Programa:
#include <conio.h>
#include <iostream.h>
void Recorrido(int Info[8],int Indice[8],int Inicio,int Disp);
void InsPr(int Info[8],int Indice[8],int Inicio,int Disp,int Elemento);
void main()
{
int Info[8]={12,10,0,9,5,3,0,20};
int Indice[8]={5,7,6,1,-999,3,-999,4};
int Inicio=0,Disp=2,Elemento,Res;
cout<<"Lista Original\n";
Recorrido(Info,Indice,Inicio,Disp);
cout<<"Que Numero deseas Insertar?";
cin>>Elemento;
InsPr(Info,Indice,Inicio,Disp,Elemento);
getch();
}
{
int Apuntador=Inicio;
while(Apuntador!=-999)
{
cout<<Info[Apuntador]<<endl;
Apuntador=Indice[Apuntador];
}
}
57
void InsPr(int Info[8],int Indice[8],int Inicio,int Disp,int Elemento)
{
if(Disp!=-999)
{
int Apuntador=Disp;
Disp=Indice[Disp];
Info[Apuntador]=Elemento;
Indice[Apuntador]=Inicio;
Inicio=Apuntador;
Recorrido(Info,Indice,Inicio,Disp);
}
else
cout<<"Overflow...";
}
CORRIDA:
58
compara la Nueva Posición (Npos) que le mandamos con Nill si cumple la condición el dato es
insertado en la primer posición, de otra forma se posicionara en la posición que guarde Npos.
Algoritmo:
Inserción Ordenada
Definición:
La Inserción Ordenada busca la posición en donde será Insertado el Elemento y la posición anterior
donde será Insertado, después de encontrar la posición en la que será Insertado el Elemento nos
regresa ese valor y lo mandamos al método de la Inserción después de un Nodo.
Explicación:
En esta ocasión usaremos dos variables para determinar la posición deseada, comparamos si Inicio es
igual a Nill ó si Elemento es menor al dato que se encuentra en Info[Inicio], si alguna de las dos cumple
regresamos Nill, de esta manera Indicamos que el Elemento será el primero de todo el Arreglo Info, si
no es así Temp tomara el valor de Inicio y Temp2 de la posición que le sigue a Inicio. Hace un ciclo
hasta encontrar la posición en donde se insertara el Nuevo Elemento y va moviéndose de posición con
las variables Temp y Temp2 para así determinar que posición debe de regresar.
Algoritmo:
Diagrama:
59
Programa:
#include <conio.h>
#include <iostream.h>
void InsNd(int Info[8],int Indice[8],int Inicio,int Disp, int Elemento, int Npos);
void main()
int Info[8]={12,10,0,9,5,3,0,20};
int Indice[8]={5,7,6,1,-999,3,-999,4};
int Inicio=0,Disp=2,Elemento,Res;
cout<<"Lista Original\n";
Recorrido(Info,Indice,Inicio,Disp);
cin>>Elemento;
60
Res=InsOrd(Info,Indice,Inicio,Elemento);
InsNd(Info,Indice,Inicio,Disp,Elemento,Res);
getch();
int Apuntador=Inicio;
while(Apuntador!=-999)
cout<<Info[Apuntador]<<endl;
Apuntador=Indice[Apuntador];
void InsNd(int Info[8],int Indice[8],int Inicio,int Disp, int Elemento, int Npos)
if(Disp!=-999)
int Apuntador=Disp;
Disp=Indice[Disp];
Info[Apuntador]=Elemento;
if(Npos==-999)
Indice[Apuntador]=Inicio;
Inicio=Apuntador;
61
}
else
Indice[Apuntador]=Indice[Npos];
Indice[Npos]=Apuntador;
Recorrido(Info,Indice,Inicio,Disp);
else
cout<<"Overflow...";
int Temp=-999,Temp2;
if(Inicio==Temp||Elemento<Info[Inicio])
return Temp;
Temp=Inicio;
Temp2=Indice[Inicio];
while(Temp2!=-999)
if(Elemento<Info[Temp2])
return Temp;
Temp=Temp2;
62
Temp2=Indice[Temp2];
return Temp;
CORRIDA:
63
Si no:
Temp2 ←- Temp
Temp ←- Indice[Temp]
Imprimir “Dato no encontrado… Imposible Eliminar” y Retornar
Diagrama:
Programa:
#include <conio.h>
#include <iostream.h>
void main()
int Info[8]={12,10,0,9,5,3,0,20};
int Indice[8]={5,7,6,1,-999,3,-999,4};
int Inicio=0,Disp=2,Elemento,Res;
cout<<"Lista Original\n";
Recorrido(Info,Indice,Inicio,Disp);
64
cin>>Elemento;
EliBusq(Info,Indice,Inicio,Disp,Elemento);
getch();
int Apuntador=Inicio;
while(Apuntador!=-999)
cout<<Info[Apuntador]<<endl;
Apuntador=Indice[Apuntador];
int Temp=Inicio,Temp2;
if(Temp==-999)
return;
while(Temp!=-999)
65
if(Elemento==Info[Temp])
if(Temp==Inicio)
Inicio=Indice[Inicio];
else
Indice[Temp2]=Indice[Temp];
Indice[Temp]=Disp;
Disp=Temp;
Recorrido(Info,Indice,Inicio,Disp);
return;
else
Temp2=Temp;
Temp=Indice[Temp];
return;
CORRIDA:
66
Prgrama clik here
PROGRAMACION LISTAS ENLAZADAS ESTRUCTURA DE DATOS
#include <stdio.h>
#include <conio.h>
#include <iomanip.h>
#include <iostream.h>
class Alumno
private:
char Nombre[10][30];
int N_control[10],Edad[10],Indice1[10],Indice2[10],Inicio,Fin,Disp;
public:
//Constructor
Alumno()
int i,j;
Inicio=0;
Fin=0;
Disp=1;
67
Indice1[Inicio]=-999;
Indice2[Fin]=-999;
for(i=1,j=2;i<9;i++,j++)
Indice1[i]=j;
Indice1[9]=-999;
//Funcion de Recorrido
int i=0,Temp;
if(op==1)
Temp=Indice1[Inicio];
if(Temp!=-999)
while(Temp!=-999)
if(i==(int(Edad[Inicio]/2)))
N_control[Inicio]=N_control[i];
strcpy(Nombre[Inicio],Nombre[i]);
68
cout<<setw(9)<<N_control[Temp]<<setw(22)<<Nombre[Temp]<<setw(9)<<Edad[Temp]<<endl;
Temp=Indice1[Temp];
i++;
else
cout<<"Lista Vacia...";
if(op==2)
Temp=Fin;
if(Edad[Inicio]!=0)
while(Temp!=-999&&i<Edad[Inicio])
if(i==(int(Edad[Inicio]/2)))
N_control[Inicio]=N_control[i];
strcpy(Nombre[Inicio],Nombre[i]);
cout<<setw(9)<<N_control[Temp]<<setw(22)<<Nombre[Temp]<<setw(9)<<Edad[Temp]<<endl;
Temp=Indice2[Temp];
i++;
69
}
else
cout<<"Lista Vacia...";
if(Elem<N_control[Inicio])
int Temp=Indice1[Inicio];
while(Temp!=-999)
if(Elem==N_control[Temp])
gotoxy(1,10);
cout<<setw(9)<<N_control[Temp]<<setw(22)<<Nombre[Temp]<<setw(9)<<Edad[Temp]<<endl;
return Temp;
else
Temp=Indice1[Temp];
70
}
else
int Temp=Fin;
while(Temp!=-999)
if(Elem==N_control[Temp])
gotoxy(1,10);
cout<<setw(9)<<N_control[Temp]<<setw(22)<<Nombre[Temp]<<setw(9)<<Edad[Temp]<<endl;
return Temp;
else
Temp=Indice2[Temp];
return -999;
if((strcmp(Elem,Nombre[Inicio]))<0)
71
{
int Temp=Indice1[Inicio];
while(Temp!=-999)
if((strcmp(Elem,Nombre[Temp]))==0)
gotoxy(1,10);
cout<<setw(9)<<N_control[Temp]<<setw(22)<<Nombre[Temp]<<setw(9)<<Edad[Temp]<<endl;
return Temp;
else
Temp=Indice1[Temp];
else
int Temp=Fin;
while(Temp!=-999)
if((strcmp(Elem,Nombre[Temp]))==0)
gotoxy(1,10);
72
cout<<"Numero de Control"<<setw(19)<<"Nombre del Alumno"<<setw(5)<<"Edad"<<endl;
cout<<setw(9)<<N_control[Temp]<<setw(22)<<Nombre[Temp]<<setw(9)<<Edad[Temp]<<endl;
return Temp;
else
Temp=Indice2[Temp];
return -999;
int Temp=Indice1[Inicio],Temp2;
if(Temp==-999||E_nc<N_control[Temp])
return -999;
Temp2=Indice1[Indice1[Inicio]];
while(Temp2!=-999)
if(E_nc<N_control[Temp2])
return Temp;
Temp=Temp2;
Temp2=Indice1[Temp2];
73
return Temp;
int Temp=Indice1[Inicio],Temp2;
if(Temp==-999)
return -999;
if((strcmp(E_nom,Nombre[Temp]))<0)
return Temp;
Temp2=Indice1[Indice1[Inicio]];
while(Temp2!=-999)
if((strcmp(E_nom,Nombre[Temp2]))<0)
return Temp;
Temp=Temp2;
Temp2=Indice1[Temp2];
return Temp;
74
if(Disp!=-999)
Edad[Inicio]++;
int Temp=Disp;
Disp=Indice1[Disp];
strcpy(Nombre[Temp],E_nom);
N_control[Temp]=E_nc;
Edad[Temp]=E_edad;
if(Npos==-999)
Indice1[Temp]=Indice1[Inicio];
if(Indice2[Fin]==-999)
Indice2[Temp]=Fin;
Fin=Temp;
else
Indice2[Temp]=Indice1[Inicio];
Indice2[Indice1[Inicio]]=Temp;
Indice1[Inicio]=Temp;
else
75
{
Indice1[Temp]=Indice1[Npos];
if(Fin==Npos)
Indice2[Temp]=Fin;
Fin=Temp;
else
Indice2[Temp]=Npos;
Indice2[Indice1[Npos]]=Temp;
Indice1[Npos]=Temp;
else
cout<<"Overflow..."<<endl;
int Temp2,Temp=Indice1[Inicio];
if(Temp==-999)
76
{
return;
while(Temp!=-999)
if(Elem==N_control[Temp])
Edad[Inicio]--;
if(Temp==Indice1[Inicio])
Indice1[Inicio]=Indice1[Indice1[Inicio]];
Indice2[Indice1[Inicio]]=Inicio;
else if(Temp==Fin)
Indice1[Temp2]=Indice1[Temp];
Fin=Indice2[Fin];
else
Indice1[Temp2]=Indice1[Temp];
Indice2[Indice1[Temp2]]=Temp2;
77
Indice1[Temp]=Disp;
Disp=Temp;
return;
else
Temp2=Temp;
Temp=Indice1[Temp];
return;
int Temp2,Temp=Indice1[Inicio];
if(Temp==Inicio)
return;
while(Temp!=Inicio)
78
{
if((strcmp(Elem,Nombre[Temp]))==0)
Edad[Inicio]--;
if(Temp==Indice1[Inicio])
Indice1[Inicio]=Indice1[Indice1[Inicio]];
Indice2[Indice1[Inicio]]=Inicio;
else if(Temp==Fin)
Indice1[Temp2]=Indice1[Temp];
Fin=Indice2[Fin];
else
Indice1[Temp2]=Indice1[Temp];
Indice2[Indice1[Temp2]]=Temp2;
Indice1[Temp]=Disp;
Disp=Temp;
return;
else
79
{
Temp2=Temp;
Temp=Indice1[Temp];
return;
}tec;
main()
int op=0,res;
char inom[30];
int in_c,iedad;
while(op!=6)
clrscr();
gotoxy(1,1);
cin>>op;
gotoxy(1,10);
80
switch (op)
case 1:
tec.Recorrido(1);
break;
case 2:
tec.Recorrido(2);
break;
case 3:
cin>>res;
res=tec.Busqueda(res);
if(res==-999)
cout<<"Dato no encontrado";
break;
case 4:
gets(inom);
cin>>in_c;
cout<<"Cual es su Edad?"<<endl;
cin>>iedad;
res=tec.Enca(in_c);
tec.InsLug(inom,in_c,iedad,res);
81
break;
case 5:
cin>>res;
tec.Borrar(res);
break;
case 6:
cout<<"Salida...";
break;
default:
cout<<"Opcion Erronea"<<endl;
break;
getch();
}
Unidad 3: LISTAS CIRCULARES
Recorrido
Definición:
Recorrido simplemente despliega los datos almacenados en el arreglo Info, con ayuda de un segundo
arreglo llamado Indice el cual guarda el orden en el que encuentran enlazados cada uno de los datos.
Detalle:
Apuntador toma el valor de Indice[Inicio], después ve si la condición cumple para efectuar un Ciclo
mientras Apuntador sea diferente de Inicio, si cumple lo que hace es que despliega la Info[Apuntador],
después Apuntador toma el valor de Indice[Apuntador] (El cual nos indica el siguiente nodo que sigue
en la lista) y hace esto hasta que Apuntador sea igual a Inicio (Cuando llega a este punto a llegado al fin
de la Lista).
Algoritmo:
82
Repetir mientras Apuntador ≠ Inicio
Imprimir Info[Apuntador]
Apuntador → Indice*Apuntador+
Fin del ciclo
Salir
Diagrama:
Programa:
#include <conio.h>
#include <iostream.h>
void main()
{"G"},{"T"}};
int Indice[8]={6,7,-999,1,0,3,5,4};
int Inicio=0,Disp=2;
Recorrido(Info,Indice,Inicio,Disp);
83
getch();
int Apuntador=Indice[Inicio];
while(Apuntador!=Inicio)
cout<<Info[Apuntador];
Apuntador=Indice[Apuntador];
Búsqueda
Definición:
La Búsqueda su objetivo es encontrar un dato en el arreglo Info, si lo encuentra lo desplegara en la
pantalla, si no lo encuentra no desplegara nada ya que el dato no se encuentra en el arreglo Info.
Detalle:
Apuntador toma el valor de Inicio, después ve si la condición cumple para efectuar un Ciclo mientras
Apuntador sea diferente de 0, si cumple lo que hace a continuación es la comparación de Elemento (El
dato que vamos a buscar) con Info[Apuntador], cuando lo encuentre lo despliega y sale del método. Si
no, regresa el valor de Apuntador para así saber que no se encontró el dato.
Algoritmo:
84
Apuntador → Indice*Apuntador+
Fin del ciclo
Regresar Apuntador
Diagrama:
Programa:
#include <conio.h>
#include <iostream.h>
void main()
int Info[8]={0,10,0,9,5,3,0,20};
int Indice[8]={5,7,6,1,0,3,-999,4};
int Inicio=0,Disp=2,Elemento,Res;
cin>>Elemento;
Res=Busqueda(Info,Indice,Inicio,Disp,Elemento);
if(Res==-999)
85
cout<<"Dato No Encontrado...";
getch();
int Apuntador=Indice[Inicio];
while(Apuntador!=Inicio)
if(Elemento==Info[Apuntador])
return Apuntador;
Apuntador=Indice[Apuntador];
return Apuntador;
86
Inserción al Principio
Definición:
La Inserción al Principio básicamente busca si existe algún lugar disponible en el arreglo Info y lo agrega
como primer Nodo si es que es posible.
Detalle:
Hace una comparación para ver si es posible insertar otro Elemento al arreglo Info, para esto checa si
Disp es Diferente de Nulo. Si no cumple con la condición se desplegar “Sobre Carga” ya que no se
puede insertar un Nuevo Elemento. Si es cierto Apuntador toma el valor de Inicio, Disp cambia a
Indice[Disp] ya que el primer Disp tomara el valor del Nuevo Elemento, después de esto solo copia la
información de Elemento al arreglo Info en la posición que guarda Apuntador, Indice[Apuntador] toma
el valor de Indice[Inicio] y finalmente Indice[Inicio] toma el valor de Apuntador.
Algoritmo:
Diagrama:
87
Programa:
#include <conio.h>
#include <iostream.h>
void main()
int Info[8]={0,10,0,9,5,3,0,20};
int Indice[8]={5,7,6,1,0,3,-999,4};
int Inicio=0,Disp=2,Elemento,Res;
cout<<"Lista Original\n";
Recorrido(Info,Indice,Inicio,Disp);
cin>>Elemento;
InsPr(Info,Indice,Inicio,Disp,Elemento);
88
getch();
int Apuntador=Indice[Inicio];
while(Apuntador!=Inicio)
cout<<Info[Apuntador]<<endl;
Apuntador=Indice[Apuntador];
if(Disp!=-999)
int Apuntador=Disp;
Disp=Indice[Disp];
Info[Apuntador]=Elemento;
Indice[Apuntador]=Indice[Inicio];
Indice[Inicio]=Apuntador;
Recorrido(Info,Indice,Inicio,Disp);
else
cout<<"Overflow...";
89
}
90
Indice*Npos+ → Apuntador
Si no:
Imprimir “Sobre Carga”
Salir
Inserción Ordenada
Definición:
La Inserción Ordenada busca la posición en donde será Insertado el Elemento y la posición anterior
donde será Insertado, después de encontrar la posición en la que será Insertado el Elemento nos
regresa ese valor y lo mandamos al método de la Inserción después de un Nodo.
Detalle:
En esta ocasión usaremos dos variables para determinar la posición deseada, comparamos si
Indice[Inicio] es igual a Inicio ó si Elemento es menor al dato que se encuentra en Info[Inicio], si alguna
de las dos cumple regresamos Nill, de esta manera Indicamos que el Elemento será el primero de todo
el Arreglo Info, si no es así Temp tomara el valor de Inicio y Temp2 de la posición que le sigue a Inicio.
Hace un ciclo hasta encontrar la posición en donde se insertara el Nuevo Elemento y va moviéndose de
posición con las variables Temp y Temp2 para así determinar que posición debe de regresar.
Algoritmo:
Diagrama:
91
Programa:
#include <stdio.h>
#include <conio.h>
#include <iostream.h>
void main()
char Elemento[10];
int Indice[8]={5,7,6,1,0,3,-999,4};
int Inicio=0,Disp=2,Res;
cout<<"Lista Original\n";
Recorrido(Info,Indice,Inicio,Disp);
92
gets(Elemento);
InsOrd(Info,Indice,Inicio,Disp,Elemento);
getch();
int Apuntador=Indice[Inicio];
while(Apuntador!=Inicio)
cout<<Info[Apuntador]<<endl;
Apuntador=Indice[Apuntador];
if(Disp!=-999)
strcpy(Info[Disp],Elemento);
Indice[Disp]=Indice[Inicio];
Indice[Inicio]=Disp;
Disp=Indice[Disp];
Recorrido(Info,Indice,Inicio,Disp);
93
}
if(Inicio==Indice[Inicio]||(strcmp(Elemento,Info[Indice[Inicio]]))==0)
InsPr(Info,Indice,Inicio,Disp,Elemento);
return;
int Temp=Indice[Inicio],Temp2=Indice[Temp];
while(Temp2!=Inicio)
if((strcmp(Elemento,Info[Temp2]))<0)
break;
Temp=Temp2;
Temp2=Indice[Temp2];
strcpy(Info[Disp],Elemento);
Indice[Disp]=Indice[Temp];
Indice[Temp]=Disp;
Disp=Indice[Disp];
Recorrido(Info,Indice,Inicio,Disp);
94
La Eliminación simplemente cambia los nodos para que el dato que se desea eliminar sea el primer
disponible, de esta forma ya no estará en el Arreglo de Info.
Detalle:
Lo primero que hace es ver si existe algún dato en la lista para eliminar, si Indice[Inicio] es igual a Inicio
entonces solo desplegara “Imposible Eliminar”. De otra formas cambiar de Posición en Posición hasta
encontrar el Elemento que sea desea Eliminar con ayudar de dos variables que guardan la Posición
actual y la anterior en donde se encuentre el dato. Ya que lo encuentra cambia ese dato como la
primera posición Disponible y lo apunta al siguiente nodo disponible. Si no encuentra el dato
simplemente desplegara “Dato no encontrado”
Algoritmo:
Diagrama:
Programa:
95
#include <conio.h>
#include <iostream.h>
void main()
int Info[8]={0,10,0,9,5,3,0,20};
int Indice[8]={5,7,6,1,0,3,-999,4};
int Inicio=0,Disp=2,Elemento,Res;
cout<<"Lista Original\n";
Recorrido(Info,Indice,Inicio,Disp);
cin>>Elemento;
EliBusq(Info,Indice,Inicio,Disp,Elemento);
getch();
int Apuntador=Indice[Inicio];
while(Apuntador!=Inicio)
cout<<Info[Apuntador]<<endl;
Apuntador=Indice[Apuntador];
96
}
int Temp=Indice[Inicio],Temp2;
if(Temp==Inicio)
return;
while(Temp!=Inicio)
if(Elemento==Info[Temp])
if(Temp==Inicio)
Inicio=Indice[Inicio];
else
Indice[Temp2]=Indice[Temp];
Indice[Temp]=Disp;
Disp=Temp;
Recorrido(Info,Indice,Inicio,Disp);
return;
else
97
{
Temp2=Temp;
Temp=Indice[Temp];
return;
Proyecto Final:
Unidad 3: Listas Dobles
Recorrido
Definición:
Recorrido simplemente despliega los datos almacenados en el arreglo Info, con ayuda de un segundo
arreglo llamado Indice1 o Indice2 el cual guarda el orden en el que encuentran enlazados cada uno de
los datos. Estos datos se pueden recorrer de Arriba hacia Abajo o de Abajo hacia Arriba.
Explicación:
Dependiendo de la forma en la que se desea recorrer el Arreglo, la variable Apuntador tomara el valor
de Indice1[Inicio], o de Fin. Después recorrerá el Arreglo mientras la condición no se rompa (Dicha
condición será diferente dependiendo el caso).
Diagrama:
98
Búsqueda
Definición:
La Búsqueda su objetivo es encontrar un dato en el arreglo Info, si lo encuentra lo desplegara en la
pantalla, si no lo encuentra no desplegara nada ya que el dato no se encuentra en el arreglo Info. Esta
búsqueda es mas efectiva ya que compara el dato de la mitad y dependiendo el resultado, empezara la
búsqueda por el Final o Inicio.
Explicación:
Primeramente usaremos un contador y la cabecera, esto nos permitirá determinar cual es dato de la
mitad. Para esto se utiliza el Recorrido el cual al encontrar el Dato de la mitad lo copia ese dato a la
cabecera con la cual se comparara para determinar por donde empezar (Inicio y Fin).
Diagrama:
Inserción Ordenada
Definición:
99
La Inserción Ordenada busca la posición en donde será Insertado el Elemento y la posición anterior
donde será Insertado, después de encontrar la posición en la que será Insertado el Elemento nos
regresa ese valor y lo mandamos al método de la Inserción después de un Nodo.
Explicación:
Esta Inserción ordenada es similar a las anteriores aunque en este caso consta de mas comparación y
movimientos de variables, esto se debe a que tenemos 2 arreglos que nos indican los movimientos y al
insertar un dato ambos arreglos deben direccionar nuevamente.
Diagrama:
100
Corrida:
#include <stdio.h>
#include <conio.h>
#include <iomanip.h>
101
#include <iostream.h>
class Alumno
private:
char Nombre[10][30];
int N_control[10],Edad[10],Indice1[10],Indice2[10],Inicio,Fin,Disp;
public:
//Constructor
Alumno()
int i,j;
Inicio=0;
Fin=0;
Disp=1;
Indice1[Inicio]=-999;
Indice2[Fin]=-999;
for(i=1,j=2;i<9;i++,j++)
Indice1[i]=j;
Indice1[9]=-999;
//Funcion de Recorrido
int i=0,Temp;
102
if(op==1)
Temp=Indice1[Inicio];
if(Temp!=-999)
while(Temp!=-999)
if(i==(int(Edad[Inicio]/2)))
N_control[Inicio]=N_control[i];
strcpy(Nombre[Inicio],Nombre[i]);
cout<<setw(9)<<N_control[Temp]<<setw(22)<<Nombre[Temp]<<setw(9)<<Edad[Temp]<<endl;
Temp=Indice1[Temp];
i++;
else
cout<<"Lista Vacia...";
if(op==2)
103
Temp=Fin;
if(Edad[Inicio]!=0)
while(Temp!=-999&&i<Edad[Inicio])
if(i==(int(Edad[Inicio]/2)))
N_control[Inicio]=N_control[i];
strcpy(Nombre[Inicio],Nombre[i]);
cout<<setw(9)<<N_control[Temp]<<setw(22)<<Nombre[Temp]<<setw(9)<<Edad[Temp]<<endl;
Temp=Indice2[Temp];
i++;
else
cout<<"Lista Vacia...";
if(Elem<N_control[Inicio])
104
{
int Temp=Indice1[Inicio];
while(Temp!=-999)
if(Elem==N_control[Temp])
gotoxy(1,10);
cout<<setw(9)<<N_control[Temp]<<setw(22)<<Nombre[Temp]<<setw(9)<<Edad[Temp]<<endl;
return Temp;
else
Temp=Indice1[Temp];
else
int Temp=Fin;
while(Temp!=-999)
if(Elem==N_control[Temp])
gotoxy(1,10);
105
cout<<"Numero de Control"<<setw(19)<<"Nombre del Alumno"<<setw(5)<<"Edad"<<endl;
cout<<setw(9)<<N_control[Temp]<<setw(22)<<Nombre[Temp]<<setw(9)<<Edad[Temp]<<endl;
return Temp;
else
Temp=Indice2[Temp];
return -999;
if((strcmp(Elem,Nombre[Inicio]))<0)
int Temp=Indice1[Inicio];
while(Temp!=-999)
if((strcmp(Elem,Nombre[Temp]))==0)
gotoxy(1,10);
cout<<setw(9)<<N_control[Temp]<<setw(22)<<Nombre[Temp]<<setw(9)<<Edad[Temp]<<endl;
return Temp;
106
}
else
Temp=Indice1[Temp];
else
int Temp=Fin;
while(Temp!=-999)
if((strcmp(Elem,Nombre[Temp]))==0)
gotoxy(1,10);
cout<<setw(9)<<N_control[Temp]<<setw(22)<<Nombre[Temp]<<setw(9)<<Edad[Temp]<<endl;
return Temp;
else
Temp=Indice2[Temp];
return -999;
107
//Funcion Sobrecargada de Orden para Numeros Enteros
int Temp=Indice1[Inicio],Temp2;
if(Temp==-999||E_nc<N_control[Temp])
return -999;
Temp2=Indice1[Indice1[Inicio]];
while(Temp2!=-999)
if(E_nc<N_control[Temp2])
return Temp;
Temp=Temp2;
Temp2=Indice1[Temp2];
return Temp;
int Temp=Indice1[Inicio],Temp2;
if(Temp==-999)
return -999;
if((strcmp(E_nom,Nombre[Temp]))<0)
return Temp;
108
Temp2=Indice1[Indice1[Inicio]];
while(Temp2!=-999)
if((strcmp(E_nom,Nombre[Temp2]))<0)
return Temp;
Temp=Temp2;
Temp2=Indice1[Temp2];
return Temp;
if(Disp!=-999)
Edad[Inicio]++;
int Temp=Disp;
Disp=Indice1[Disp];
strcpy(Nombre[Temp],E_nom);
N_control[Temp]=E_nc;
Edad[Temp]=E_edad;
if(Npos==-999)
109
Indice1[Temp]=Indice1[Inicio];
if(Indice2[Fin]==-999)
Indice2[Temp]=Fin;
Fin=Temp;
else
Indice2[Temp]=Indice1[Inicio];
Indice2[Indice1[Inicio]]=Temp;
Indice1[Inicio]=Temp;
else
Indice1[Temp]=Indice1[Npos];
if(Fin==Npos)
Indice2[Temp]=Fin;
Fin=Temp;
else
Indice2[Temp]=Npos;
110
Indice2[Indice1[Npos]]=Temp;
Indice1[Npos]=Temp;
else
cout<<"Overflow..."<<endl;
int Temp2,Temp=Indice1[Inicio];
if(Temp==-999)
return;
while(Temp!=-999)
if(Elem==N_control[Temp])
Edad[Inicio]--;
if(Temp==Indice1[Inicio])
111
{
Indice1[Inicio]=Indice1[Indice1[Inicio]];
Indice2[Indice1[Inicio]]=Inicio;
else if(Temp==Fin)
Indice1[Temp2]=Indice1[Temp];
Fin=Indice2[Fin];
else
Indice1[Temp2]=Indice1[Temp];
Indice2[Indice1[Temp2]]=Temp2;
Indice1[Temp]=Disp;
Disp=Temp;
return;
else
Temp2=Temp;
Temp=Indice1[Temp];
112
cout<<"Dato no encontrado... Imposible Eliminar";
return;
int Temp2,Temp=Indice1[Inicio];
if(Temp==Inicio)
return;
while(Temp!=Inicio)
if((strcmp(Elem,Nombre[Temp]))==0)
Edad[Inicio]--;
if(Temp==Indice1[Inicio])
Indice1[Inicio]=Indice1[Indice1[Inicio]];
Indice2[Indice1[Inicio]]=Inicio;
else if(Temp==Fin)
113
{
Indice1[Temp2]=Indice1[Temp];
Fin=Indice2[Fin];
else
Indice1[Temp2]=Indice1[Temp];
Indice2[Indice1[Temp2]]=Temp2;
Indice1[Temp]=Disp;
Disp=Temp;
return;
else
Temp2=Temp;
Temp=Indice1[Temp];
return;
}tec;
main()
114
{
int op=0,res;
char inom[30];
int in_c,iedad;
while(op!=6)
clrscr();
gotoxy(1,1);
cin>>op;
gotoxy(1,10);
switch (op)
case 1:
tec.Recorrido(1);
break;
case 2:
tec.Recorrido(2);
break;
case 3:
115
cin>>res;
res=tec.Busqueda(res);
if(res==-999)
cout<<"Dato no encontrado";
break;
case 4:
gets(inom);
cin>>in_c;
cout<<"Cual es su Edad?"<<endl;
cin>>iedad;
res=tec.Enca(in_c);
tec.InsLug(inom,in_c,iedad,res);
break;
case 5:
cin>>res;
tec.Borrar(res);
break;
case 6:
cout<<"Salida...";
break;
default:
116
cout<<"Opcion Erronea"<<endl;
break;
getch();
}
ESTRUCTURA DE DATOS
Recursividad
Definición:
Capacidad que tiene los métodos de invocarse a si mismos, esta es una potente herramienta en la
informática.
Con esta herramienta muchos algoritmos pueden simplificarse significativamente.
Programa:
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <iomanip.h>
#include <iostream.h>
class Matematicas
public:
if(B<11)
Tablas(T,B+1);
117
}
return;
long Factorial(long n)
if(n<=1)
return 1;
else
void Formula(int X)
if(X<11)
cout<<"f("<<X<<") = "<<((X*X*X)+(2*X)+(3))<<endl;
Formula(X+1);
return;
if(N==1)
118
cout<<Inicio<<" --> "<<Fin<<endl;
return;
Torres(N-1,Inicio,Fin,Aux);
Torres(N-1,Aux,Inicio,Fin);
return;
}tec;
main()
int t,b,op=0;
while(op!=5)
clrscr();
gotoxy(1,1);
cin>>op;
clrscr();
switch(op)
case 1:
119
cout<<"Que Tabla de Multiplicar deseas Imprimir?"<<endl;
cin>>t;
cin>>b;
tec.Tablas(t,b);
break;
case 2:
cin>>t;
cout<<t<<"! = "<<tec.Factorial(t)<<endl;
break;
case 3:
cin>>t;
tec.Formula(t);
break;
case 4:
cin>>t;
tec.Torres(t,'A','B','C');
break;
case 5:
120
cout<<"Salida...";
break;
default:
cout<<"Opcion Erronea...";
break;
getch();
}
Unidad 5: Arboles Binarios
Definición:
Un Árbol Binario es un conjunto de finito de Elementos, de nombre Nodos de forma que:
El Árbol Binario es Vació si no tiene ningún elemento en el.
El Árbol Binario contiene un Nodo Raíz y los dos que parten de él, llamados Nodo Izquierdo y Nodo
Derecho.
Los Árboles tiene 3 Recorridos Diferentes los cuales son:
Pre-Orden
In-Orden
Post-Orden
Pre-Orden
Definición:
El Recorrido “Pre-Orden” lo recorre de la siguiente manera, viaje a través del Árbol Binario
desplegando el Contenido en la Raíz, después viaje a través del Nodo Izquierdo y después a través del
Nodo Derecho.
Detalle:
Temp toma el Valor de la Raíz y compara si el Árbol tiene algún Elemento, de otra manera Desplegara
“Árbol Vació…” y terminara el método. Si el Árbol tiene elementos dentro de él, lo recorrerá y viajara a
través de los Arreglos Izq y Der para determinar que valor meter en la Pila y en Temp para de esta
manera imprimir el siguiente Elemento correspondiente.
Algoritmo:
121
Si Der*Temp+ ≠ Nulo
Top → Top + 1
Pila*Top+ → Der*Temp+
Si Izq*Temp+ ≠ Nulo
Temp → Izq*Temp+
Si no:
Temp → Pila*Top+;
Top → Top - 1
Fin del ciclo
Salir
Diagrama:
Corrida:
In-Orden
Definición:
El Recorrido “In-Orden” lo recorre de la siguiente manera, viaje a través del Árbol Binario desplegando
el Contenido en el Nodo Izquierdo después la Raíz y finalmente viaja a través del Nodo Derecho.
122
Detalle:
Temp toma el Valor de la Raíz y compara si el Árbol tiene algún Elemento, de otra manera Desplegara
“Árbol Vació…” y terminara el método. Si el Árbol tiene elementos dentro de él, lo recorrerá y viajara a
través de los Arreglos Izq y Der para determinar que valor meter en la Pila y en Temp para de esta
manera imprimir el siguiente Elemento correspondiente.
Algoritmo:
Diagrama:
123
Corrida:
In-Orden
Definición:
El Recorrido “In-Orden” lo recorre de la siguiente manera, viaje a través del Árbol Binario desplegando
el Contenido en el Nodo Izquierdo después el Nodo Derecho y finalmente viaja a través de la Raiz.
Detalle:
Temp toma el Valor de la Raíz y compara si el Árbol tiene algún Elemento, de otra manera Desplegara
“Árbol Vació…” y terminara el método. Si el Árbol tiene elementos dentro de él, lo recorrerá y viajara a
través de los Arreglos Izq y Der para determinar que valor meter en la Pila y en Temp para de esta
manera imprimir el siguiente Elemento correspondiente.
Algoritmo:
124
Imprimir “Arbol Vacio…” y Salir
Etiqueta:
Mientras Temp ≠ Nulo
Top → Top + 1
Pila*Top+ → Temp
Si Der*Temp+ ≠ Nulo
Top → Top + 1
Pila*Top+ → - (Der[Temp])
Temp → Izq*Temp+
Temp → Pila*Top+
Top → Top - 1
Fin del ciclo
Mientras Temp ≥ 0
Imprimir Arbol[Temp]
Si Arbol[Temp] = Info[Raiz]
Salir
Temp → Pila*Top+
Top → Top - 1
Fin del ciclo
Si Temp < 0
Temp = -(Temp)
Ir a Etiqueta
Salir
Diagrama:
Corrida:
125
Búsqueda
Definición:
La Búsqueda es Similar a todas los Métodos anteriores de Búsqueda, simplemente efectúa un recorrido
comparando el Elemento que deseas encontrar contra cada uno de los Elementos en los Arreglos.
Detalle:
El Algoritmo de Búsqueda compara el Elemento a buscar con cada uno de los datos de nuestro Árbol,
compara si el Elemento con el Nodo Raíz, si no se encuentra en la Raíz… compara Elemento contra la
Raíz para empezar a viajar por el Árbol respectivamente, usa un método similar al anterior hasta
encontrar el Elemento. De otra forma la búsqueda es fallida.
Algoritmo:
126
Regresar Pos y Pad
Salir
Si Elem < Arbol[Temp]
Temp2 → Temp
Temp → Izq*Temp+
Si no:
Temp2 → Temp
Temp → Der*Temp+
Fin del ciclo
Imprimir “Elemento no Encontrado…”
Pos → Nulo
Pad → Temp2
Regresar Pos y Pad
Salir
Diagrama:
Corrida:
127
Programa click here:
PROGRAMACION ARBOL BINARIO ESTRUCTURAS DE DATOS
#include <conio.h>
#include <iostream.h>
class Arbol
private:
int Top,Pila[10];
int Info[10],Izq[10],Der[10],Raiz,Disp;
public:
Arbol()
int in[10]={0,0,0,0,0,0,0,0,0,0};
for(int i=0;i<10;i++)
Info[i]=0;
Izq[i]=i+1;
Der[i]=-999;
Pila[i]=0;
Top=0;
Disp=0;
Raiz=-999;
Izq[9]=-999;
128
}
void PreOrd(void)
int Temp=Raiz;
Top=0;
Pila[0]=-999;
if(Raiz==-999)
cout<<"Arbol Vacio..."<<endl;
return;
while(Temp!=-999)
cout<<Info[Temp]<<endl;
if(Der[Temp]!=-999)
Top++;
Pila[Top]=Der[Temp];
if(Izq[Temp]!=-999)
Temp=Izq[Temp];
else
129
{
Temp=Pila[Top];
Top--;
void InOrd(void)
int Temp=Raiz,
Top=0;
Pila[0]=-999;
if(Raiz==-999)
cout<<"Arbol Vacio..."<<endl;
return;
Back:
while(Temp!=-999)
Top++;
Pila[Top]=Temp;
Temp=Izq[Temp];
130
Temp=Pila[Top];
Top--;
while(Temp!=-999)
cout<<Info[Temp]<<endl;
if(Der[Temp]!=-999)
Temp=Der[Temp];
goto Back;
Temp=Pila[Top];
Top--;
void PostOrd(void)
int Temp=Raiz;
Top=0;
Pila[0]=-999;
if(Raiz==-999)
cout<<"Arbol Vacio..."<<endl;
return;
131
Back1:
while(Temp!=-999)
Top++;
Pila[Top]=Temp;
if(Der[Temp]!=-999)
Top++;
Pila[Top]=-Der[Temp];
Temp=Izq[Temp];
Temp=Pila[Top];
Top--;
while(Temp>=0)
cout<<Info[Temp]<<endl;
if(Info[Temp]==Info[Raiz])
return;
Temp=Pila[Top];
Top--;
if(Temp<0)
132
{
Temp=-Temp;
goto Back1;
int Temp,Temp2;
if(Raiz==-999)
PosPad[0]=-999;
PosPad[1]=-999;
cout<<"Arbol Vacio..."<<endl;
return;
if(Elem==Info[Raiz])
PosPad[0]=Raiz;
PosPad[1]=-999;
cout<<"Elemento Encontrado..."<<endl;
return;
if(Elem<Info[Raiz])
133
Temp=Izq[Raiz];
Temp2=Raiz;
else
Temp=Der[Raiz];
Temp2=Raiz;
while(Temp!=-999)
if(Elem==Info[Temp])
cout<<"Elemento Encontrado..."<<endl;
PosPad[0]=Temp;
PosPad[1]=Temp2;
return;
if(Elem<Info[Temp])
Temp2=Temp;
Temp=Izq[Temp];
else
134
{
Temp2=Temp;
Temp=Der[Temp];
PosPad[0]=-999;
PosPad[1]=Temp2;
cout<<"Elemento no Encontrado..."<<endl;
int PosPad[2],Temp;
if(Disp!=-999)
Busqueda(PosPad,Elem);
clrscr();
if(PosPad[0]!=-999)
return;
Temp=Disp;
Disp=Izq[Disp];
Info[Temp]=Elem;
135
PosPad[0]=Temp;
Izq[Temp]=-999;
Der[Temp]=-999;
if(PosPad[1]==-999)
Raiz=Temp;
else if(Elem<Info[PosPad[1]])
Izq[PosPad[1]]=Temp;
else
Der[PosPad[1]]=Temp;
cout<<"Elemento Insertado..."<<endl;
return;
int PosPad[2];
Busqueda(PosPad,Elem);
clrscr();
if(PosPad[0]==-999)
return;
136
}
if(Der[PosPad[0]]!=-999&&Izq[PosPad[0]]!=-999)
CasoB(PosPad);
else
CasoA(PosPad);
Izq[PosPad[0]]=Disp;
Disp=PosPad[0];
int Temp;
if(Izq[PosPad[0]]==-999&&Der[PosPad[0]]==-999)
Temp=-999;
else if(Izq[PosPad[0]]!=-999)
Temp=Izq[PosPad[0]];
else
Temp=Der[PosPad[0]];
if(PosPad[1]!=-999)
if(PosPad[0]==Izq[PosPad[1]])
Izq[PosPad[1]]=Temp;
else
Der[PosPad[1]]=Temp;
137
else
Raiz=Temp;
int PosPad2[2],Temp=Der[PosPad[0]],Temp2=PosPad[0];
while(Izq[Temp]!=-999)
Temp2=Temp;
Temp=Izq[Temp];
PosPad2[0]=Temp;
PosPad2[1]=Temp2;
CasoA(PosPad2);
if(PosPad[1]!=-999)
if(PosPad[0]==Izq[PosPad[1]])
Izq[PosPad[1]]=PosPad2[0];
else
Der[PosPad[1]]=PosPad2[0];
else
Raiz=PosPad2[0];
138
Izq[PosPad2[0]]=Izq[PosPad[0]];
Der[PosPad2[0]]=Der[PosPad[0]];
}tec;
main()
int PosPad[2],res,op=0;
while(op!=7)
clrscr();
gotoxy(1,1);
cin>>op;
gotoxy(1,10);
switch (op)
case 1:
tec.PreOrd();
break;
case 2:
tec.InOrd();
break;
139
case 3:
tec.PostOrd();
break;
case 4:
cin>>res;
tec.Busqueda(PosPad,res);
break;
case 5:
cin>>res;
tec.InsOrd(res);
break;
case 6:
cin>>res;
tec.Eliminar(res);
break;
case 7:
cout<<"Salida...";
break;
default:
cout<<"Opcion Erronea"<<endl;
break;
140
}
getch();
}
Unidad 5: Arboles en Monton
Definición:
El Arbol en Monton consisten en el ordenamiento de un conjunto de Elemento en un solo arreglo.
Trabajaremos sobre la siguientes Operaciones en este Tema:
1. Inserción
2. Búsqueda
3. Eliminación
4. Recorrido (Ordenado)
Inserción
Definición:
El Concepto de Inserción ya es familiar para nosotros y sabemos que para realizar el mismo no resulta
complejo el procedimiento.
Pero en los Árboles en Montón es uno de los Métodos más largos para efectuarlo.
Detalle:
Básicamente lo que hace estos Algoritmos es la Inserción Ordenada. Primero comparan si es posible
insertar algún Elemento al Arreglo, si es posible hacerlo Ingresa el Elemento a la Ultima posición.
Después básicamente acomoda el Arreglo con el Método de la Burbuja llamando a otra serie de
Métodos.
Algoritmos:
Insertar(Arbol, N, Elemento)
Si N<25
Arbol[N] -> a
N -> N + 1
OrdMon(Arbol, N)
Salir
//Fin de la condición//
Salir
OrdMon(Arbol, Total)
141
ConstMon(Arbol, Total)
Burbuja(0, Total)
RecMon(Total, 0)
Salir
ConstMon(Arbol, Total)
v -> (Total/2) - 1
Mientras v ≥ 0
RecMon(Arbol, Total, v)
v -> v - 1
Salir
----
RecMon(Arbol, Total, v)
w -> 2*v+1
w++
//Fin de la condición//
Fin de la condición
142
Si Arbol*v+ ≥ Arbol[w]
Salir
//Fin de la condición//
Burbuja(Arbol, v, w)
v -> w
w -> 2*v+1
Salir
----
Burbuja(Arbol, v, w)
t -> Arbol[v]
Arbol[w] -> t
Salir
Diagrama:
143
Corrida:
Búsqueda
Definición:
El Concepto de Búsqueda es sencillo, simplemente es un método de búsqueda lineal. Existen 3 posible
resultados:
1. Que el Árbol este Vació y no se puede realizar la búsqueda.
2. Que el Elemento sea encuentre en el Árbol
3. Que el Elemento no este dentro del Árbol
Detalle:
Se manda al Método Búsqueda el Dato que se desea buscar, se acomoda el Árbol en Orden en caso
que no estuviera Ordenado y después compara con cada uno de los datos.
Algoritmos:
**Busqueda(Arbol, N, Elemento)**
Si N ≠ 0
OrdMon(Arbol, N)
i ->
Si Arbol[i] = Elemento
Salir
//Fin de la condición//
i -> i + 1
144
Salir
//Fin de la condición//
Salir
Diagrama:
Corrida:
Eliminación
Definición:
El Concepto de Eliminación consiste en la búsqueda de un Elemento y sacarlo del Arreglo. Existen 3
casos Diferentes;
1. Que el Árbol este Vació y no se puede realizar la eliminación
2. Que el Elemento sea encuentre en el Árbol y sea eliminado
3. Que el Elemento no este dentro del Árbol por lo tanto no se elimina
Detalle:
145
Vemos si el Árbol tiene Elementos insertados en el, de otra forma será imposible realizar la Eliminación
ya que esta Vació. Después si el Árbol tiene Elementos lo ordenamos y hacemos un búsqueda lineal
para encontrar el dato. Después usamos el método de la Burbuja para dejar el Elemento Eliminado
hasta el final y le Restamos a N un Elemento.
Algoritmo:
Eliminar(Arbol, N, Elemento)
Si N ≠ 0
OrdMon(Arbol, N)
i ->
Mientras I < N
Si Arbol[i] = Elemento
j -> i + 1
Mientras j < N
t -> Arbol[i]
Arbol[j] -> t
j -> j + 1
N -> n - 1
Salir
//Fin de la condición//
i -> i + 1
Fin de la condición
146
Salir
Diagrama:
Corrida:
Recorrido (Ordenado)
Definición:
El Recorrido simplemente ira desplegando cada uno de los Elementos del Árbol. Solo existen 2 posibles
casos:
1. Que el Árbol este Vació y no se pueda recorrer
2. El Árbol tenga Elementos para desplegar
Detalle:
Comparamos para comprobar que el Árbol tiene Elementos dentro de el, de ser así Desplegamos cada
uno de ellos. De otra manera Desplegamos Árbol Vació.
Algoritmo:
Recorrido(Arbol, N)
Si N ≠ 0
147
i ->
Mientras i < N
Imprimir Arbol[i]
i -> i + 1
Salir
//Fin de la condición//
Salir
Corrida:
#include <conio.h>
#include <iostream.h>
class Arbol_Monton
private:
int Arbol[25];
int N;
148
public:
Arbol_Monton()
for(int i=0;i<25;i++)
Arbol[i]=0;
N=0;
void Insertar(int a)
if(N<25)
Arbol[N]=a;
N++;
OrdMon(N);
return;
cout<<"Arbol Lleno..."<<endl;
void Eliminar(int a)
int t;
if(N!=0)
149
OrdMon(N);
for(int i=0;i<N;i++)
if(Arbol[i]==a)
for(int j=i+1;j<N;j++)
t=Arbol[i];
Arbol[i]=Arbol[j];
Arbol[j]=t;
N--;
cout<<"Elemento Eliminado..."<<endl;
return;
void Busqueda(int a)
if(N!=0)
OrdMon(N);
150
for(int i=0;i<N;i++)
if(Arbol[i]==a)
cout<<"Elemento Encontrado..."<<endl;
return;
return;
cout<<"Arbol Vacio..."<<endl;
void OrdMon(int n)
ConstMon(n);
while(n>1)
n--;
Burbuja(0,n);
RecMon(n,0);
void ConstMon(int n)
151
for(int v=n/2-1;v>=0;v--)
RecMon(n,v);
int w=2*v+1;
while(w<n)
if(w+1<n)
if (Arbol[w+1]>Arbol[w])
w++;
if(Arbol[v]>=Arbol[w])
return;
Burbuja(v,w);
v=w;
w=2*v+1;
int t=Arbol[i];
Arbol[i]=Arbol[j];
Arbol[j]=t;
152
void Recorrido()
if(N!=0)
for(int i=0;i<N;i++)
cout<<Arbol[i]<<endl;
return;
cout<<"Arbol Vacio..."<<endl;
}tec;
main()
int res,op=0;
while(op!=5)
clrscr();
gotoxy(1,1);
cin>>op;
gotoxy(1,10);
switch (op)
153
{
case 1:
tec.Recorrido();
break;
case 2:
cin>>res;
tec.Busqueda(res);
break;
case 3:
cin>>res;
tec.Insertar(res);
break;
case 4:
cin>>res;
tec.Eliminar(res);
break;
case 5:
cout<<"Salida...";
break;
default:
cout<<"Opcion Erronea"<<endl;
154
break;
getch();
}
Unidad 6: Ordenamientos Internos
Introducción:
En esta Unidad explicaremos 4 algoritmos para el Ordenamiento de Arreglos en Memoria Ram.
A continuación mencionaremos los diferentes métodos para ordenar:
1. Burbuja
2. ShellSort
3. RadixSort
4. QuickSort
Burbuja
Definición:
El método de la burbuja es una comparación lineal con cada uno de los elementos, el elemento que
sea menor contra el que se esta comparado intercambiaran posiciones. Este método no es
recomendado para grandes comparaciones, ya que es un proceso muy lento y requiere de una gran
cantidad de Memoria Ram.
Programa:
#include <conio.h>
#include <iostream.h>
class Lista
private:
int Lista[10],N;
public:
Lista()
for(int i=0;i<10;i++)
Lista[i]=0;
155
N=0;
void Burbuja(void)
if(N!=0)
int i,j,aux;
for(i=0;i<9;i++)
for(j=i+1;j<10;j++)
if(Lista[i]<Lista[j])
aux=Lista[i];
Lista[i]=Lista[j];
Lista[j]=aux;
cout<<"Lista Ordenada..."<<endl;
return;
cout<<"Lista Vacia..."<<endl;
if(N!=0)
156
{
for(int i=0;i<N;i++)
if(Lista[i]==Elem)
return;
cout<<"Lista Vacia..."<<endl;
return;
if(N<10)
Lista[N]=Elem;
N++;
return;
return;
157
{
if(N!=0)
for(int i=0;i<N;i++)
if(Lista[i]==Elem)
Lista[i]=0;
Burbuja();
N--;
return;
return;
void Recorrido()
if(N!=0)
for(int i=0;i<N;i++)
cout<<Lista[i]<<endl;
cout<<"Lista Vacia..."<<endl;
158
}
}tec;
main()
int op=0,res;
while(op!=6)
clrscr();
gotoxy(1,1);
cin>>op;
gotoxy(1,10);
switch (op)
case 1:
tec.Recorrido();
break;
case 2:
tec.Burbuja();
break;
case 3:
cin>>res;
159
tec.Busqueda(res);
break;
case 4:
cin>>res;
tec.Insertar(res);
break;
case 5:
cin>>res;
tec.Eliminar(res);
break;
case 6:
cout<<"Salida...";
break;
default:
cout<<"Opcion Erronea"<<endl;
break;
getch();
ShellSort
Definición:
160
Esta forma de ordenación es muy parecida a la ordenación con burbuja. La diferencia es que no es una
comparación lineal, sino que trabaja con una segmentación entre los datos. Por lo tanto es un buen
método, pero no el mejor para implementarlos en grandes arreglos.
Programa:
#include <conio.h>
#include <iostream.h>
class Lista
private:
int Lista[10],N;
public:
Lista()
for(int i=0;i<10;i++)
Lista[i]=0;
N=0;
void ShellSort(void)
if(N!=0)
int salto,aux,i;
for(salto=6/2;salto!=0;salto/=2)
for(i=salto;i<6;i++)
161
if(Lista[i-salto]<Lista[i])
aux=Lista[i];
Lista[i]=Lista[i-salto];
Lista[i-salto]=aux;
cout<<"Lista Ordenada..."<<endl;
return;
cout<<"Lista Vacia..."<<endl;
if(N!=0)
for(int i=0;i<N;i++)
if(Lista[i]==Elem)
return;
cout<<"Lista Vacia..."<<endl;
162
return;
if(N<10)
Lista[N]=Elem;
N++;
return;
return;
if(N!=0)
for(int i=0;i<N;i++)
if(Lista[i]==Elem)
Lista[i]=0;
ShellSort();
163
N--;
return;
return;
void Recorrido()
if(N!=0)
for(int i=0;i<N;i++)
cout<<Lista[i]<<endl;
cout<<"Lista Vacia..."<<endl;
}tec;
main()
int op=0,res;
while(op!=6)
clrscr();
164
gotoxy(1,1);
cin>>op;
gotoxy(1,10);
switch (op)
case 1:
tec.Recorrido();
break;
case 2:
tec.ShellSort();
break;
case 3:
cin>>res;
tec.Busqueda(res);
break;
case 4:
cin>>res;
tec.Insertar(res);
break;
case 5:
165
cout<<"Que Numero de Control deseas Eliminar?"<<endl;
cin>>res;
tec.Eliminar(res);
break;
case 6:
cout<<"Salida...";
break;
default:
cout<<"Opcion Erronea"<<endl;
break;
getch();
RadixSort
Definición:
Este ordenamiento se basa en los valores de los dígitos reales en las representaciones de posiciones de
los números que se ordenan. Es decir… toma un número y lo descompone en sus unidades, decenas,
centenas, etc… de esta manera va determinando las posiciones de cada uno de ellos.
Programa:
#include <math.h>
#include <conio.h>
#include <iostream.h>
class Lista
private:
166
int Lista[10],Temp[10],Elementos,N;
public:
Lista()
for(int i=0;i<10;i++)
Lista[i]=0;
N=9;
Elementos=0;
void Ordenar()
if(N!=9)
RadixSort(0,Elementos,Lista,Temp);
RadixSort(1,Elementos,Temp,Lista);
RadixSort(2,Elementos,Lista,Temp);
RadixSort(3,Elementos,Temp,Lista);
cout<<"Lista Ordenada..."<<endl;
return;
cout<<"Lista Vacia..."<<endl;
167
int cont[256];
int ind[256];
int i;
memset(cont,0,sizeof(cont));
for(i=0;i<10;i++)
cont[((fuente[i])>>(byte*8))&0xff]++;
ind[0]=0;
for(i=1;i<256;i++)
ind[i]=ind[i-1]+cont[i-1];
for(i=0;i<10;i++)
dest[ind[((fuente[i])>>(byte*8))&0xff]++]=fuente[i];
if(N!=9)
for(int i=0;i<N;i++)
if(Lista[i]==Elem)
return;
168
cout<<"Lista Vacia..."<<endl;
return;
if(N!=-1)
Elementos++;
Lista[N]=Elem;
N--;
return;
return;
if(N!=9)
for(int i=0;i<N;i++)
if(Lista[i]==Elem)
Lista[i]=0;
169
Ordenar();
N++;
Elementos--;
return;
return;
void Recorrido()
if(N!=9)
for(int i=9;i!=N;i--)
cout<<Lista[i]<<endl;
return;
cout<<"Lista Vacia..."<<endl;
}tec;
main()
int op=0,res;
170
while(op!=6)
clrscr();
gotoxy(1,1);
cin>>op;
gotoxy(1,10);
switch (op)
case 1:
tec.Recorrido();
break;
case 2:
tec.Ordenar();
break;
case 3:
cin>>res;
tec.Busqueda(res);
break;
case 4:
cin>>res;
171
tec.Insertar(res);
break;
case 5:
cin>>res;
tec.Eliminar(res);
break;
case 6:
cout<<"Salida...";
break;
default:
cout<<"Opcion Erronea"<<endl;
break;
getch();
QuickSort
Definición:
Probablemente este será el mejor de los métodos que mencionamos en esta unidad. Este divide
aleatoriamente el arreglo para comparar si un elemento es mayor o menor. Dependiendo el resultado
lo partirá ya sea por la izquierda o derecha, de esta forma se repite el procedimiento para ordenarlos.
Programa:
#include <conio.h>
#include <iostream.h>
class Lista
172
{
private:
int Lista[10],N;
public:
Lista()
for(int i=0;i<10;i++)
Lista[i]=0;
N=1;
int izq,dch,temp;
izq=menor;
dch=mayor;
while(izq<dch)
while(Lista[dch]>Lista[menor])
dch--;
while((izq<dch)&&(Lista[izq]<=Lista[menor]))
izq++;
if(izq<dch)
173
temp=Lista[izq];
Lista[izq]=Lista[dch];
Lista[dch]=temp;
temp=Lista[dch];
Lista[dch]=Lista[menor];
Lista[menor]=temp;
return dch;
if(N!=1)
int medio;
if(menor<mayor)
medio=Dividir(menor,mayor);
QuickSort (menor,medio-1);
QuickSort (medio+1,mayor);
cout<<"Lista Ordenada..."<<endl;
cout<<"Lista Vacia..."<<endl;
174
}
if(N!=0)
for(int i=0;i<N;i++)
if(Lista[i]==Elem)
return;
cout<<"Lista Vacia..."<<endl;
return;
if(N<11)
Lista[10-N]=Elem;
N++;
return;
175
}
return;
if(N!=0)
for(int i=0;i<N;i++)
if(Lista[i]==Elem)
Lista[i]=0;
QuickSort(0,9);
N--;
return;
return;
void Recorrido()
if(N!=1)
176
for(int i=1;i!=N;i++)
cout<<Lista[10-i]<<endl;
cout<<"Lista Vacia..."<<endl;
}tec;
main()
int op=0,res;
while(op!=6)
clrscr();
gotoxy(1,1);
cin>>op;
gotoxy(1,10);
switch (op)
case 1:
tec.Recorrido();
break;
case 2:
177
tec.QuickSort(0,9);
break;
case 3:
cin>>res;
tec.Busqueda(res);
break;
case 4:
cin>>res;
tec.Insertar(res);
break;
case 5:
cin>>res;
tec.Eliminar(res);
break;
case 6:
cout<<"Salida...";
break;
default:
cout<<"Opcion Erronea"<<endl;
break;
178
getch();
}
Unidad 7: Ordenamientos Externos
Introducción:
En esta Unidad explicaremos 2 algoritmos para el Ordenamiento de Archivos. A continuación
mencionaremos los diferentes métodos para ordenar:
1. Mezcla Directa
2. Mezcla Natural
Mezcla Directa
Definición:
Este algoritmo consiste en tener un archivo A desordenado. Este archivo se ordenara haciendo los
siguientes pasos:
1.- Definir tamaño de tramo igual a 1
2.- Repartir el archivo A en dos archivos B y C escribiendo alternadamente un tramo en cada uno
3.- Aplicar el algoritmo de mezcla simple a cada par de tramos correspondiente de los archivos B y C
guardando el resultado en el archivo A
4.- Duplicar el tamaño del tramo
5.- Regresar al paso 2 si el tamaño del tramo es menor que la cantidad de elementos a ordenar
Programa:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream.h>
class Archivos
public:
char linea[128];
rewind(fich);
179
fgets(linea, 128, fich);
while(!feof(fich))
puts(linea);
int ordenado;
FILE *aux[2];
do
rewind(fich);
Separar(fich, aux);
rewind(aux[0]);
rewind(aux[1]);
rewind(fich);
fclose(aux[0]);
fclose(aux[1]);
180
}while(!ordenado);
remove("aux1.txt");
remove("aux2.txt");
int salida = 0;
strcpy(anterior[0], "");
strcpy(anterior[1], "");
while(!feof(fich))
salida = 1;
salida = 0;
strcpy(anterior[salida], linea);
fputs(linea, aux[salida]);
181
char ultima[128], linea[2][128], anterior[2][128];
int entrada;
int tramos = 0;
strcpy(ultima, "");
strcpy(anterior[0], "");
strcpy(anterior[1], "");
entrada = 0;
else
entrada = 1;
strcpy(anterior[entrada], linea[entrada]);
fputs(linea[entrada], fich);
if(!entrada)
entrada = 1;
else
entrada = 0;
182
tramos++;
do
strcpy(anterior[entrada], linea[entrada]);
fputs(linea[entrada], fich);
if(!feof(aux[0]))
tramos++;
while(!feof(aux[0]))
fputs(linea[0], fich);
if(!feof(aux[1]))
tramos++;
while(!feof(aux[1]))
fputs(linea[1], fich);
return(tramos == 1);
183
}
}tec;
main()
FILE *fichero;
int res,op=0,b=0;
while(op!=3)
clrscr();
gotoxy(1,1);
cin>>op;
gotoxy(1,10);
switch (op)
case 1:
if(b!=1)
b=1;
tec.Mostrar(fichero);
184
else
break;
case 2:
tec.Mezcla(fichero);
tec.Mostrar(fichero);
break;
case 3:
cout<<"Salir..."<<endl;
break;
default:
cout<<"Opcion Erronea..."<<endl;
break;
fclose(fichero);
getch();
Mezcla Directa
Definición:
Es una mejora del algoritmo de mezcla directa puesto que en vez de considerar tramos de tamaño fijo
se toman en cuenta para la ordenación en todo momento tramos de longitud máxima.
Al igual que el mezcla directa se debe hacer un proceso de partir el archivo original para mezclarlo,
posteriormente mientras en el archivo C haya elementos a mezclar.
Programa:
#include <conio.h>
#include <stdio.h>
185
#include <iostream.h>
#include <string.h>
void main(){
char n[10]="mezcla.txt";
mezcla_directa(n);
getch();
FILE *a,*b,*c;
int ra,rb;
a=fopen(A,"rb");
b=fopen(B,"rb");
c=fopen(C,"rb");
if(a&&b&&c)
fread(&ra,sizeof(ra),1,a);
fread(&rb,sizeof(rb),1,b);
while(!feof(a)&&!feof(b))
186
{
if(ra<=rb)
fwrite(&ra,sizeof(ra),1,c);
fread(&ra,sizeof(ra),1,a);
else
fwrite(&rb,sizeof(rb),1,c);
fread(&ra,sizeof(ra),1,b);
while(!feof(a))
fwrite(&ra,sizeof(ra),1,c);
fread(&ra,sizeof(ra),1,a);
while(!feof(a))
fwrite(&rb,sizeof(rb),1,c);
fread(&rb,sizeof(rb),1,b);
fclose(a);
fclose(b);
187
fclose(c);
FILE *a,*b,*c;
a=fopen(nom,"r+");
b=fopen("m1.txt","r+");
c=fopen("m2.txt","r+");
while(t<n){
partir(nom,t);
mezcla_simple("m1.txt","m2.txt",nom);
mezclar(nom,t);
t = t* 2;
FILE *a,*b,*c;
a=fopen(nom,"r+");
b=fopen("m1.txt","a+");
c=fopen("m2.txt","a+");
if(a&&b&&c){
188
fread(®,sizeof(reg),1,a);
while(!feof(a)){
if(sw)
fwrite(®,sizeof(reg),1,b);
else
fwrite(®,sizeof(reg),1,c);
fread(®,sizeof(reg),1,a);
sw=!sw ;
fclose(a);
fclose(b);
fclose(c);
FILE *a,*b,*c;
int rb,rc,ctb,ctc;
a= fopen(nom,"w+");
b= fopen("m1","r+");
c= fopen("m2","r+");
if(a&&b&&c){
fread(&rb,sizeof(rb),1,b);
189
fread(&rc,sizeof(rb),1,c);
ctb=ctc=t;
if(rb<rc){
fwrite(&rb,sizeof(rb),1,a);
fread(&rb,sizeof(rb),1,b);
ctb--;
else{
fwrite(&rc,sizeof(rc),1,a);
fread(&rc,sizeof(rc),1,c);
ctc--;
fwrite(&rb,sizeof(rb),1,a);
fread(&rb,sizeof(rb),1,b);
ctb--;
fwrite(&rc,sizeof(rc),1,a);
fread(&rc,sizeof(rc),1,c);
190
ctc--;
while(!feof(b)){
fwrite(&rb,sizeof(rb),1,a);
fread(&rb,sizeof(rb),1,b);
while(!feof(c)){
fwrite(&rc,sizeof(rc),1,a);
fread(&rc,sizeof(rc),1,c);
fclose(a);
fclose(b);
fclose(c);
remove("m1");
remove("m2");
}
Metodos de Busquedas
Busqueda Secuencial
Definicion:
La búsqueda es el proceso de localizar un registro (elemento) con un valor de llave particular. La
búsqueda termina exitosamente cuando se localiza el registro que contenga la llave buscada, o termina
sin éxito, cuando se determina que no aparece ningún registro con esa llave.
Búsqueda secuencial, también se le conoce como búsqueda lineal. Supongamos una colección de
registros organizados como una lista lineal. El algoritmo básico de búsqueda secuencial consiste en
empezar al inicio de la lista e ir a través de cada registro hasta encontrar la llave indicada (k), o hasta al
final de la lista.
191
La situación óptima es que el registro buscado sea el primero en ser examinado. El peor caso es cuando
las llaves de todos los n registros son comparados con k (lo que se busca). El caso promedio es n/2
comparaciones.
Este método de búsqueda es muy lento, pero si los datos no están en orden es el único método que
puede emplearse para hacer las búsquedas. Si los valores de la llave no son únicos, para encontrar
todos los registros con una llave particular, se requiere buscar en toda la lista.
Mejoras en la eficiencia de la búsqueda secuencial
1)Muestreo de acceso
Este método consiste en observar que tan frecuentemente se solicita cada registro y ordenarlos de
acuerdo a las probabilidades de acceso detectadas.
2)Movimiento hacia el frente
Este esquema consiste en que la lista de registros se reorganicen dinámicamente. Con este método,
cada vez que búsqueda de una llave sea exitosa, el registro correspondiente se mueve a la primera
posición de la lista y se recorren una posición hacia abajo los que estaban antes que el.
3)Transposición
Este es otro esquema de reorganización dinámica que consiste en que, cada vez que se lleve a cabo
una búsqueda exitosa, el registro correspondiente se intercambia con el anterior. Con este
procedimiento, entre mas accesos tenga el registro, mas rápidamente avanzara hacia la primera
posición. Comparado con el método de movimiento al frente, el método requiere mas tiempo de
actividad para reorganizar al conjunto de registros . Una ventaja de método de transposición es que no
permite que el requerimiento aislado de un registro, cambie de posición todo el conjunto de registros.
De hecho, un registro debe ganar poco a poco su derecho a alcanzar el inicio de la lista.
4)Ordenamiento
Una forma de reducir el numero de comparaciones esperadas cuando hay una significativa frecuencia
de búsqueda sin éxito es la de ordenar los registros en base al valor de la llave. Esta técnica es útil
cuando la lista es una lista de excepciones, tales como una lista de decisiones, en cuyo caso la mayoría
de las búsquedas no tendrán éxito. Con este método una búsqueda sin éxito termina cuando se
encuentra el primer valor de la llave mayor que el buscado, en lugar de la final de la lista.
Programa:
#include <conio.h>
#include <iostream.h>
class Lista
private:
int Lista[10],N;
public:
Lista()
192
for(int i=0;i<10;i++)
Lista[i]=0;
N=0;
if(N!=0)
for(int i=0;i<N;i++)
if(Lista[i]==Elem)
return;
return;
cout<<"Lista Vacia..."<<endl;
return;
if(N<10)
193
{
Lista[N]=Elem;
N++;
return;
return;
if(N!=0)
for(int i=0;i<N;i++)
if(Lista[i]==Elem)
Lista[i]=0;
N--;
return;
return;
194
void Recorrido()
if(N!=0)
for(int i=0;i<N;i++)
cout<<Lista[i]<<endl;
cout<<"Lista Vacia..."<<endl;
}tec;
main()
int op=0,res;
while(op!=5)
clrscr();
gotoxy(1,1);
cin>>op;
gotoxy(1,10);
switch (op)
195
case 1:
tec.Recorrido();
break;
case 2:
cin>>res;
tec.Busqueda(res);
break;
case 3:
cin>>res;
tec.Insertar(res);
break;
case 4:
cin>>res;
tec.Eliminar(res);
break;
case 5:
cout<<"Salida...";
break;
default:
cout<<"Opcion Erronea"<<endl;
break;
196
}
getch();
CORRIDA:
Búsqueda Binaria
Definicion:
Se puede aplicar tanto a datos en listas lineales como en árboles binarios de búsqueda. Los
prerrequisitos principales para la búsqueda binaria son:
La lista debe estar ordenada en un orden especifíco de acuerdo al valor de la llave.
Debe conocerse el número de registros.
Algoritmo:
197
El esfuerzo máximo para este algoritmo es de log2n.
El mínimo de 1 y en promedio ½ log2 n.
Programa:
#include <conio.h>
#include <iostream.h>
class Lista
private:
int Lista[10],N;
public:
Lista()
for(int i=0;i<10;i++)
Lista[i]=0;
N=0;
if(N!=0)
int inicio=0,medio,final=9;
while(inicio<=final)
medio=(inicio+final)/2;
if(Elem==Lista[medio])
198
{
return;
else if(Elem<Lista[medio])
final=medio-1;
else
inicio=medio+1;
return;
cout<<"Lista Vacia..."<<endl;
return;
if(N<10)
199
Lista[N]=Elem;
N++;
return;
return;
if(N!=0)
for(int i=0;i<N;i++)
if(Lista[i]==Elem)
Lista[i]=0;
N--;
return;
return;
void Recorrido()
200
{
if(N!=0)
for(int i=0;i<N;i++)
cout<<Lista[i]<<endl;
cout<<"Lista Vacia..."<<endl;
}tec;
main()
int op=0,res;
while(op!=5)
clrscr();
gotoxy(1,1);
cin>>op;
gotoxy(1,10);
switch (op)
case 1:
201
tec.Recorrido();
break;
case 2:
cin>>res;
tec.Busqueda(res);
break;
case 3:
cin>>res;
tec.Insertar(res);
break;
case 4:
cin>>res;
tec.Eliminar(res);
break;
case 5:
cout<<"Salida...";
break;
default:
cout<<"Opcion Erronea"<<endl;
break;
202
getch();
CORRIDA
203
Pero el término mas usado es el de hashing. Al cálculo que se realiza para obtener una dirección a
partir de una llave se le conoce como función hash.
Ventaja
1. Se pueden usar los valores naturales de la llave, puesto que se traducen internamente a
direcciones fáciles de localizar
2. Se logra independencia lógica y física, debido a que los valores de las llaves son independientes
del espacio de direcciones
3. No se requiere almacenamiento adicional para los índices.
Desventajas
1. No pueden usarse registros de longitud variable
2. El archivo no esta clasificado
3. No permite llaves repetidas
4. Solo permite acceso por una sola llave
Costos
Tiempo de procesamiento requerido para la aplicación de la función hash
Tiempo de procesamiento y los accesos E/S requeridos para solucionar las colisiones.
La eficiencia de una función hash depende de:
1. La distribución de los valores de llave que realmente se usan
2. El numero de valores de llave que realmente están en uso con respecto al tamaño del espacio
de direcciones
3. El numero de registros que pueden almacenarse en una dirección dad sin causar una colisión
4. La técnica usada para resolver el problema de las colisiones
Las funciones hash mas comunes son:
Residuo de la división
Medio del cuadrado
Pliegue
HASHING POR RESIDUO DE LA DIVISIÓN
La idea de este método es la de dividir el valor de la llave entre un numero apropiado, y después
utilizar el residuo de la división como dirección relativa para el registro (dirección = llave módulo
divisor).
Mientras que el valor calculado real de una dirección relativa, dados tanto un valor de llave como el
divisor, es directo; la elección del divisor apropiado puede no ser tan simple. Existen varios factores
que deben considerarse para seleccionar el divisor:
1. El rango de valores que resultan de la operación “llave % divisor”, va desde cero hasta el divisor
1. Luego, el divisor determina el tamaño del espacio de direcciones relativas. Si se sabe que el
archivo va a contener por lo menos n registros, entonces tendremos que hacer que divisor > n,
suponiendo que solamente un registro puede ser almacenado en una dirección relativa dada.
2. El divisor deberá seleccionarse de tal forma que la probabilidad de colisión sea minimizada.
¿Como escoger este numero? Mediante investigaciones se ha demostrado que los divisores que
son números pares tienden a comportase pobremente, especialmente con los conjuntos de
valores de llave que son predominantemente impares. Algunas investigaciones sugieren que el
divisor deberá ser un numero primo. Sin embargo, otras sugieren que los divisores no primos
trabajan también como los divisores primos, siempre y cuando los divisores no primos no
contengan ningún factor primo menor de 20. Lo mas común es elegir el número primo mas
próximo al total de direcciones.
Ejemplo:
204
Independientemente de que tan bueno sea el divisor, cuando el espacio de direcciones de un archivo
esta completamente lleno, la probabilidad de colisión crece dramáticamente. La saturación de archivo
de mide mediante su factor de carga, el cual se define como la relación del numero de registros en el
archivo contra el numero de registros que el archivo podría contener si estuviese completamente
lleno.
Todas las funciones hash comienzan a trabajar probablemente cuando el archivo esta casi lleno. Por lo
general el máximo factor de carga que puede tolerarse en un archivo para un rendimiento razonable es
de entre el 70 % y 80 %.
HASHING POR MEDIO DEL CUADRADO
En esta técnica, la llave es elevada al cuadrado, después algunos dígitos específicos se extraen de la
mitad del resultado para constituir la dirección relativa. Si se desea una dirección de n dígitos, entonces
los dígitos se truncan en ambos extremos de la llave elevada al cuadrado, tomando n dígitos
intermedios. Las mismas posiciones de n dígitos deben extraerse para cada llave.
Ejemplo:
Utilizando esta función hashing el tamaño del archivo resultante es de 10 n donde n es el numero de
dígitos extraídos de los valores de la llave elevada al cuadrado.
HASHING POR PLIEGUE
En esta técnica el valor de la llave es particionada en varias partes, cada una de las cuales
(excepto la ultima) tiene el mismo numero de dígitos que tiene la dirección relativa objetivo. Estas
particiones son después plegadas una sobre otra y sumadas. El resultado, es la dirección relativa. Igual
que para el método del medio del cuadrado, el tamaño del espacio de direcciones relativas es una
potencia de 10.
Ejemplo:
COMPARACIÓN ENTRE LAS FUNCIONES HASH
Aunque alguna otra técnica pueda desempeñarse mejor en situaciones particulares, la técnica del
residuo de la división proporciona el mejor desempeño. Ninguna función hash se desempeña siempre
mejor que las otras. El método del medio del cuadrado puede aplicarse en archivos con factores de
cargas bastantes bajas para dar generalmente un buen desempeño. El método de pliegues puede ser la
técnica mas fácil de calcular pero produce resultados bastante erráticos, a menos que la longitud de la
llave se aproximadamente igual a la longitud de la dirección.
Si la distribución de los valores de llaves no es conocida, entonces el método del residuo de la división
es preferible. Note que el hashing puede ser aplicado a llaves no numéricas. Las posiciones de
ordenamiento de secuencia de los caracteres en un valor de llave pueden ser utilizadas como sus
equivalentes “numéricos”. Alternativamente, el algoritmo hash actúa sobre las representaciones
binarias de los caracteres.
Todas las funciones hash presentadas tienen destinado un espacio de tamaño fijo. Aumentar el tamaño
del archivo relativo creado al usar una de estas funciones, implica cambiar la función hash, para que se
refiera a un espacio mayor y volver a cargar el nuevo archivo.
MÉTODOS PARA RESOLVER EL PROBLEMA DE LAS COLISIONES
Considere las llaves K1 y K2 que son sinónimas para la función hash R. Si K1 es almacenada primero en el
archivo y su dirección es R(K1), entonces se dice que K1 esta almacenado en su dirección de origen.
Existen dos métodos básicos para determinar donde debe ser alojado K2 :
Direccionamiento abierto.- Se encuentra entre dirección de origen para K2 dentro del archivo.
Separación de desborde (Area de desborde).- Se encuentra una dirección para K2 fuera del
área principal del archivo, en un área especial de desborde, que es utilizada exclusivamente
para almacenar registro que no pueden ser asignados en su dirección de origen
205
Los métodos mas conocidos para resolver colisiones son:
Sondeo lineal
Que es una técnica de direccionamiento abierto. Este es un proceso de búsqueda secuencial desde la
dirección de origen para encontrar la siguiente localidad vacía. Esta técnica es también conocida como
método de desbordamiento consecutivo.
Para almacenar un registro por hashing con sondeo lineal, la dirección no debe caer fuera del limite del
archivo, En lugar de terminar cuando el limite del espacio de dirección se alcanza, se regresa al inicio
del espacio y sondeamos desde ahí. Por lo que debe ser posible detectar si la dirección base ha sido
encontrada de nuevo, lo cual indica que el archivo esta lleno y no hay espacio para la llave.
Para la búsqueda de un registro por hashing con sondeo lineal, los valores de llave de los registros
encontrados en la dirección de origen, y en las direcciones alcanzadas con el sondeo lineal, deberá
compararse con el valor de la llave buscada, para determinar si el registro objetivo ha sido localizado o
no.
El sondeo lineal puede usarse para cualquier técnica de hashing. Si se emplea sondeo lineal para
almacenar registros, también deberá emplearse para recuperarlos.
Doble hashing
En esta técnica se aplica una segunda función hash para combinar la llave original con el resultado del
primer hash. El resultado del segundo hash puede situarse dentro del mismo archivo o en un archivo
de sobreflujo independiente; de cualquier modo, será necesario algún método de solución si ocurren
colisiones durante el segundo hash.
La ventaja del método de separación de desborde es que reduce la situación de una doble colisión, la
cual puede ocurrir con el método de direccionamiento abierto, en el cual un registro que no esta
almacenado en su dirección de origen desplazara a otro registro, el que después buscará su dirección
de origen. Esto puede evitarse con direccionamiento abierto, simplemente moviendo el registro
extraño a otra localidad y almacenando al nuevo registro en la dirección de origen ahora vacía.
Puede ser aplicado como cualquier direccionamiento abierto o técnica de separación de desborde.
Para ambas métodos para la solución de colisiones existen técnicas para mejorar su desempeño como:
1.- Encadenamiento de sinónimos
Una buena manera de mejorar la eficiencia de un archivo que utiliza el calculo de direcciones, sin
directorio auxiliar para guiar la recuperación de registros, es el encadenamiento de sinónimos.
Mantener una lista ligada de registros, con la misma dirección de origen, no reduce el numero de
colisiones, pero reduce los tiempos de acceso para recuperar los registros que no se encuentran en su
localidad de origen. El encadenamiento de sinónimos puede emplearse con cualquier técnica de
solución de colisiones.
Cuando un registro debe ser recuperado del archivo, solo los sinónimos de la llave objetivo son
accesados.
2.- Direccionamiento por cubetas
Otro enfoque para resolver el problema de las colisiones es asignar bloques de espacio (cubetas), que
pueden acomodar ocurrencias múltiples de registros, en lugar de asignar celdas individuales a
registros. Cuando una cubeta es desbordada, alguna nueva localización deberá ser encontrada para el
registro. Los métodos para el problema de sobrecupo son básicamente los mismo que los métodos
para resolver colisiones.
COMPARACIÓN ENTRE SONDEO LINEAL Y DOBLE HASHING
206
De ambos métodos resultan distribuciones diferentes de sinónimos en un archivo relativo. Para
aquellos casos en que el factor de carga es bajo (< 0.5), el sondeo lineal tiende a agrupar los sinónimos,
mientras que el doble hashing tiende a dispersar los sinónimos mas ampliamente a travéz del espacio
de direcciones.
El doble hashing tiende a comportarse casi también como el sondeo lineal con factores de carga
pequeños (< 0.5), pero actúa un poco mejor para factores de carga mayores. Con un factor de carga >
80 %, el sondeo lineal por lo general resulta tener un comportamiento terrible, mientras que el doble
hashing es bastante tolerable para búsquedas exitosas pero no así en búsquedas no exitosas.
Unidad 9: Grafos
Definicion:
Un grafo dirigido G consiste en un conjunto de vértices V y un conjunto de arcos o aristas A. Los vertice
se denominan también nodos o puntos.
Un arco, es un par ordenado de vértices(V,W) donde V es el vértice inicial y W es el vértice terminal del
arco. Un arco se expresa como: V–>W y se representa de la siguiente manera:
Los vértice de un grafo pueden usarse para representar objetos. Los arcos se utilizan para representar
relaciones entre estos objetos.
Las aplicaciones más importantes de los grafos son las siguientes:
Rutas entre ciudades.
Determinar tiempos máximos y mínimos en un proceso.
Flujo y control en un programa.
Operaciones Sobre Grafos:
En esta sección analizaremos algunas de las operaciones sobre grafos, como :
Creación.
Inserción.
Búsqueda.
Eliminación.
En esta sección, continuaremos utilizando los apuntadores que se usaron en las secciones anteriores.
TOP para hacer referencia al primer nodo, LD para indicar liga derecha y LA para indicar liga abajo, por
último usaremos los apuntadores P y Q para hacer referencia a los nuevos nodos que vayan a ser
usados.
ALGORITMO DE CREACION.
repite
si top=NIL entonces
new(top)
top(la)←NIL
top(ld)←NIL
lee(top(dato))
q←top
en caso contrario
new(p)
p(ld)←NIL
p(la)←NIL
q(la)←p
lee(p(dato))
q←-p
207
mensaje(otro vertice ?)
lee(respuesta)
hasta repuesta=no
p←top
mientras p<>NIL haz
mensaje(tiene vértices adyacentes p(dato) ?)
lee(respuesta)
si respueta=si entonces
repite
new(q)
lee(q(dato))
q(ld)←p(ld)
p(ld)←q
mensaje(otro vértice ?)
lee(respuesta2)
hasta respuesta2=no
p←p(la)
ALGORITMO DE INSERCION
mensaje(valor a insertar ?)
lee(valor_a_insertar)
si top<>NIL entonces
p←top
mientras p(la)<>NIL haz
p←p(la)
new(q)
lee(q(dato))
p(la)←q
q(la)←NIL
mensaje(Hay vértices adyacentes?)
lee(respuesta)
si respuesta=si entonces
mensaje(Cuantos vértices?)
lee(número_vértices)
desde i=1 hasta número_vértices haz
new(p)
lee(p(dato))
q(ld)←p
q←q(ld)
en caso contrario
mensaje(no existe lista)
ALGORITMO DE BUSQUEDA
mensaje(vértice a buscar)
lee(vértice_a_buscar)
208
p←top
repite
si p(dato)=vértice_a_buscar entonces
repite
p←p(ld)
escribe(p(dato))
hasta p(ld)=NIL
en caso contrario
p←(la)
hasta p=NIL
ALGORITMO DE BORRADO
mensaje(vértice a borrar ?)
lee(vértice_a_borrar)
p←top
r←p
q←p
sw←falso
repite
si p(dato)=vértice_a_borrar entonces
si p=top entonces
top←top(la)
r←top
sw←verdadero
en caso contrario
r(la)←p(la)
repite
p←p(ld)
dispose(q)
q←p
hasta p=NIL
si sw=verdadero entonces
p←r
q←p
en caso contrario
p←r(la)
q←p
en caso contrario
r←p
repite
q←p(ld)
si q(dato)=vértice_a_borrar entonces
p(ld)←q(ld)
dispose(q)
q←p
en caso contrario
209
p←p(ld)
hasta p=NIL
Camino Mínimo:
Se denomina camino mínimo entre dos vértices V y W, al camino óptimo entre ambos vértices.Para
determinar el camino mínimo entre dos vértices se utiliza el siguiente algoritmo:
210