Apuntes de Estructuras de Datos

Anuncio
Apuntes de Estructuras de Datos
Matias Valdenegro T.
2 de marzo de 2006
2
Índice general
1. Introduccion a C++
1.1. Diferencias con C . . . . . . .
1.2. Nuevos Tipos de Datos . . . .
1.3. Manejo de Memoria Dinamica
1.4. Flujos . . . . . . . . . . . . .
1.5. Sobrecarga de Funciones . . .
1.6. Parametros por Defecto . . .
1.7. Plantillas . . . . . . . . . . .
1.8. Referencias . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5
5
5
5
6
7
7
8
9
2. Programacion Orientada a Objetos
11
2.1. Fundamentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.2. Implementacion en C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.3. Plantillas de Clases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3
ÍNDICE GENERAL
ÍNDICE GENERAL
4
Capı́tulo 1
Introduccion a C++
1.1.
Diferencias con C
C++ podria considerarse una version mas moderna y mejorada de C++, ya que este ultimo contiene un conjunto
de ayudas a la programacion que C no tiene.
Entre las diferencias y semejanzas mas importantes, estan :
El codigo en C se puede compilar con el Compilador de C++.
Se pueden llamar funciones escritas en C, desde C++.
Los tipos de datos se mantienen, y se agregan el tipo de dato bool.
C++ tiene un nuevo sistema de memoria dinamica, que es mas facil de usar.
C++ permite el uso de Tecnicas de Programacion Orientada a Objetos (POO) a travez del uso de clases.
1.2.
Nuevos Tipos de Datos
Normalmente en C, si uno deseaba retornar un valor de exito o fracaso en alguna funcion, generalmente se
declaraba dicha funcion con tipo de retorno int y se retornaba el valor 1 en el caso de exito, y 0 en el caso de un
fracaso.
En C++, esto ya no es necesario, ya que el lenguaje incorpora el tipo de dato bool, que corresponde a una
variable de valor booleano, con valores true y false, lo cual facilita la lectura del codigo.
1.3.
Manejo de Memoria Dinamica
En C++ el manejo de Memoria Dinamica, es basicamente el mismo, pero tiene ciertas diferencias que lo hacen de
mas facil uso.
Entre estas diferencias, tenemos :
Las peticiones de memoria dinamica se realizaran usando el operador new y liberaremos memoria usando el
operador delete.
No necesitaremos calcular los tamanos de las estructuras de datos, ya que el compilador realizara esto
automaticamente.
El formato del uso de los operadores new y delete es :
5
1.4. FLUJOS
CAPÍTULO 1. INTRODUCCION A C++
Tipo ∗ p u n t e r o = new Tipo ;
delete p u n t e r o ;
Tipo ∗ p u n t e r o = new Tipo [ 1 0 ] ;
delete [ ] p u n t e r o ;
A diferencia del uso de malloc() y free(), no es necesario especificar el tamano de los tipos de datos, y ademas se
usa el mismo operador para solicitar un trozo de memoria, como para solicitar un arreglo de trozos de memoria.
La unica diferencia es que el operador delete requiere unos corchetes a continuacion de este en el caso de liberar
memoria que corresponde a un arreglo, de lo contrario se producen problemas y los llamados ”Memory Leaks”.
1.4.
Flujos
En C, nosotros usamos la funcion printf() para imprimir mensajes hacia la consola o interfaz de modo texto del
sistema operativo. En C++, esta funcion todavia se puede usar, pero existe una mejor forma, mas facil de usar, de
imprimir mensajes en pantalla.
Un flujo es una abstraccion de la comunicacion entre el teclado y la pantalla, ya que estos se comunican con flujos
o ”streams” de caracteres que van en una cierta direccion, y el dispositivo correspondiente interpreta.
Todo eso es teoria, en la practica, esto se refleja en que C++ contiene dos nuevos operadores, llamados operadores
de insercion y extraccion, y corresponden a ”((” y ”))”, dichos operadores se pueden usar para insertar ((() un dato
en un cierto flujo, con lo que imprimimos mensajes en pantalla.
))Equivalentemente, con el operador )) se extraen datos de un flujo, con lo que ingresamos datos desde el teclado.
Todos estos operadores se pueden usar con cualquier tipo de dato, y no requieren la memorizacion de ciertos
codigos como era necesario con prinf y scanf.
El flujo de entrada se llama cin y el de salida se llama cout, y son simples variables con las que podemos usar los
operadores (( y )).
Suficiente teoria, vamos a los ejemplos:
#include <i o s t r e a m >
int numero = 9 5 ;
f l o a t otronumero = 3 . 1 4 1 5 ;
c o u t << ” Mensaje ” ;
c o u t << ” Mensaje ” << numero << otronumero ;
/∗ Imprime ” Mensaje ” en l a P a n t a l l a ∗/
/∗ Tambien podemos c o n c a t e n a r v a r i o s ∗/
/∗ f l u j o s en l a misma d i r e c c i o n . ∗/
int e n t r a d a ;
float otraentrada ;
c i n >> e n t r a d a ;
c i n >> o t r a e n t r a d a ;
/∗ Entrada por t e c l a d o de un numero e n t e r o ∗/
/∗ Entrada por t e c l a d o de un numero r e a l . ∗/
int a , b , c ;
c i n >> a >> b >> c ;
/∗ Tambien podemos c o n c a t e n a r . ∗/
6
CAPÍTULO 1. INTRODUCCION A C++
1.5.
1.5. SOBRECARGA DE FUNCIONES
Sobrecarga de Funciones
En C, si declaramos dos funciones con el mismo nombre, aunque estan usen parametros diferentes, se produce un
error de compilacion, ya que el compilador de C no puede diferenciarlas. Esto en muchos casos representa una
desventaja, ya que se necesitan usar funciones que operen en diferentes tipos de datos, pero que hagan la misma
operacion.
En C++, podemos usar la caracteristica de poder Sobrecargar funciones, y que corresponde a declarar y usar
funciones con el mismo nombre, pero con diferente numero, tipo y orden de parametros en su declaracion y uso.
Podemos demostrarlo con el siguiente ejemplo :
int f u n c i o n ( int a )
{
return a ∗ a ;
}
float funcion ( float a)
{
return a ∗ a ;
}
int a = f u n c i o n ( 2 ) ;
float b = funcion ( 4 . 0 ) ;
En este caso, el compilador selecciono automaticamente la primera funcion al llamarla con el parametro entero 2,
y en la segunda llamada, selecciono la segunda funcion al ser llamada con el parametro float.
Que sucede si llamamos la funcion con otros parametros? Se producira un error en el momento de compilacion,
indicandonos las versiones sobrecargadas de la funcion que podremos usar. Lo mismo ocurrira si llamamos la
funcion con parametros en el orden incorrecto, o si la llamada de esta es ambigua.
La ambiguedad se produce cuando mas de una funcion puede ser llamada dado los parametros que se les han
pasado a esta. Esto solo deberia ocurrir cuando se usen Clases con Herencia, lo que se estudiara mas adelante.
1.6.
Parametros por Defecto
Nuevamente en el topico de las funciones, podemos hacer que estas tengan valores ”por defecto” para sus
parametros, en el caso de que estos no esten especificados, creando la posibilidad de llamar la funcion. Mejor
pongamos un ejemplo :
float funcion ( float a = 0.0)
{
return a / 2 . 0 + a ∗ 2 . 0 ;
}
float x = funcion ( ) ;
/∗ Asume a = 0 . 0 ∗/
f l o a t y = f u n c i o n ( 2 . 0 ) ; /∗ Asume a = 2 . 0 ∗/
Como se ve en el ejemplo, la funcion que hemos definido toma solo un parametro, que tiene un valor por defecto
de 0.0, y por ende podemos llamar la funcion sin parametros, y inmediatamente el parametro a tomara el valor
por defecto que es 0.0, y en caso contrario se usara el valor del parametro que se especifique.
Multiples parametros por defecto estan permitidos, pero tienen el detalle de que estos deben aparecer al final de la
lista de parametros de la funcion, ya que de lo contrario, seria imposible especificar ciertos parametros sin tener
7
1.7. PLANTILLAS
CAPÍTULO 1. INTRODUCCION A C++
que especificar otros.
Por ejemplo :
void f u n c i o n ( int a , char ∗ s t r i n g = ” Hola ” , double numero = 1 . 0 )
{
// Codigo de l a f u n c i o n .
}
funcion ( 3 ) ;
f u n c i o n ( 3 , ”Chao” ) ;
f u n c i o n ( 3 , ”Chao” , 1 . 0 ) ;
/∗ Llamada v a l i d a . ∗/
/∗ Llamada v a l i d a . ∗/
/∗ Llamada v a l i d a . ∗/
void o t r a f u n c i o n ( int a , int b = 0 , f l o a t c )
{
// Codigo de l a f u n c i o n .
}
otrafuncion (1 , 2 , 3 . 0 ) ;
otrafuncion (1);
otrafuncion (1 , 1 . 0 ) ;
1.7.
/∗ Unica l l a m a d a v a l i d a . ∗/
/∗ Llamada no v a l i d a . ∗/
/∗ Llamada no v a l i d a . ∗/
Plantillas
Las Plantillas se aplican a funciones y a Clases, por el momento solo veremos Plantillas de Funciones. Plantillas de
Clases se vera en el Capitulo de Programacion Orientada a Objetos.
La razon de ser de las Plantillas, es soportar la llamada Programacion Generica, termino que corresponde a crear
funciones que toman tipos de datos genericos, de modo que estas funciones puedan ser usadas con distintos tipos
de datos diferentes, sin necesidad de reescribir el codigo.
La declaracion y implementacion de una funcion Plantilla, es la siguiente:
template <c l a s s T> t i p o −r e t o r n o nombrefuncion ( pa r a m e t ro s )
{
/∗ Codigo de l a Funcion , puede u s a r T como e l nombre d e l t i p o g e n e r i c o . ∗/
}
En el caso de requerir una Funcion Plantilla que requiera mas de un tipo generico, la declaracion es :
template <c l a s s A, c l a s s B, c l a s s C> t i p o −r e t o r n o nombrefuncion ( pa r a m e t ro s )
{
/∗ Codigo de l a Funcion , puede u s a r A, B o C como
e l nombre de l o s t i p o s g e n e r i c o s . ∗/
}
Obviamente, el nombre del Tipo Generico no debe ser necesariamente T, A, B o C, y puede ser cualquier
combinacion de caracteres.
Un muy buen ejemplo del uso de Funciones Plantillas, son los algoritmos de Ordenacion que se vieron en el curso
de Programacion:
void i n t e r c a m b i a r ( int a [ ] , int i , int j )
{
int temp = a [ i ] ;
a[ i ] = a[ j ];
8
CAPÍTULO 1. INTRODUCCION A C++
1.8. REFERENCIAS
a [ j ] = temp ;
}
void b u b b l e S o r t ( int a [ ] , int n )
{
int i , j ;
f o r ( i = 0 ; i < n ; i ++) {
f o r ( j = n ; j > i ; j −−) {
i f ( a [ j −1] > a [ j ] )
i n t e r c a m b i a r ( a , j −1, j ) ;
}
}
}
Este codigo funciona perfectamente con arreglos de Numeros Enteros, pero que sucede si deseamos ordenar un
arreglo de float o de double? O con alguna estructura que nosotros hemos definido? En C tendriamos que crear
una funcion que tenga basicamente el mismo codigo, pero solo diferentes tipos, y ademas diferente nombre.
En C++, podriamos traducir el codigo a una funcion plantilla:
template <c l a s s T>
void i n t e r c a m b i a r (T a [ ] , int i , int j )
{
T temp = a [ i ] ;
a[ i ] = a[ j ];
a [ j ] = temp ;
}
template <c l a s s T>
void b u b b l e S o r t (T a [ ] , int n )
{
int i , j ;
f o r ( i = 0 ; i < n ; i ++) {
f o r ( j = n ; j > i ; j −−) {
i f ( a [ j −1] > a [ j ] )
i n t e r c a m b i a r ( a , j −1, j ) ;
}
}
}
El codigo es exactamente el mismo, solo que en lugar de aceptar un arreglo de Enteros, esta funcion acepta un
arreglo de ”Ts”, que es nuestro Tipo Generico, y podemos realizar codigo como el siguiente:
int a [ ] = { 2 , 9 , 6 , 8 , 1 , 3}
float b [ ] = {2.0 , 4.0 , 9.0 , 1.0 , 6.0 , 0.0}
bubbleSort (a , 6 ) ;
bubbleSort (b , 6 ) ;
/∗ En e s t e caso , T = i n t ∗/
/∗ En e s t e caso , T = f l o a t ∗/
Notese que el compilador realiza practicamente todo el trabajo, y selecciona y compila las funciones que requiere.
Ademas no necesitamos especificar el tipo de dato que queremos usar con nuestra funcion, ya que este se detecta
automaticamente. De hecho, se llaman igual que cualquier otra funcion.
1.8.
Referencias
Todos sabemos que en el caso de que necesitemos que una funcion modifique uno o varios de sus parametros, esto
requiere que dichos parametros se pasen a la funcion como punteros. Mucha gente tiene problemas con punteros,
9
1.8. REFERENCIAS
CAPÍTULO 1. INTRODUCCION A C++
se confunden simplemente. Gracias a dios, en C++ existe una forma mas ”elegante” de pasar parametros por
referencia, y consiste en usar las llamadas ”Referencias”.
La forma de declarar que una funcion toma una referencia a un cierto parametro, es usar un & (ampersand) de la
misma forma que se declaran punteros a parametros, pero con la diferencia, que dentro del codigo de la funcion, el
parametro se usa de la forma normal, osea podemos asignar a este, y la variable referenciada automaticamente
cambia.
Por ejemplo :
void i n t e r c a m b i o ( int &a , int &b )
{
int temp = a ;
a = b;
b = temp ;
}
int i = 2 , j = 3 ;
intercambio ( i , j ) ;
/∗ Ahora , i = 3 y j = 2 ∗/
Despues de ver este codigo, la ventaja de las Referencias sobre el uso de Punteros es bastante evidente.
10
Capı́tulo 2
Programacion Orientada a Objetos
2.1.
Fundamentos
2.2.
Implementacion en C++
2.3.
Plantillas de Clases
11
Descargar