UNIVERSIDAD SALESIANA
DE BOLIVIA
CARRERA INGENIERIA DE SISTEMAS
DOSSIER
PROGRAMACION II
Tercer Semestre
Lic. Katya Maricela Pérez Martínez
Lic. Gladys Francisca Chuquimia Mamani
Lic. Juan Vito Condori
2012
[Estructura de Datos] Page 2
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
INDICE
1. Capítulo I. Introducción a las Estructuras de Datos 1
1.1. Introducción 1
1.2. Estructuras Fundamentales 1
1.3. Abstracción 2
1.4. Definición de Estructuras de datos 2
1.5. T.D.A. (Tipo de Dato Abstracto) 2
1.6. Clasificación de las Estructuras de Datos 2
1.7. Estructuras de Datos Estáticas 4
1.8. Registros 18
1.9. Conjuntos 24
1.9.1. Definición de Conjuntos 24
1.10. Matrices poco densas 24
1.11. Archivos 26
1.12. Ejercicios propuestos 32
2. Capítulo II: Pilas 36
2.1. Introducción 36
2.2. Representación de las Pilas 37
2.3. Operaciones con pilas 38
2.4. Operaciones adicionales 39
2.5. Aplicaciones 43
2.5.1. Llamadas a subprogramas 43
2.5.2. Recursión 45
2.6. Ejercicios Propuestos 46
3. Capitulo III: Colas 47
3.1. Introducción 47
3.2. Características 48
3.3. Representación de las colas 48
3.4. Estructura de una cola 48
3.5. Operaciones con colas 49
3.6. Colas circulares 53
3.7. Operaciones con colas circulares 54
3.8. Aplicación de Pilas y Colas 55
3.9. Ejercicios 56
4. Capitulo IV: Recursividad 58
[Estructura de Datos] Page 3
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
4.2. Ámbito de aplicación 58
4.3. Razones de uso 58
4.4. ¿En qué consiste la recursividad? 59 4.5. Forma de Enfrentar problemas recursivos 59
4.6. Tipos de recursividad 61
4.7. La pila de recursion 62
4.8. La llamada a una función 63
4.9. Ejercicios 63
5. Listas Enlazadas 65
5.1. Introducción a las Estructuras de datos dinámica 65 5.2. Mecanismos para enlazar información 66
5.3. El tipo puntero 67
5.4. Tipo de dato abstracto Nodo 72
5.5. Punteros 72
5.5.1. Operador -> 72
5.6. Operaciones básicas sobre listas enlazadas 73
5.7. Ejercicios 78
6. Capítulo IV: Árboles y Grafos 79
6.1. Introducción 79
6.2. Conceptos Básicos 79
6.3. Árboles Binarios 81
6.4. Representación de árboles binarios 82
6.5. Recorridos 83
6.6. Árboles Binarios de Búsqueda (Abb) 86
6.7. Operaciones sobre árboles binarios de búsqueda 86
6.8. Árboles ordenados 90 6.9. Grafos 91 6.9.1. Definiciones Básicas 91 6.10. Ejercicios 95 7. Lecturas Complementarias 97 8. Glosario 102
Capítulo I
Introducción a las Estructuras De Datos
1.1. Introducción
Para procesar información en un computador es necesario hacer una abstracción de los datos que tomamos del mundo real, abstracción en el sentido de que se ignoran algunas propiedades de los objetos reales, es decir, se simplifican. Se hace una selección de los datos más representativos de la realidad a partir de los cuales pueda trabajar el computador para obtener unos resultados.
Cualquier lenguaje suministra una serie de tipos de datos simples, como son los números enteros, caracteres, números reales. En realidad suministra un subconjunto de éstos,
Asamblea en la carpintería
Cuentan que en la carpintería hubo una vez una extraña asamblea. Fue una reunión de herramientas para arreglar sus diferencias. El martillo ejerció la presidencia, pero la asamblea le notificó que tenía que renunciar. ¿La causa? ¡Hacía demasiado ruido! Y, además, se pasaba el tiempo golpeando. El martillo aceptó su culpa, pero pidió que también fuera expulsado el tornillo; dijo que había que darle muchas vueltas para que sirviera de algo. Ante el ataque, el tornillo aceptó también, pero a su vez pidió la expulsión de la lija. Hizo ver que era muy áspera en su trato y siempre tenía fricciones con los demás. Y la lija estuvo de acuerdo, a condición de que fuera expulsado el metro que siempre se la pasaba midiendo a los demás según su medida, como si fuera el único perfecto. En eso entró el carpintero, se puso el delantal e inició su trabajo. Utilizó el martillo, la lija, el metro y el tornillo. Finalmente, la tosca madera inicial se convirtió en un lindo mueble.
Cuando la carpintería quedó nuevamente sola, la asamblea reanudó la deliberación. Fue entonces cuando tomó la palabra el serrucho, y dijo: "Señores, ha quedado demostrado que tenemos defectos, pero el carpintero trabaja con nuestras cualidades. Eso es lo que nos hace valiosos. Así que no pensemos ya en nuestros puntos malos y concentrémonos en la utilidad de nuestros puntos buenos". La asamblea encontró entonces que el martillo era fuerte, el tornillo unía y daba fuerza, la lija era especial para afinar y limar asperezas y observaron que el metro era preciso y exacto.
Se sintieron entonces un equipo capaz de producir muebles de calidad. Se sintieron orgullosos de sus fortalezas y de trabajar juntos.
[Estructura de Datos] Page 2
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
pues la memoria del ordenador es finita. Los punteros (si los tiene) son también un tipo de datos. El tamaño de todos los tipos de datos depende de la máquina y del compilador sobre los que se trabaja.
1.2. Estructuras Fundamentales
Los datos a procesar por una computadora se clasifican en: 9 Simples
9 Estructurados
Los datos simples ocupan sólo una casilla de memoria, por tanto una variable simple hace referencia a un único valor a la vez.
Los datos Estructurados o Compuestos se caracterizan por el hecho de que con un nombre (identificador de variable estructurada) se hace referencia a un grupo de casillas de memoria. Tiene varios componentes.
Ejemplos: Dato Simple
Declaramos una variable A de tipo entero y asignamos el valor 25. A Å Identificador
int A;
A = 25; Dato Estructurado
Declaramos un dato compuesto o estructurado A que tendrá 5 elementos de tipo entero.
25
Cabe hacer notar que en el presente texto, se tomará como herramienta para los programas y representar las diferentes estructuras de datos el Lenguaje C++ y Java.
[Estructura de Datos] Page 3
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
int A[5] ;
A = {20,30,40,50,60}; A =
1.3. Abstracción
Una abstracción es un proceso mental donde se extraen rasgos esenciales de algo para representarlos por medio de un lenguaje gráfico o escrito.
1.4. Definición de Estructuras de Datos
Una estructura de datos es cualquier colección de datos organizados de tal forma que tengan asociados un conjunto de operaciones para poder manipularlos.
1.5. T.D.A. (Tipo de Dato Abstracto)
Al diseñar una estructura de datos con la técnica de abstracción pasa a ser un TDA, que: 9 Puede implementarse en cualquier lenguaje
9 Puede aplicarse en cualquier concepto
Ejemplo: Abstraemos el concepto Estudiante
Nombre del TAD Elementos
Operaciones o métodos
Como se puede notar existe una operación No Permitida denominada:
CalcularNotaFinal(); que no debiera estar presente en el TAD, debido a que no se cuenta
con elementos que nos permitan realizar esta operación.
ESTUDIANTE Ru: entero Nombre: Cadena Sexo: carácter Direccion: Cadena LeerDatosEstudiante () ImprimirDatosEstudiante () ModificarDireccion() CalcularNotaFinal() 20 30 40 50 60 Identificador
[Estructura de Datos] Page 4
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
Recuerda en todo momento que sólo deben incluirse las operaciones que puedan trabajar con los elementos que contiene el TAD.
1.6. Clasificación de las Estructuras de Datos
Las estructuras de datos desde el punto de vista de asignación de memoria, se clasifican en:
9 Estructuras de datos estáticas 9 Estructuras de datos dinámicas
También pueden ser clasificadas en: 9 Estructuras Lineales
9 Estructuras No Lineales
1.6.1.
Estructuras de Datos Estáticas
Son aquellas en las que el tamaño ocupado en memoria se define antes de que el programa se ejecute y no puede modificarse dicho tamaño durante la ejecución del programa. Por ejemplo tenemos a los Arreglos, Registros y Conjuntos.
1.6.2.
Estructuras de Datos Dinámicas
Las estructuras dinámicas de datos son estructuras que cuya dimensión puede crecer o disminuir durante la ejecución del programa. Por ejmplos: Listas Enlazadas, Árboles y Grafos.
1.6.3.
Estructuras de Datos Lineales
Las estructuras de datos lineales se derivan del concepto de secuencia. Primero se definen las secuencias como conjuntos de elementos entre los que se establece una relación de predecesor y sucesor. Los diferentes TADs basados en este concepto se diferenciaran por las operaciones de acceso a los elementos y manipulación de la estructura. Desde el punto de vista de la informática, existen tres estructuras lineales especialmente importantes: vectores, las pilas, las colas y las listas.
1.6.4.
Estructuras de Datos No Lineales
Se denominan estructuras de datos No Lineales porque a cada elemento le pueden seguir varios elementos o puede estar rodeado de elementos. Por ejemplo: Árboles, Grafos y Matrices
[Estructura de Datos] Page 5
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
1.7. Estructuras de Datos Estáticas
1.7.1.
Arreglos
Definición: Colección finita, homogénea y ordenada de elementos. Finita: Porque todo
arreglo tiene un límite. Homogénea: Porque todos los elementos son del mismo tipo. Ordenada: Porque se puede determinar cuál es el enésimo elemento.
Un arreglo tiene dos partes: Componentes e índices
C1 C2 … Cn
i0 i1 … iN
Componentes: Hacen referencia a los elementos que forman el arreglo. Índices: Permiten referirse a los componentes del arreglo en forma individual.
1.7.2.
Arreglos Unidimensionales (Vectores)
Son los arreglos más simples y constan de un solo índice, también se llaman vectores.
Notación: Podría ser de diferentes maneras. Por ejemplo:
Array [0...9] de enteros: Vector Vector: C componente 30 50 70 60 0 1 2 … 8 Identificador Indice
Donde, C hace referencia a todo el vector, mientras que los índices hacen referencia a los elementos en forma individual.
1.7.3.
Declaración de vectores
En Java
Para declarar un Array se utilizan corchetes para indicar que se trata de un Array y no de una simple variable de tipo especificado. Su sintaxis es:
Componentes Indices
C =
[Estructura de Datos] Page 6
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
O bien:
Donde:
Tipo_dato: es el tipo de datos de los elementos del vector. Identificador: es el nombre del vector.
Luego, se debe crear el Array con el operador new, de la siguiente manera:
Por ejemplo:
El programa: Array.java, trabaja con el vector losValores, que almacena un máximo de 10 elementos enteros.
Implementación del TAD Vector
Este es el diseño del TAD vector que maneja números enteros.
Ejercicios
A continuación se muestra la implementación de este TAD en Java.
En lenguaje java:
public class Array {
public static void main (String arg []) {
int losValores [];
losValores = new int [10]; losValores [0] = 100; System.out.println (losValores [0]); } } Archivo: Array.java Tipo_dato [ ] identificador;
Identificador = new tipo [ cantidad_de_elementos ];
VECTOR V[15]: Entero N: Entero leedim() leervector() mostrarvector()
[Estructura de Datos] Page 7
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
//ARCHIVO VECTOR.JAVA import java.io.*; public class Vector { static int v[]; static int n;
static InputStreamReader Caracteres; static BufferedReader Buffer;
static String dato;
static void leedim () throws IOException {
System.out.println ("Cuantos elementos insertara en el Vector? "); dato = Buffer.readLine ();
n = Integer.parseInt (dato); }
static void leervector () throws IOException { int i; for(i=0; i < n; i++) { System.out.println("Ingrese elemento "+ i + " = "); dato = Buffer.readLine(); v[i] = Integer.parseInt(dato); } }
static void mostrarvector () throws IOException { int i; for(i=0; i < n; i++) { System.out.print(v[i] + " "); } }
public static void main (String [] args) throws IOException {
v = new int[15];
Caracteres = new InputStreamReader (System.in); Buffer = new BufferedReader(Caracteres);
leedim (); leervector(); mostrarvector(); } }
[Estructura de Datos] Page 8
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
EJERCICIOS EN LENGUAJE C
1. Queremos efectuar estadísticas con una serie de valores (las edades de 15 personas).
En una primera versión, solicitaremos las edades de todas las personas y, a continuación, calcularemos y mostraremos por pantalla la edad media, la desviación estándar, la moda y la mediana. Las fórmulas para la media y la desviación estándar son:
15
15 1∑
==
ix
ix
15
)
(
15 1 2∑
=−
=
ix
ix
δ
Donde Xi es la edad del individuo número i.
Se diseña a continuación el TAD.
//ARCHIVO EJERCICIO1.CPP #include <conio.h> #include <iosteam.h> #include <math.h> #define PERSONAS 15 struct ESTADISTICA { int E[PERSONAS]; void LeerEdades(void); void ImprimirEdades(void); void CalculaMedia(void); void CalculaDesviacion(void); }; void ESTADISTICA::LeerEdades(void) { //Lectura de edades
for (int i=0; i<PERSONAS; i++) { ESTADISTICA E[15]: Entero LeerEdades() ImprimirEdades() CalculaMedia() CalculaDesviacion()
[Estructura de Datos] Page 9
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
cout<<"Por favor, introduce la edad de la persona nïumero"<< i; cin>>E[i];
} //fin del for
} // fin de IngresarDatos
void ESTADISTICA::ImprimirEdades(void) {
//imprime edades
for (int i=0; i<PERSONAS; i++) {
cout<<E[i]<<” - “; } //fin del for
} // fin de IngresarDatos
// Calculo de la media
void ESTADISTICA::CalculaMedia(void) {
double sumaedad = 0, media; for (int i=1; i<=PERSONAS; i++) sumaedad = sumaedad +edad[i]; media =(double) sumaedad / PERSONAS;
cout<<”La media de las edades es……”<< media; }
// Calculo de la desviación estándar
void ESTADISTICA::CalculaDesviacion(void) {
double desviacion, sumadesviacion = 0.0; for (int i=0; i<PERSONAS; i++)
sumadesviacion = sumadesviacion+(edad[i]-media)*(edad[i] - media); desviacion = sqrt(sumadesviacion / PERSONAS );
cout<<”La desviación estándar es….”<<desviación; } void main(void ) { ESTADISTICA Es; clrscr(); Es.LeerEdades(); Es.ImprimirEdades(); Es.CalculaMedia(); Es.CalculaDesviacion(); getch(); }
[Estructura de Datos] Page 10
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
1.7.4.
Cadenas de Caracteres
Los arreglos de caracteres tienen varias características únicas. Un arreglo de caracteres puede inicializarse de la siguiente forma:
• El tamaño de CADENA1 está determinado por el compilador, y generalmente es de 256 caracteres máximo.
• La cadena "rosa" contiene cuatro caracteres, más un caracter especial de terminación denominado caracter nulo (' \0 ').
• Los arreglos de caracteres pueden inicializarse también con constantes individuales dentro de una lista.
• También podemos colocar una cadena de caracteres directamente dentro de un arreglo de caracteres desde el teclado. Por ejemplo:
char CAD2[20];
cin >> CAD2;
EJERCICIO 1.
El programa puede parecer a primera vista muy sencillo. En primer lugar vamos a leer y escribir una cadena. La primera solución intuitiva:
char CADENA1[ ] = "rosa";
char CADENA1[ ]= {' r ', ' o ', ' s ', ' a ', ' \0 ' };
#include <iostream> // USAMOS: cin, cout void main()
{
char s[20]; // Cadena de hasta 19 caracteres cin >> s; // Leer la primera palabra
cout << endl << s // Escribir en nueva línea la cadena << endl; // Y pasar a la línea siguiente
[Estructura de Datos] Page 11
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia EJERCICIO 1.
Programa para leer caracteres desde teclado hasta que el caracter sea nulo
EJERCICIO 3.
Bien, ahora veamos un ejemplo tradicional, se trata de leer caracteres desde el teclado y contar cuántos hay de cada tipo. Los tipos que deberemos contar serán: consonantes, vocales, dígitos, signos de puntuación, mayúsculas, minúsculas y espacios. Cada carácter puede pertenecer a uno o varios grupos. Los espacios son utilizados frecuentemente para contar palabras.
#include <iostream.h> // Usamos: ios, cin, cout #include <iomanip.h> // Usamos: resetiosflags
void Leer_Cadena(char * s) {
cin >> resetiosflags(ios::skipws); // Para que no pase los caracteres blancos. for (int i= 0; cin >> s[i]; i++) // Leer caracteres hasta el caracter nulo. if (s[i] == '\n') break;
s[i]= '\0'; // Pone el caracter de fin de cadena. }
void main() {
char s[100]; // Buffer de capacidad de hasta 99 caracteres y '\0'. Si // metemos mas caracteres hay posibilidad de 'cuelgue'
cout << endl << "Introduce una cadena (termina con CTRL-Z o INTRO)" << endl; Leer_Cadena(s);
cout << endl << "La cadena es: " << s << endl; }
[Estructura de Datos] Page 12
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
// Cuenta letras #include <iostream.h> #include <ctype.h> int main() { int consonantes = 0; int vocales = 0; int digitos = 0; int mayusculas = 0; int minusculas = 0; int espacios = 0; int puntuacion = 0;
char c; // caracteres leidos desde el teclado
cout << "Contaremos caracteres hasta que se pulse ^Z" << endl; while((c = getchar()) != EOF)
{
if(isdigit(c)) digitos++; else if(isspace(c)) espacios++; else if(ispunct(c)) puntuacion++; else if(isalpha(c))
{
if(isupper(c)) mayusculas++; else minusculas++; switch(tolower(c)) { case 'a': case 'e': case 'i': case 'o': case 'u': vocales++; break; default: consonantes++; } } }
cout << "Resultados:" << endl;
cout << "Dígitos: " << digitos << endl; cout << "Espacios: " << espacios << endl; cout << "Puntuación: " << puntuacion << endl;
cout << "Alfabéticos: " << mayusculas + minusculas<< endl; cout << "Mayúsculas: " << mayusculas << endl;
cout << "Minúsculas: " << minusculas << endl; cout << "Vocales: " << vocales << endl; cout << "Consonantes: " << consonantes << endl; cout << "Total: " << digitos + espacios + vocales + consonantes + puntuacion << endl;
return 0; }
[Estructura de Datos] Page 13
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
1.7.5.
Arreglos Multidimensionales
Existe en la mayoría de los lenguajes una estructura de arreglos multidimensionales. El número de dimensiones (índices) permitido depende del lenguaje elegido.
1.7.5.1. Matrices
Una matriz es un arreglo de dos dimensiones, y para especificar cualquier elemento, debemos hacer referencia a dos índices (que representan la posición como renglón y columna). Aunque no se justificará aquí, es conveniente mencionar que la representación matricial es puramente conceptual y con el único fin de facilitar al programador el manejo de los elementos, ya que la computadora almacena los datos en una forma totalmente diferente
Se analizarán primero los arreglos bidimensionales (caso especial de los multidimensionales) por ser los mas utilizados.
• C++ soporta hasta arreglos con 12 dimensiones. En arreglos de dos dimensiones, el primer elemento representa el renglón y el segundo la columna.
• Cada elemento de un arreglo bidimensional puede referenciarse de la siguiente manera: arreglo [ i ] [ j ].
• Un arreglo multidimensional puede inicializarse desde su declaración. Por ejemplo, un arreglo bidimensional b[2][2] puede declararse e inicializarse así:
int b[2][2] = { {1,2} , {3,4} };
• Los valores son agrupados en renglones.
9 Declaración de una Matríz
La sintaxis en el lenguaje C++ es el siguiente:
donde:
• tipo puede ser cualquier tipo de dato (int, float, char, etc.).
[Estructura de Datos] Page 14
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
• nombre_de_variable es el nombre del arreglo.
• rango 1 corresponde al número de renglones que conforman el arreglo. • rango 2 corresponde al número de columnas.
Podemos trabajar con cada uno de los elementos de la matriz: X[3][5] = 20;
9 Operaciones con arreglos bidimensionales
Las operaciones que pueden realizarse con arreglos bidimensionales son las siguientes: • Lectura/escritura • Asignación • Actualización: Inserción Eliminación Modificación • Ordenación • Búsqueda
En general los arreglos bidimensionales son una generalización de los unidimensionales, por lo que se realizará un ejemplo con algunas de estas operaciones a continuación.
Ejemplo: La Tabla contiene gastos que registra una ama de casa correspondientes a los
12 meses del año anterior.
Meses/Gastos Agua Luz Telefono Mercado
Enero 23 57 840 250 Febrero 28 60 560 280 Marzo 34 55 400 275 Abril 24 87 700 340 Mayo 29 80 450 310 Junio 34 65 670 320 Julio 45 67 560 325 Agosto 48 78 570 323 Septiembre 32 54 540 290 Octubre 33 50 250 300 Noviembre 35 70 330 350 Diciembre 38 62 300 430
Es posible interpretar esta tabla de la siguiente manera: dado un mes, se conocen los gasto realizados por la ama de casa; y dado un gasto se conocen los gastos mensuales. El programa será el siguiente:
[Estructura de Datos] Page 15
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
// PROCEDIMIENTO PARA IMPRIMIR TODOS LOS GASTOS DE LA // MATRIZ G
void Imprime_Gastos(MATRIZ G, int m, int g) {
for (int i=1; i<=m; i++) { for(int j=1; j<=n; j++) cout<<G[i][j]<<” “; cout<<”\n”; } }
//PROCEDIMIENTO PARA LISTAR SUMAR TODOS LOS GASTOS DE TODO EL AÑO void Suma_Gastos (MATRIZ G, int m, int g)
{
int TotalGastos=0;
for (int i=1; i<=m; i++) for(int j=1; j<=n; j++)
TotalGastos = TotalGastos + G[i][j];
Cout<<”\n \n EL TOTAL DE GASTOS DEL AÑO ES...”<<TotalGastos; }
//PROGRAMA PRINCIPAL void main(void)
{ MATRIZ GASTOS ; clrscr() ;
Lee_Gastos (GASTOS, 12, 4) ; //lee gastos para 12 meses y 4 gastos Imprime_Gastos (GASTOS, 12,4); //Imprime los gastos de la matriz Suma_Gastos(GASTOS, 12,4);
getch(); }
#iclude<iostream.h> #include<conio.h>
typedef int MATRIZ[13][5]; //definimos un tipo de dato MATRIZ de números enteros
//PROCEDIMIENTO PARA REGISTRAR LOS GASTOS EN LA MATRIZ G //DE DIMENSIONES m filas y g columnas
void Lee_gastos(MATRIZ G, int m, int g) {
int i; //contador de meses
int j; //contador de columnas de gasto
for ( i= 1; i<=m ; i++) for ( j=1; j<=g; j++) {
cout<<”\n Ingrese el gasto del mes “<< i << “gasto ”<< j<<; cin>>G[i][j];
} }
[Estructura de Datos] Page 16
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
1.8. Registros (Estructuras)
Cuando se habló de los arreglos se mencionó que se trataba de una colección de datos, todos del mismo tipo, que era un tipo estructurado de datos, y que son ellos se podía solucionar un gran número de problemas. Sin embargo, en la práctica a veces se necesitan estructuras que permitan almacenar distintos tipos de datos (característica con la cual no cuentan los arreglos).
Ejemplo
Una compañía tiene por cada empleado los siguientes datos: • Nombre (cadena de caracteres)
• Dirección (cadena de caracteres) • Edad (entero)
• Sexo (carácter) • Antigüedad (entero)
Si lo vemos gráficamente estos datos tenemos;
Nombre Direccion
Nom Pat Mat Calle Nro Zona Edad Sexo Antig
Juan Maria Rodríguez Alvarez Salas Vargas Av. Arce Calle 12 123 1345 Central Obrajes 25 29 M F 2 3
Si se quisiera almacenar estos datos no sería posible usar un arreglo, ya que sus componentes deben ser todos del mismo tipo.
1.8.1.
Definición De Registro y declaración de la
variable de registro.
Un registro es un dato estructurado, donde cado uno de sus componentes se denomina campo. Los campos de un registro pueden ser todos de diferentes tipos. Por lo tanto también podrán ser registros o arreglos. Cada campo se identifica por un nombre único (el identificador de campo). No se establece orden entre los campos.
[Estructura de Datos] Page 17
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
Donde:
Nom_Registro: Es el nombre o identificador del registro.
campoi: Es el nombre del campo i
tipo_datoi: es el tipo de dato del campo i.
EJEMPLO
Definir la estructura para los datos de un empleado y luego declarar la variable de registro.
1.8.2.
Acceso a los Campos De Un Registro
Como un registro es un dato estructurado no puede accecsarse directamente como un todo, sino que debe especificarse qué elemento (campo) del registro interesa. Para ello, en la mayoría de los lenguajes se sigue la siguiente sintaxis:
Variable_registro.campo struct Nom_Registro { tipo_dato1 campo1; tipo_dato1 campo2; tipo_daton campon; };
//declaración de la variable Variable_registro de tipo // Nom_Registro Nom_Registro Variable_registro ; struct EMPLEADO { char nombre[20]; char direccion[30]; int edad; int antigüedad: char sexo; }; EMPLEADO E ;
[Estructura de Datos] Page 18
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
Ejemplo:
Escribir un programa para leer los registros de N empleados de una empresa.
#include<iostream.h> #include<conio.h> struct EMPLEADO { char nombre[20]; char direccion[30]; int edad; int antiguedad: char sexo; };
//PROCEDIMIENTO PARA LEER LOS DATOS DE UN EMPLEADO
EMPLEADO LeeEmpleado (void) {
EMPLEADO E;
cout<<”\n Nombre del Empleado “; cin>> E.nombre;
cout<<”\n Dirección del Empleado “; cin>> E.direccion; cout<<”\n Edad del Empleado “; cin>> E.edad;
cout<<”\n Antigüedad del Empleado “; cin>> E.antiguedad; cout<<”\n Sexo del Empleado “; cin>> E.sexo;
return ( E ); }
// PROCEDIMIENTO PARA IMPRIMIR LOS DATOS PARA UN EMPLEADO void ImprimeEmpleado (EMPLEADO E)
{
cout<<”\n NOMBRE : “<<E.nombre;
cout<<”\n DIRECCION : “<<E.direccion; cout<<”\n EDAD : “<<E.edad;
cout<<”\n ANTIGUEDAD : “<<E.antiguedad; cout<<”\n SEXO : “<<E.sexo;
}
// PROCEDIMIENTO LEER LOS DATOS DE LOS EMPLEADOS EN UN VECTOR void Lee_N_Empleados (EMPLEADO VE[50], int N)
{ //llena el vector de empleados VE con registros de N empleados for (int i=1; i<= N; i++)
{ cout<<”\n INTRODUZCA LOS DATOS DEL EMPLEADO “<<i<<endl; VE[i]= LeeEmpleado();
} }
// PROCEDIMIENTO IMPRIMIR LOS DATOS DE LOS EMPLEADOS EN UN VECTOR void Imprime_N_Empleados (EMPLEADO VE[50], int N)
{ for (int i=1; i<= N; i++)
{ cout<<”\n EMPLEADO “<<i<<endl; ImprimeEmpleado( VE[i]);
} getch(); }
[Estructura de Datos] Page 19
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
1.8.3.
Funciones en el interior de estructuras:
C++, al contrario que C, permite incluir funciones en el interior de las estructuras. Normalmente estas funciones tienen la misión de manipular los datos incluidos en la estructura.
Aunque esta característica se usa casi exclusivamente con las clases, como veremos más adelante, también puede usarse en las estructuras.
Dos funciones muy particulares son las de inicialización, o constructor, y el destructor. Veremos con más detalle estas funciones cuando asociemos las estructuras y los punteros.
1.8.4.
Asignación de estructuras:
La asignación de estructuras está permitida, pero sólo entre variables del mismo tipo de estructura, salvo que se usen constructores, y funciona como la intuición dice que debe hacerlo.
Veamos un ejemplo:
La línea:
//PROGRAMA PRINCIPAL
void main (void) {
EMPLEADO ve[50]; int N;
clrscr( );
cout<<”\n Cuantos empleados desea registrar ?”; cin >>N; Leer_N_Empleados (ve , N); Imprimir_N_Empleados (ve, N); getch( ); } struct Punto { int x, y; Punto() {x = 0; y = 0;} } ;
Punto Punto1, Punto2; int main() { Punto1.x = 10; Punto1.y = 12; Punto2 = Punto1; }
[Estructura de Datos] Page 20
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
Punto2 = Punto1; equivale a:
Punto2.x = Punto1.x; Punto2.y = Punto1.y;
1.8.5.
Arrays de estructuras:
La combinación de las estructuras con los arrays proporciona una potente herramienta para el almacenamiento y manipulación de datos.
Ejemplo:
Vemos en este ejemplo lo fácil que podemos declarar el array Plantilla que contiene los datos relativos a doscientas personas.
Podemos acceder a los datos de cada uno de ellos:
cout << Plantilla[43].Direccion;
O asignar los datos de un elemento de la plantilla a otro:
Plantilla[0] = Plantilla[99];
1.8.6.
Estructuras anidadas:
También está permitido anidar estructuras, con lo cual se pueden conseguir superestructuras muy elaboradas.
struct Persona { char Nombre[65]; char Direccion[65]; int AnyoNacimiento; }; Persona Plantilla[200];
[Estructura de Datos] Page 21
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia Ejemplo:
Definiremos una estructura para persona con los datos: Nombre (nombre de pila, paterno, materno), Direccion (Calle, nro y zona) y telefono.
En general, no es una práctica corriente definir estructuras dentro de estructuras, ya que resultan tener un ámbito local, y para acceder a ellas se necesita hacer referencia a la estructura más externa.
Por ejemplo para declarar una variable del tipo stNombre hay que utilizar el operador de acceso (::):
stPersona::stNombre NombreAuxiliar;
Sin embargo para declarar una variable de tipo stDireccion basta con declararla:
stDireccion DireccionAuxiliar;
1.9. Conjuntos
El conjunto es también un tipo de dato estructurado. Puede definirse un conjunto como una colección de objetos del mismo tipo base. El tipo base puede ser solamente un tipo ordinal (enteros, caracteres, enumerados y subrangos).
struct stDireccion { char Calle[64]; int Nro; char Zona[32]; }; Struct stNombre { char nom[20]; char pat[20]; char mat[25]; }; struct stPersona { stNombre Nomb; stDireccion Direccion; long int Telefono; };
[Estructura de Datos] Page 22
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
1.9.1.
Definición De Conjuntos
Los conjuntos serán definidos de la siguiente manera:
Ident_conjunto = CONJUNTO DE tipo_base Donde:
Tipo_base es cualquier tipo ordinal de dato.
Ejemplo:
Se definen los conjuntos NUMEROS, MAYUSCULAS y ALUMNOS. NUMEROS es el tipo conjunto formado por todos los números enteros comprendidos entre el 1 y el 50 inclusive. MAYUSCULAS es el tipo conjunto formado por las letras mayúsculas, y finalmente ALUMNOS es el tipo conjunto formado por todos los elementos del tipo enumerado NOMBRES.
NOMBRES = (Juan, Jose, Julio,Javier) NUMEROS = CONJUNTO DE 1..50 MAYUSCULAS = CONJUNTO DE ‘A’..’Z’ ALUMNOS = CONJUNTO DE nombres
1.10.
Matrices Poco Densas
Matriz es un término matemático utilizado para definir un conjunto de elementos organizados por medio de renglones y columnas, equivalente al término arreglo bidimensional utilizado en computación.
Poco Densa indica una proporción muy alta de ceros entre los elementos de la matríz. Es
decir una matriz poco densa es aquella que tiene gran cantidad de elementos ceros.
Ejemplo:
La matriz A de 4 filas por 4 columnas, del total de elementos que es 16, solo 4 de ellos son diferentes de cero.
0 1 1 0 0 0 1 0 0 1 0 0 0 1 0 0 A =
[Estructura de Datos] Page 23
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
Existen diversos métodos para almacenar los valores diferentes de cero de una matríz poco densa. A continuación presentamos uno de ellos.
Arreglo de Registros
Se utiliza un arreglo unidimensional, donde cada elemento es un registro formado por tres campos: uno para guardar la fila donde se encontró el valor diferente de cero, otro para guardar la columna, y el tercero para guardar el valor del elemento distinto de cero de la matriz.
El siguiente programa nos permite registrar una matriz poco densa
#include<iostream.h> #include<conio.h> struct PocoDensa { int fila; int col; int valor; };
//PROCEDIMIENTO PARA LLENAR LA MATRIZ POCO DENSA
void LeePocoDensa( PocoDensa PD[20]) {
int F, C, k; int e;
cout<< “\n Cual es la dimensión de la matríz poco densa (filas y columnas) ”
cin>>M>>N; k=1;
for (int i= 1; i<= F; i++) for (int j=1; j<=C;j++)
{ cout<< “\n Ingrese el elemento ”<<i<<” “<<j<<” “; cin>>e; if (e != 0) { PD[k].fila = i; PD[k].col =j; PD[k].valor = e; k++; }
PD[0].fila = F ; PD[0].col = C; PD[0].valor= k-1; }
//PROGRAMA PRINCIPAL
void main (void) {
PocoDensa M[20]; //M es un vector de registros clrscr() ;
LeePocoDensa(M) ; getch() ;
[Estructura de Datos] Page 24
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
1.11.
Archivos
• El almacenamiento de datos en variables y arreglos es temporal; al terminar un programa todos estos datos se pierden. Para la conservación permanente de grandes cantidades de datos se utilizan los archivos.
• Las computadoras almacenan los archivos en dispositivos de almacenamiento secundario, especialmente en discos.
• C ve cada uno de los archivos simplemente como un flujo secuencial de bytes. Cada archivo termina con un marcador de fin de archivo.
• Abrir un archivo regresa un apuntador a una estructura FILE (definida en <stdio.h>) que contiene información utilizada para procesar dicho archivo.
Modos de apertura de archivos
w :Para crear un archivo, o para descartar el contenido de un archivo antes de escribir datos.
r :Para leer un archivo existente.
a :Para añadir registros al final de un archivo existente.
r+ :Para abrir un archivo de tal forma que pueda ser escrito y leído (abre un archivo de lectura y escritura para actualizar)
w+ :Genera un archivo para lectura y escritura. Si el archivo ya existe, se abre y el contenido se descarta
a+ :Abre un archivo para lectura y escritura - toda escritura se efectuará al final del archivo. Si no existe, será creado.
Si al abrir un archivo en cualquiera de los modos anteriores ocurre un error, fopen regresará NULL.
EJEMPLO
ARCHIVO DE TEXTO CREACION Y LECTURA. Lee y escribe en un archivo de texto de n números sus cubos.
[Estructura de Datos] Page 25
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
//ARCHIVOS DE TEXTO #include<iostream.h> #include<conio.h> #include<process.h> #include<stdio.h> FILE *Miarch; void crear(void) { int a,n; if ( (Miarch=fopen("C:\\prueba.dat","w"))==NULL) {
cout<<"no se puede abrir el archivo \n"; exit(1);
} else {
cout<<"Cuantos numeros quieres introducir al archivo "<<endl; cin>>n;
for (int i=1; i<=n; i++) { a=i*i*i; fprintf(Miarch,"\n %d %d",i,a); } fclose(Miarch); } } void leer(void) { int a,b; if ((Miarch=fopen("c:\\prueba.dat","r"))==NULL) {
cout<<"no se puede abrir el archivo "<<endl; exit(1); } else { cout<<"\n n n^3"; fscanf(Miarch,"%d%d",&a,&b); while (!feof(Miarch)) { cout<<"\n "<<a<<" "<<b; fscanf(Miarch,"%d%d",&a,&b); } fclose(Miarch); } } void main(void) { clrscr(); crear(); leer(); }
[Estructura de Datos] Page 26
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
// Ejemplo de ficheros de acceso aleatorio. #include <stdio.h>
#include <stdlib.h>
struct stRegistro {
char valido; // Campo que indica si el registro es válido S->Válido, N->Inválido char nombre[34];
int dato[4]; };
int Menu();
void Leer(struct stRegistro *reg); void Mostrar(struct stRegistro *reg);
void Listar(long n, struct stRegistro *reg); long LeeNumero();
void Empaquetar(FILE **fa);
int main() {
struct stRegistro reg; FILE *fa;
int opcion; long numero;
fa = fopen("alea.dat", "r+b"); // Este modo permite leer y escribir if(!fa) fa = fopen("alea.dat", "w+b"); // si el fichero no existe, lo crea. do {
opcion = Menu(); switch(opcion) {
case '1': // Añadir registro Leer(®);
// Insertar al final: fseek(fa, 0, SEEK_END);
fwrite(®, sizeof(struct stRegistro), 1, fa); break;
case '2': // Mostrar registro system("cls");
printf("Mostrar registro: "); numero = LeeNumero();
fseek(fa, numero*sizeof(struct stRegistro), SEEK_SET); fread(®, sizeof(struct stRegistro), 1, fa);
Mostrar(®); break;
case '3': // Eliminar registro system("cls");
printf("Eliminar registro: "); numero = LeeNumero();
fseek(fa, numero*sizeof(struct stRegistro), SEEK_SET); fread(®, sizeof(struct stRegistro), 1, fa);
reg.valido = 'N';
[Estructura de Datos] Page 27
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
fwrite(®, sizeof(struct stRegistro), 1, fa); break;
case '4': // Mostrar todo rewind(fa);
numero = 0; system("cls");
printf("Nombre Datos\n"); while(fread(®, sizeof(struct stRegistro), 1, fa)) Listar(numero++, ®);
system("PAUSE"); break;
case '5': // Eliminar marcados Empaquetar(&fa); break; } } while(opcion != '0'); fclose(fa); return 0; }
// Muestra un menú con las opciones disponibles y captura una opción del usuario int Menu() { char resp[20]; do { system("cls"); printf("MENU PRINCIPAL\n"); printf("---\n\n"); printf("1- Insertar registro\n"); printf("2- Mostrar registro\n"); printf("3- Eliminar registro\n"); printf("4- Mostrar todo\n");
printf("5- Eliminar registros marcados\n"); printf("0- Salir\n");
fgets(resp, 20, stdin);
} while(resp[0] < '0' && resp[0] > '5'); return resp[0];
}
// Permite que el usuario introduzca un registro por pantalla void Leer(struct stRegistro *reg)
{ int i; char numero[6]; system("cls"); printf("Leer registro:\n\n"); reg->valido = 'S'; printf("Nombre: "); fgets(reg->nombre, 34, stdin);
[Estructura de Datos] Page 28
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
// la función fgets captura el retorno de línea, hay que eliminarlo: for(i = strlen(reg->nombre)-1; i && reg->nombre[i] < ' '; i--) reg->nombre[i] = 0; for(i = 0; i < 4; i++) { printf("Dato[%1d]: ", i); fgets(numero, 6, stdin); reg->dato[i] = atoi(numero); } }
// Muestra un registro en pantalla, si no está marcado como borrado void Mostrar(struct stRegistro *reg)
{
int i;
system("cls");
if(reg->valido == 'S') {
printf("Nombre: %s\n", reg->nombre);
for(i = 0; i < 4; i++) printf("Dato[%1d]: %d\n", i, reg->dato[i]); }
system("PAUSE"); }
// Muestra un registro por pantalla en forma de listado, // si no está marcado como borrado
void Listar(long n, struct stRegistro *reg) {
int i;
if(reg->valido == 'S') {
printf("[%6ld] %-34s", n, reg->nombre);
for(i = 0; i < 4; i++) printf(", %4d", reg->dato[i]); printf("\n");
} }
// Lee un número suministrado por el usuario long LeeNumero() { char numero[6]; fgets(numero, 6, stdin); return atoi(numero); }
// Elimina los registros marcados como borrados void Empaquetar(FILE **fa)
{
FILE *ftemp;
struct stRegistro reg;
[Estructura de Datos] Page 29
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
Ejercicios Propuestos
ARREGLOS DE UNA DIMENSIÓN
1. Declare e inicialice un vector de N elementos de modo que los
componentes de indice par valgan 0 y los de indice impar valgan 1. Ejm. V(1,0,1,0, . . . . .)
2. Escriba un programa que almacene en un vector los N primeros números de Fibonacci. Una vez calculados, el programa los mostrará por pantalla en orden inverso.
3. Escriba un programa que almacene en un vector los N primeros números de Fibonacci. Una vez calculados, el programa pedirá al usuario que introduzca un número y dirá si es o no es uno de los N primeros números de Fibonacci.
4. Hallar la mediana, en el anterior planteado en la pagina 6 del texto
5. Modifica el programa anterior para que permita efectuar cálculos con N personas. 6. Modifica el programa del ejercicio anterior para que muestre, además, cuántas
edades hay entre 0 y 9 años, entre 10 y 19, entre 20 y 29, etc. Considera que ninguna edad es igual o superior a 150. Ejemplo: si el usuario introduce las siguientes edades correspondientes a 12 personas:
10 23 15 18 20 18 57 12 29 31 78 28
el programa mostrará (además de la media, desviación estándar, moda y mediana), la siguiente tabla:
rewind(*fa);
while(fread(®, sizeof(struct stRegistro), 1, *fa)) if(reg.valido == 'S')
fwrite(®, sizeof(struct stRegistro), 1, ftemp); fclose(ftemp); fclose(*fa); remove("alea.bak"); rename("alea.dat", "alea.bak"); rename("alea.tmp", "alea.dat"); *fa = fopen("alea.dat", "r+b"); }
[Estructura de Datos] Page 30
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia 0 - 9: 0 10 - 19: 5 20 - 29: 4 30 - 39: 1 40 - 49: 0 50 - 59: 1 60 - 69: 0 70 - 79: 1 80 - 89: 0 90 - 99: 0 100 - 109: 0 110 - 119: 0 120 - 129: 0 130 - 139: 0 140 - 149: 0
4 Modifica el programa para que muestre un histograma de edades. La tabla anterior se mostrará ahora como este histograma:
0 - 9: 10 - 19: ***** 20 - 29: **** 30 - 39: * 40 - 49: 50 - 59: * 60 - 69: 70 - 79: * 80 - 89: 90 - 99: 100 - 109: 110 - 119: 120 - 129: 130 - 139: 140 - 149:
Como puedes ver, cada asterisco representa la edad de una persona.
5 Modifica el programa anterior para que el primer y último rangos de edades mostrados en el histograma correspondan a tramos de edades en los que hay al menos una persona. El histograma mostrado antes aparecerá ahora así:
10 - 19: ***** 20 - 29: **** 30 - 39: * 40 - 49: 50 - 59: * 60 - 69: 70 - 79: *
6 Modifica el programa del ejercicio anterior para que muestre el mismo histograma de esta otra forma:
[Estructura de Datos] Page 31
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
| ####### | | | | | | | | ####### | ####### | | | | | | | ####### | ####### | | | | | | | ####### | ####### | | | | | | | ####### | ####### | ####### | | ####### | | ####### | +---+---+---+---+---+---+---+ | 10 – 19 | 20 - 29 | 30 – 39 | 40 – 49 | 50 – 59 | 60 - 69 | 70 – 79 |
7 Diseñe un programa que pida el valor de N números enteros distintos y los almacene en un vector. Si se da el caso, el programa advertirá al usuario, tan pronto sea posible, si introduce un número repetido y solicitará nuevamente el número hasta que sea diferente de todos los anteriores. A continuación, el programa mostrará los N números por pantalla
8 Diseñe un programa C que lea y almacene en un vector N números enteros
asegurándose de que sean positivos. A continuación, el programa pedirá que se introduzca una serie de números enteros y nos dirá si cada uno de ellos está o no en el vector. El programa finaliza cuando el usuario introduce un número negativo. Luego ordenar el vector, por el método de la burbuja.
9 En un arreglo se ha almacenado el número total de toneladas de cereales
cosechadas durante cada mes del año anterior. Se desea la siguiente información:
i. El promedio anual de toneladas cosechadas
ii. ¿Cuántos meses tuvieron una cosecha superior al promedio anual? iii. ¿Cuántos meses tuvieron una cosecha inferior al promedio
anual?Escriba un programa que proporcione estos datos.
ARREGLOS MULTIDIMENSIONALES
20. Escriba un programa que intercambie por renglón los elementos de un arreglo
bidimensional. Los elementos del renglón 1 deben intercambiarse con los del renglón N, los del renglón 2 con los del N-1, y así sucesivamente.
21. Escriba un programa que asigne valores a A, a partir de B teniendo en cuenta los
siguientes criterios:
iv. Aij = (bi) si i <= j
[Estructura de Datos] Page 32
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia REGISTROS
22. Una compañía distribuye N productos a distintos comercios de la ciudad. Para
ellos almacena en un arreglo toda la información relacionada con su mercancía: • Clave
• Descripción • Existencia
• Mínimo a mantener de existencia • Precio unitario
Escriba un programa que pueda llevar a cabo las siguientes operaciones:
a) Venta de un producto: se deben actualizar los campos que correspondan, y verificar que la nueva existencia no esté por debajo del mínimo. (datos: clave, cantidad_vendida)
b) Reabastecimientos de un producto: se deben actualizar los campos que
correspondan. (Datos: clave, cantidad comprada)
c) Actualizar el precio de un producto: se deben proporcionar todos los datos
[Estructura de Datos] Page 33
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
Capítulo II
Pilas
2.1. Introducción
La pila es una lista de elementos caracterizada porque las operaciones de inserción y eliminación se realizan solamente en un extremo de la estructura. El extremo donde se realizan estas operaciones se denomina habitualmente 'cima' o tope (top en nomenclatura inglesa).
Dada una pila P = (a, b, c, ... k ), se dice que a, es el elemento más inaccesible de la pila, está en el fondo de la pila (bottom) y que k, por el contrario, el más accesible, está en el
Tope.
Las restricciones definidas para la pila implican que si una serie de elementos A, B, C, D, E se añaden, en este orden a una pila, entonces el primer elemento que se borre de la estructura deberá ser el E. Por tanto, resulta que el último elemento que se inserta en una pila es el primero que se borra. Por esta razón, se dice que una pila es una lista LIFO (Last Input First Output, es decir, el último que entra es el primero que sale).
Un ejemplo típico de pila lo constituye un montón de platos, cuando se quiere introducir un nuevo plato, éste se pone en la posición más accesible, encima del último plato. Cuando se coge un nuevo plato, éste se extrae, igualmente, del punto más accesible, el último que se ha introducido.
El pequeño pez
"Usted perdone", le dijo un pez a otro, "es usted más viejo y con más experiencia que yo
y probablemente podrá usted ayudarme. Dígame: ¿dónde puedo encontrar eso que llaman Océano? He estado buscándolo por todas partes, sin resultado".
"El Océano", respondió el viejo pez, "es donde está ahora mismo".
"¿Esto? Pero si esto no es más que agua... Lo que yo busco es el Océano, replicó el joven pez,
totalmente decepcionado, mientras se marchaba nadando a buscar en otra parte.
Deja de buscar, pequeño pez. No hay nada que buscar. Sólo tienes que estar tranquilo, abrir tus ojos y mirar.
No puedes dejar de verlo.
[Estructura de Datos] Page 34
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
Una pila de papeles Una pirámide de personas
Otro ejemplo natural de la aplicación de la estructura pila aparece durante la ejecución de un programa de ordenador, en la forma en que la máquina procesa las llamadas a los procedimientos. Cada llamada a un procedimiento (o función) hace que el sistema almacene toda la información asociada con ese procedimiento (parámetros, variables, constantes, dirección de retorno, etc..) de forma independiente a otros procedimientos y permitiendo que unos procedimientos puedan invocar a otros distintos (o a si mismos) y que toda esa información almacenada pueda ser recuperada convenientemente cuando corresponda.
Como en un procesador sólo se puede estar ejecutando un procedimiento, esto quiere decir que sólo es necesario que sean accesibles los datos de un procedimiento (el último activado que está en la cima). De ahí que la estructura pila sea muy apropiada para este fin.
Como en cualquier estructura de datos, asociadas con la estructura pila existen una serie de operaciones necesarias para su manipulación, éstas son:
a. Crear la pila.
b. Comprobar si la pila está vacía. Es necesaria para saber si es posible eliminar elementos.
c. Acceder al elemento situado en la cima.
d. Añadir elementos a la cima.
e. Eliminar elementos de la cima.
La especificación correcta de todas estas operaciones permitirá definir adecuadamente una pila.
2.2. Representación de Las Pilas
Las pilas no son estructuras fundamentales de datos, es decir, no están definidas como tales en los lenguajes de programación (como lo están por ejemplo los arreglos). Las pilas pueden representarse mediante el uso de:
[Estructura de Datos] Page 35
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
• Arreglos
• Listas Enlazadas
Aquí se utilizarán arreglos. En consecuencia deberá definirse cuál será el tamaño máximo de la pila, y además una variable auxiliar a la que se denominará TOPE, que será un apuntador al último elemento insertado en la pila. En la figura siguiente se presentan dos alternativas de representación de una pila, utilizando arreglos.
2.3. Estructura de una Pila utilizando Arreglos
Donde los elementos son:
V[MAX]:es el vector que representa a la pila y es de tamaño de la pila. Tope: es la varible que indica la posición del ultimo elemento de la pila. Y las operaciones como se describen a continuación.
2.4. Operaciones
Con
Pilas
La definición de una estructura de datos queda completa al incluir las operaciones que se pueden realizar en ella. Las operaciones principales con pilas son:
444 222 434 555 555 434 222 4444 PILA = PILA 1 2 3 4 … MAX TOPE MAX 4 3 2 1 E TOPE PILA V[MAX]: tipo_dato Tope: entero Poner(e) Quitar() Imprimir() Vacia() Llena() Nombre del TAD
elementos
[Estructura de Datos] Page 36
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
• Pone (e) un elemento en la pila (push) • Quita () un elemento de la pila (pop)
• Llena() verifica si la pila esta llena, si es asi, retorna el valor verdad, caso contrario falso.
• Vacia() verifica si la pila esta vacia, si es asi, reotrna el valor verdad, caso contrario falso.
• Imprime() Permite imprimir todos los elementos de la pila desde el tope hasta el fondo de la pila.
2.5. Implementación del TAD pila en lenguaje java
//clase pila y sus operaciones import java.io.*;
public class Pila {
private final int MAX = 20; private int v[] = new int [MAX]; private int tope;
Pila () {
tope = 0;
System.out.println ("PILA CREADA..."); } boolean vacia () { if (tope == 0) return (true); else return (false); } boolean llena () { if (tope == MAX) return (true); else return (false); }
[Estructura de Datos] Page 37
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
void poner (int elem) {
if (llena ())
System.out.println ("PILA LLENA..."); else { tope++; v [tope] = elem; } } int quitar () { int elem = 0; if (vacia ())
System.out.println ("PILA VACIA..."); else { elem = v [tope]; tope--; } return (elem); } void imprimir () {
System.out.println ("...IMPRIMIENDO LA PILA..."); for (int i = tope ; i >= 1 ; i--)
System.out.println (v [i]); }
void llenarPila () {
int n, e;
System.out.println ("cuantos elementos ??..."); n = Lectura.Entero ();
for (int i = 1 ; i <= n ; i++) { System.out.print ("elemento?... "); e = Lectura.Entero (); poner (e); } } }
[Estructura de Datos] Page 38
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
Ejercicios con pilas
a. Sumar dos pilas del mismo tamaño.
//sumar dos pilas del mismo tamaño class EjPila1
{
static Pila P1 = new Pila (); static Pila P2 = new Pila (); static Pila P3 = new Pila ();
static void sumarPilas (Pila A, Pila B, Pila C) { int e, f; while (!A.vacia ()) { e = A.quitar (); f = B.quitar (); C.poner (e + f); } }
public static void main (String args[]) { P1.llenarPila (); P2.llenarPila (); P1.imprimir (); P2.imprimir (); sumarPilas (P1, P2, P3); P3.imprimir (); } }
[Estructura de Datos] Page 39
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
b. Eliminar los elementos negativos de una pila.
//ELIMINAR ELEMENTOS NEGATIVOS DE LA PILA class EjPila2
{
static Pila P = new Pila ();
static void EliminaNegativos (Pila A) {
Pila aux = new Pila (); int e;
System.out.println ("Eliminando Elementos Negativos de la Pila..."); while (!A.vacia ()) { e = A.quitar (); if (e > 0) aux.poner (e); } while (!aux.vacia ()) { e = aux.quitar (); A.poner (e); } }
public static void main (String args[]) { P.llenarPila (); P.imprimir (); EliminaNegativos (P); P.imprimir (); } }
[Estructura de Datos] Page 40
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
c. Realizar un procedimiento para intercalar los elementos de una pila A con los elementos de una pila B en una pila C. Es decir:
C = 3 4 77 89 23 11 44 33 89 33 77 44 4 11 3 23 A = B = 1 2 3 4 5 1 2 3 4 5 TOPE TOPE 1 2 3 4 5 6 7 8 TOPE
//intercalar los elementos de una pila A con los elementos de una pila B //en una pila c
class EjPila3 {
static Pila p1 = new Pila (); static Pila p2 = new Pila ();
static void Intercala (Pila A, Pila B) {
Pila aux = new Pila (); int e;
System.out.println ("****** INTERCALANDO LA PILA *********"); while (!A.vacia ()) { e = A.quitar (); aux.poner (e); e = B.quitar (); aux.poner (e); } aux.imprimir (); }
public static void main (String args[]) { p1.llenarPila (); p2.llenarPila (); p1.imprimir (); p2.imprimir (); Intercala (p1, p2); } }
[Estructura de Datos] Page 41
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
2.6. Aplicaciones
Las pilas son una estructura de datos muy usada en la solución de diversos tipos de problemas. Ahora se verán algunos de los casos más representativos de aplicación de pilas:
• Llamadas a subprogramas • Recursión
• Tratamiento de expresiones aritméticas • Ordenación
2.6.1. Llamadas a subprogramas
Cuando se tiene un programa que llama a un subprograma, internamente se usan pilas para guardar el estado de las variables del programa en el momento que se hace la llamada. Así, cuando termina la ejecución del subprograma, los valores almacenados en la pila pueden recuperarse para continuar con la ejecución del programa en el punto en el cual fue interrumpido. Además de las variables debe guardarse la dirección del programa en la que se hizo la llamada, porque es a esa posición a la que regresa el control del proceso.
Por ejemplo, se tiene un programa principal (PP) que llama a los subprogramas UNO y DOS. A su vez, el subprograma DOS llama al subprograma TRES. Cada vez que la ejecución de uno de los subprogramas concluye, se regresa el control al nivel inmediato superior.
Cuando el programa PP llama a UNO, se guarda en una pila la posición en la que se hizo la llamada. Al terminar UNO, el control se regresa a PP recuperando previamente la dirección de la pila. Al llamar a DOS, nuevamente se guarda la dirección de PP en la pila. Cuando DOS llama a TRES, se pone en la pila la dirección de DOS. Después de procesar TRES, se recupera la posición de DOS para continuar con su ejecución. Al terminar DOS se regresa el control a PP, obteniendo previamente la dirección guardada en la pila.
[Estructura de Datos] Page 42
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
PP
UNO DOS
TRES
Finalmente podemos concluir que las pilas son necesarias en esta área de aplicaciones por lo siguiente:
• Permiten guardar la dirección del programa (subprograma) desde donde se hizo la llamada a otros subprogramas, para poder regresar y seguir ejecutándolo a partir de la instrucción inmediata a la llamada.
• Permiten guardar el estado de las variables en el momento que se hace la llamada, para poder seguir ocupándolas al regresar del subprograma.
… UNO …. DOS …. … … …. … …. TRES …. … …. …. PP 5 4 3 2 1 TOPE PP 5 4 3 2 1 TOPE 5 4 3 2 1 0 PP 5 4 3 2 1 TOPE PP 5 4 3 2 1 DOS PP 5 4 3 2 1 TOPE PP 5 4 3 2 1 PP 5 4 3 2 1 TOPE PP 5 4 3 2 1 5 4 3 2 1 0 TOPE
[Estructura de Datos] Page 43
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
2.6.2. Recursión
Se Tratará en el tema 5 el tema de recursión. Se dejará para entonces la aplicación de pilas en procesos recursivos.
2.6.3. Tratamiento de expresiones aritméticas
Un problema interesante en computación es poder convertir expresiones en notación infija a su equivalente en notación postfija.(o prefija). Revisaremos algunos conceptos:
• Dada la expresión A+B se dice que está en notación infija, y su nombre se debe a que el operador (+) está entre los operandos ( A y B).
• Dada la expresión AB+ se dice que está en notación postfija, y su nombre se debe a que el operador (+) está después de los operandos (A y B).
• Dada la expresión +AB se dice que está en notación prefija, y su nombre se debe a que el operador (+) está antes que los operando (A y B).
• La ventaja de usar expresiones en notación polaca postfija o prefija radica en que no son necesarios los paréntesis para indicar orden de operación, ya que éste queda establecido por la ubicación de los operadores con respecto a los operandos.
• Para convertir una expresión dada en notación infija a una notación postfija (o prefija) deberán establecerse previamente ciertas condiciones:
• Solamente se manejarán los siguientes operadores (están dados ordenadamente de mayor a menor según su prioridad de ejecución):
^ (potencia)
* / (multiplicación y división) + - (suma y resta)
• Los operadores de más alta prioridad se ejecutan primero.
• Si hubiera en una expresión dos o más operadores de igual prioridad, entonces se procesarán de izquierda a derecha.
• La subexpresiones patentizadas tendrán más prioridad que cualquier operador. • Presentaremos, paso a paso, algunos ejemplos de conversión de expresiones
infijas a notación polaca postfija.
EJEMPLO
En este ejemplo se presentan dos casos de traducción de notación infija a postfija. El primero de ellos es una expresión simple, mientras que el segundo presenta un mayor grado de complejidad.
[Estructura de Datos] Page 44
Lic. Katya Perez Martinez &Lic. Gladys Chuquimia
a) expresión infija: X + Z * W X + [ZW*]
Expresión postfija XZW*+
b) transformamos a notación prefija la misma expresión anterior X + Z * W
X + [* Z W]
Notación prefija + X*ZW
EJERCICIOS PROPUESTOS
3. Traduzca las siguietes expresiones a notación postfija utilizando el algoritmo de evaluación.
3.1. X*(Z+W)/(T-V) 3.2. Z-W*Y+XˆK 3.3. W*(Z/(K-T))
4. Realizar un programa para hallar el mayor elemento de una pila P.
5. Realizar un procedimiento para intercambiar el último elemento de la pila por el primer elemento.
6. Escriba un programa que elimine los elementos repetidos de una pila. Los elementos repetidos ocupan posiciones sucesivas.
7. Escriba un subprograma que invierta los elementos de una pila. 8. Insertar n elementos después al fondo de una pila que ya tiene datos. 9. Eliminar los elementos divisores de X de la pila
10. Intercambiar cada elemento de la pila con su adyacente. 11. eliminar el primer elemento par de la pila
12. Hallar la frecuencia de repetición de cada elemento de la pila 13. Apilar los elementos de la pila B sobre la pila A.
14. Insertar el elemento X en una pila cuyos elementos estan ordenados en forma ascendente desde el fondo hasta el tope. La pila debe quedar ordenada
15. Escriba un programa que lea una expresión en notación infija, y la traduzca anotación postfija.