La implementación de Secuencia recoge los elementos que vimos en las implementaciones de Arreglo y Conjunto, hay solo tres nuevos elementos de C++: herencia de excepciones, funciones amigas en plantillas y sobrecarga del operador <<, pero antes veamos el código:
secuencia.h
Autor: L. Alejandro Bernal R.
Fecha: 2000.12.03
*/
#ifndef _SECUENCIA_H_
#define _SECUENCIA_H_
#include <stdio.h>
#include <iostream.h>
/*
TDA Secuencia
Descripción: Una secuencia es un conjunto de elementos del mismo tipo que guardan un orden.
Invariante: Secuencia=<elem[0],...,elem[n-1]> y (Para todo i,0 <= i < n,elem[i] pertenece a TipoB)
*/
template<class TipoB>
class Secuencia
{
private:
// Atributos:
TipoB *elem; // Elementos de la secuencia.
int num; // Número de elementos en la secuencia.
public:
// Excepciones:
class Excepcion { }; // Excepcion general.
class NoHayMemoria : public Excepcion { }; // Excepción: No hay memoria.
class FueraDeRango : public Excepcion { }; // Excepción: Fuera de rango.
// Operaciones:
/*
Operación Secuencia
Descripción: Construlle una secuencia vácia.
Descripción operacional: Secuencia: -> Secuencia
Precondición: verdadero
Poscondición: Secuencia=<>
*/
Secuencia() { num = 0; elem = NULL; }
/*
Operación Secuencia
Descripción: Construlle una secuencia basandose en otra.
Descripción operacional: Secuencia: -> Secuencia
Precondición: otra pertenece a Secuencia
Poscondición: Secuencia=otra
*/
Secuencia(Secuencia<TipoB> &otra);
/*
Operación Secuencia
Descripción: Destrulle la secuencia.
Descripción operacional: Secuencia: ->
Precondición:
Poscondición:
*/
Secuencia() { delete elem; }
/*
Operación: =
Descripción: Asigna (copia) la secuencia fuente.
Descripcion operacional: =: Secuencia x Secuencia -> Secuencia
Precondición: fuente pertenece a Secuencia
Poscondición: secuencia=fuente
*/
Secuencia<TipoB> &operator = (Secuencia otra);
/*
Operación tam
Descripción: Dice el tamaño de la secuencia.
Descripción operacional: tam: Secuencia -> N
Precondición:
Poscondición: tam=n
*/
int tam() { return num; }
/*
Operación []
Descripción: Selecciona el elemento de la posición i.
Descripción operacional: []: Secuencia x N -> TipoB
Precondición: i pertenece a N y 0 <= i < n
Poscondición: []=elem[i]
*/
TipoB &operator [](int i);
/*
Operación insd
Descripción: Inserta después de la posición i.
Descripción operacional: ins: Secuencia x TipoB -> Secuencia
Precondición: secuencia=<elem[0],...,elem[i],ele[i+1],...,elem[n-1]> y nuevo pertenece a TipoB y -1 <= i <= n
Poscondición: secuencia=<elem[0],elem[i],nuevo,elem[i+1],...,elem[n-1]>
*/
void ins(TipoB nuevo, int i);
/*
Operación add
Descripción: Adiciona un nuevo elemento al final del la secuencia.
Descripción operacional: add: Secuencia x TipoB -> Secuencia
Precondición: secuencia=<elem[0],...,elem[n-1]> y nuevo pertenece a TipoB
Poscondición: secuencia=<elem[0],...,elem[n-1],nuevo>
*/
void add(TipoB nuevo) { ins(nuevo, num - 1); }
/*
Operación eliminar
Descripción: Elimina el elemento de la posición i.
Descripción operacional: eliminar: Secuencia x N -> Secuencia
Precondición: secuencia=<elem[0],...,elem[i-1],elem[1],elem[i+1],...,elem[n-1]> y 0 <= i < n
Poscondición: secuencia=<elem[0],...,elem[i-1],elem[i+1],\cdots ,elem[n-1]>
*/
void eliminar(int i);
/*
Operación donde
Descripción: Retorna la posición del elemento en la secuencia. Si no está retorna -1.
Descripción operacional: donde: Secuencia x TipoB -> N
Precondición: el pertenece a TipoB
Poscondición: (Existe un i,elem[i]=el) => donde=i ó (Para todo i,elem[i] != el) => donde=-1
*/
int donde(TipoB el);
/*
Operación +
Descripción: Une dos secuencias en una tercera, en ésta aparecen primero los elementos de la secuencia inicial y segundos los de la otra secuencia.
Descripción operacional: +: Secuencia x Secuencia -> Secuencia
Precondición: secuencia=<elem[0],...,elem[n-1]> y otra=<el[0],...,el[m-1]>
Poscondición: +=<elem[0],...,elem[n-1],el[0],...,el[m-1]>
*/
Secuencia<TipoB> operator +(Secuencia<TipoB> otra);
/*
Operación <<
Descripción: Imprime la secuencia en un stream.
Descripción operacional: <<: ostream x Secuencia -> ostream
Precondición: is pertenece a ostream y sec pertenece a Secuencia
Poscondición: ostream=<'<',elem[0], ',' ,..., ',' ,elem[n-1]>
*/
template<class TipoB>
friend ostream &operator << (ostream &is, Secuencia<TipoB> sec);
}; // class Secuencia
// Operaciones:
/*
Operación Secuencia
Descripción: Construlle una secuencia basandose en otra.
Descripción operacional: Secuencia: -> Secuencia
Precondición: otra pertenece a Secuencia
Poscondición: Secuencia=otra
*/
template<class TipoB>
Secuencia<TipoB>::Secuencia(Secuencia<TipoB> &fuente)
{
num = fuente.num;
elem = new TipoB[num];
// Si no hay memoria
if(elem == NULL){
throw NoHayMemoria();
}
for(int i = 0; i < num; i++){
elem[i] = fuente.elem[i];
}
}
/*
Operación: =
Descripción: Asigna (copia) la secuencia fuente.
Descripcion operacional: =: Secuencia x Secuencia -> Secuencia
Precondición: fuente pertenece a Secuencia
Poscondición: secuencia=fuente
*/
template<class TipoB>
Secuencia<TipoB> &Secuencia<TipoB>::operator = (Secuencia<TipoB> otra)
{
delete elem;
num = otra.num;
elem = new TipoB[num];
// Si no hay memoria
if(elem == NULL){
throw NoHayMemoria();
}
for(int i = 0; i < num; i++){
elem[i] = otra.elem[i];
}
}
/*
Operación []
Descripción: Selecciona el elemento de la posición i.
Descripción operacional: []: Secuencia x N -> TipoB
Precondición: i pertenece a N y 0 <= i < n
Poscondición: []=elem[i]
*/
template<class TipoB>
TipoB &Secuencia<TipoB>::operator [](int i)
{
if(i < 0 || i >= num){
throw FueraDeRango();
}
return elem[i];
}
/*
Operación ins
Descripción: Inserta después de la posición i.
Descripción operacional: ins: Secuencia x TipoB -> Secuencia
Precondición: secuencia=<elem[0],...,elem[i],ele[i+1],...,elem[n-1]> y nuevo pertenece a TipoB y -1 <= i <= n
Poscondición: secuencia=<elem[0],elem[i],nuevo,elem[i+1],...,elem[n-1]>
*/
template<class TipoB>
void Secuencia<TipoB>::ins(TipoB nuevo, int i)
{
// Verificar el rango de i.
if(i < -1 || i >= num){
throw FueraDeRango();
}
// i >= -1 && i < num
int j; //Recorre el arreglo temporal.
// Pedir memoria para un arreglo con una posición adicional.
TipoB *tmp = new TipoB[num + 1];
if(tmp == NULL){
throw NoHayMemoria();
}
// Copiar hasta i, incluido.
for(j = 0; j <= i; j++){
tmp[j] = elem[j];
}
// Copiar el nuevo.
tmp[j++] = nuevo;
// Copiar los que faltan.
for(;j < num + 1; j++){
tmp[j] = elem[j - 1];
}
delete elem;
elem = tmp;
num++;
}
/*
Operación eliminar
Descripción: Elimina el elemento de la posición i.
Descripción operacional: eliminar: Secuancia x N -> Secuencia
Precondición: secuencia=<elem[0],...,elem[i-1],elem[1],elem[i+1],...,elem[n-1]> y 0 <= i < n
Poscondición: secuencia=<elem[0],...,elem[i-1],elem[i+1],\cdots ,elem[n-1]>
*/
template<class TipoB>
void Secuencia<TipoB>::eliminar(int i)
{
// Verificar el rango de i.
if(i < 0 || i >= num){
throw FueraDeRango();
}
// Pedir menos memoria.
TipoB *nuevo = new TipoB[num - 1];
if(nuevo == NULL){
throw NoHayMemoria();
}
int j; // Para recorrer el nuevo arreglo.
// Copiar hasta antes de i;
for(j = 0; j < i; j++){
nuevo[j] = elem[j];
}
// Copiar desde después de i.
for(; j < num - 1; j++){
nuevo[j] = elem[j + 1];
}
// Liberar el viejo y actualizarlo con el nuevo.
delete elem;
elem = nuevo;
num-;
}
/*
Operación donde
Descripción: Retorna la posición del elemento en la secuencia. Si no está retorna -1.
Descripción operacional: donde: Secuencia x TipoB -> N
Precondición: el pertenece a TipoB
Poscondición: (Existe un i,elem[i]=el) => donde=i ó (Para todo i,elem[i] != el) => donde=-1
*/
template<class TipoB>
int Secuencia<TipoB>::donde(TipoB el)
{
for(int i = 0; i < num; i++){
if(elem[i] == el){
return i;
}
}
return -1;
}
/*
Operación +
Descripción: Une dos secuencias en una tercera, en ésta aparecen primero los elementos de la secuencia inicial y segundos los de la otra secuencia.
Descripción operacional: +: Secuencia x Secuencia -> Secuencia
Precondición: secuencia=<elem[0],...,elem[n-1]> y otra=<el[0],...,el[m-1]>
Poscondición: +=<elem[0],...,elem[n-1],el[0],...,el[m-1]>
*/
template<class TipoB>
Secuencia<TipoB> Secuencia<TipoB>::operator +(Secuencia<TipoB> otra)
{
Secuencia nuevo; // Conjunto unión.
for(int i = 0; i < num; i++){
nuevo.add(elem[i]);
}
for(int i = 0; i < otra.num; i++){
nuevo.add(otra.elem[i]);
}
return nuevo;
}
/*
Operación <<
Descripción: Imprime la secuencia en un stream.
Descripción operacional: <<: ostream x Secuencia -> ostream
Precondición: is pertenece a ostream y sec pertenece a Secuencia
Poscondición: ostream=<'<',elem[0], ',' ,..., ',' ,elem[n-1]>
*/
template<class TipoB>
ostream &operator << (ostream &os, Secuencia<TipoB> sec)
{
os << "<";
for(int i = 0; i < sec.tam(); i++){
os << sec[i];
if(i < sec.tam() - 1){
os << ',';
}
}
os << ">";
return os;
}
#endif
//------ Fin de secuencia.h
class Excepcion { }; // Excepcion general.
class NoHayMemoria : public Excepcion { };
class FueraDeRango : public Excepcion { };
La segun da diferencia está en el operador amigo:
friend ostream &operator << (ostream &is, Secuencia<TipoB> sec);
ostream &operator << (ostream &os, Secuencia<TipoB> sec)
{
os << "<";
for(int i = 0; i < sec.tam(); i++){
os << sec[i];
if(i < sec.tam() - 1){
os << ',';
}
}
os << ">";
return os;
}
secuencia_prueba.cpp
Autor: L. Alejandro Bernal R.
Fecha: 2000.12.04
Descripción: Prueba informal de la Secuencia.
*/
#include "secuencia.h"
#include <iostream.h>
int main()
{
try{
Secuencia<float> a,b;
a.add(10.4);
a.add(100.56);
a.add(3.4);
cout << "a=" << a << '\n';
b.add(100.56);
b.add(8.7);
cout << "b=" << b << '\n';
Secuencia<float> c;
c = a + b;
cout << "c=" << c << '\n';
c.ins(0.0, -1);
c.ins(1.0, 0);
c.ins(5.0, 4);
cout << "c=" << c << '\n';
}
catch(Secuencia<float>::Excepcion){
cerr << "Error: O no hay memoria o esta fuera de rango\n";
return 2;
}
return 0;
}
//-----Fin secuencia_prueba.cpp