R:
lista_double.H
#ifndef LISTA_DOUBLE_Hlista_double.C
#define LISTA_DOUBLE_H#include <cassert>
#include <iostream>// Uma classe para representar listas de itens do tipo Item (actualmente double):
class ListaDouble {
public:
// Cria-se um sinónimo para simplificar a tarefa de criar listas com itens de outros tipos:
typedef double Item;// Declaração de uma classe embutida que serve para percorrer e manipular listas.
class Iterador;// A classe de iteração tem acesso irrestrito às listas:
friend Iterador;// Construtor da classe, cria uma lista vazia:
ListaDouble();// Acrescenta item no início da lista:
void poeInicio(const Item& item);
// Acrescenta item no fim da lista:
void poeFim(const Item& item);
// Insere item imediatamente antes da posição indicada pelo iterador i, fazendo com que
// o iterador continue a referenciar o mesmo item que antes da inserção:
void insere(Iterador& i, const Item& item);// Retira o primeiro item da lista:
void tiraPrimeiro();
// Retira o último item da lista:
void tiraUltimo();
// Remove o item indicado pelo iterador i, ficando o iterador a referenciar o item logo
// após o item removido:
void remove(const Iterador& i);// Devolve o primeiro item:
Item primeiroItem() const;
Item& primeiroItem();
// Devolve o último item:
Item ultimoItem() const;
Item& ultimoItem();// Devolve o comprimento da lista:
int comprimento() const;
// Indica se a lista está vazia:
bool vazia() const;
// Indica se a lista está cheia:
bool cheia() const;// Devolve um iterador referenciando o primeiro item da lista:
Iterador primeiro();
// Devolve um iterador referenciando o último item da lista:
Iterador ultimo();
// Devolve um iterador referenciando o item fictício depois do último item da lista:
Iterador fim();
// Devolve um iterador referenciando o item fictício antes do primeiro item da lista:
Iterador inicio();private:
// O número máximo de itens na lista:
static const int limite = 100;// Matriz que guarda os itens da lista:
Item itens[limite];// Contador do número de itens na lista:
int quantos;
};// Uma classe para representar iteradores para itens de listas ListaDouble:
class ListaDouble::Iterador {
public:
// Construtor da classe. Associa o iterador com a lista lista e põe-no a referenciar o
// seu primeiro item:
explicit Iterador(ListaDouble& lista);// Incrementação prefixa de iteradores (avança para o próximo item):
Iterador& operator ++ ();
// Decrementação prefixa de iteradores (recua para o item anterior):
Iterador& operator -- ();// Incrementação sufixa de iteradores (avança para o próximo item):
Iterador operator ++ (int);
// Decrementação sufixa de iteradores (recua para o item anterior):
Iterador operator -- (int);// Devolve o item referenciado pelo iterador:
Item& item() const;// Operadores de igualdade e diferença entre iteradores:
bool operator == (const Iterador& i) const;
bool operator != (const Iterador& i) const;// A classe ListaDouble tem acesso irrestrito a todos os membros da classe Iterador:
friend ListaDouble;private:
// Referência para a lista a que o iterador está associado:
ListaDouble& lista;
// Índice do item referenciado:
int indice;
};// Definição das funções e procedimentos membro inline da classe ListaDouble:
inline ListaDouble::ListaDouble()
: quantos(0) {
// Usa-se uma lista de inicializadores. Neste caso basta dizer que a lista está vazia, i.e.,
// não tem qualquer item.
}inline void ListaDouble::poeFim(const Item& item) {
assert(!cheia());itens[quantos++] = item;
}inline void ListaDouble::tiraUltimo() {
assert(!vazia());--quantos;
}inline ListaDouble::Item ListaDouble::primeiroItem() const {
assert(!vazia());
return itens[0];
}inline ListaDouble::Item& ListaDouble::primeiroItem() {
assert(!vazia());
return itens[0];
}inline ListaDouble::Item ListaDouble::ultimoItem() const {
assert(!vazia());
return itens[quantos - 1];
}inline ListaDouble::Item& ListaDouble::ultimoItem() {
assert(!vazia());
return itens[quantos - 1];
}inline int ListaDouble::comprimento() const {
return quantos;
}inline bool ListaDouble::vazia() const {
return comprimento() == 0;
}inline bool ListaDouble::cheia() const {
return comprimento() == limite;
}inline ListaDouble::Iterador ListaDouble::primeiro() {
// Cria-se um iterador para esta lista, que referencia logo o primeiro item da lista
// (ver construtor de ListaDouble::Iterador):
Iterador iterador(*this);// Devolve-se o iterador criado:
return iterador;
// ou simplesmente return Iterador(*this);
}inline ListaDouble::Iterador ListaDouble::ultimo() {
// Cria-se um iterador para esta lista:
Iterador iterador(*this);// O iterador deve referenciar o último item da lista:
iterador.indice = comprimento() - 1;return iterador;
}inline ListaDouble::Iterador ListaDouble::inicio() {
Iterador iterador(*this);// O iterador deve referenciar o item fictício antes do primeiro item da lista:
iterador.indice = -1;return iterador;
}inline ListaDouble::Iterador ListaDouble::fim() {
Iterador iterador(*this);// O iterador deve referenciar o item fictício após o último item da lista:
iterador.indice = comprimento();return iterador;
}// Definição das funções e procedimentos membro inline da classe ListaDouble::Iterador:
inline ListaDouble::Iterador::Iterador(ListaDouble& l)
: lista(l), indice(0) {
}inline ListaDouble::Iterador& ListaDouble::Iterador::operator ++ () {
assert(indice != lista.comprimento());++indice;
return *this;
}inline ListaDouble::Iterador& ListaDouble::Iterador::operator -- () {
// Decrementar para aquém do item fictício inicial é um erro:
assert(indice != -1);--indice;
return *this;
}inline ListaDouble::Iterador ListaDouble::Iterador::operator ++ (int) {
ListaDouble::Iterador resultado = *this;
operator ++ ();
return resultado;
}inline ListaDouble::Iterador ListaDouble::Iterador::operator -- (int) {
ListaDouble::Iterador resultado = *this;
operator -- ();
return resultado;
}// Comparam-se os índices. Esta implementação não é perfeita. Em rigor dever-se-ia verificar se
// ambos os iteradores estão associados à mesma lista, pois não faz sentido compará-los de outra
// forma (pense como fazê-lo quando tiver aprendido ponteiros).
inline bool ListaDouble::Iterador::operator == (const Iterador& i) const {
return indice == i.indice;
}inline bool ListaDouble::Iterador::operator != (const Iterador& i) const {
return indice != i.indice;
}inline ListaDouble::Item& ListaDouble::Iterador::item() const {
// O item só existe se o iterador não se referir a um item fictício:
assert(0 <= indice && indice < lista.comprimento());return lista.itens[indice];
}// Definição de funções e procedimentos não membro e inline:
// Declaração de funções e procedimentos não membro e não inline:
std::ostream& operator << (std::ostream& saida, ListaDouble& l);
#endif // LISTA_DOUBLE_H
#include "lista_double.H"teste.C// Definição das funções e procedimentos membro não inline da classe ListaDouble:
void ListaDouble::poeInicio(const Item& item)
{
// Só se pode inserir se ainda houver espaço:
assert(!cheia());// Inserir no início implica rearranjar todos os itens já na lista:
for(int i = comprimento(); i != 0; --i)
itens[i] = itens[i - 1];// Agora já há espaço:
itens[0] = item;// E convém incrementar o contador de itens...
++quantos;
}void ListaDouble::tiraPrimeiro()
{
assert(!vazia());--quantos;
for(int i = 0; i != comprimento(); ++i)
itens[i] = itens[i + 1];
}void ListaDouble::insere(Iterador& iterador, const Item& item)
{
// Só se pode inserir se ainda houver espaço:
assert(!cheia());// Não se pode inserir se o iterador referir o item antes do primeiro:
assert(iterador.indice != -1);// Há que rearranjar todos os itens a partir do referenciado pelo iterador:
for(int i = comprimento(); i != iterador.indice; --i)
itens[i] = itens[i - 1];// Agora já há espaço (não esquecer de revalidar o iterador!):
itens[iterador.indice++] = item;// Mais um...
++quantos;
}void ListaDouble::remove(const Iterador& iterador)
{
assert(iterador.indice != -1 && iterador.indice != comprimento());--quantos;
for(int i = iterador.indice; i != comprimento(); ++i)
itens[i] = itens[i + 1];
}// Definição das funções e procedimentos membro não inline da classe ListaDouble::Iterador:
// Definição de funções e procedimentos não membro e não inline:
// Definição do operador << para escrita de listas num canal. ListaDouble& deveria ser
// const ListaDouble&, mas isso implicaria a definição de uma classe de iterador para
// listas constantes:
std::ostream& operator << (std::ostream& saida, ListaDouble& l)
{
saida << '(';
for(ListaDouble::Iterador i = l.primeiro(); i != l.fim(); ++i) {
saida << i.item();
if(i != l.ultimo())
saida << ", ";
}
return saida << ')';
}
#include <iostream>Se lhe sobrar tempo avance para a Aula 3.using namespace std;
#include "lista_double.H"
// O programa de teste:
int main()
{
ListaDouble l;l.poeFim(1);
l.poeFim(2);
l.poeFim(3);
l.poeFim(4);for(ListaDouble::Iterador i = l.primeiro(); i != l.fim(); ++i)
cout << i.item() << ' ';
cout << endl;for(ListaDouble::Iterador i = l.ultimo(); i != l.inicio(); --i)
cout << i.item() << ' ';
cout << endl;cout << l << endl;
ListaDouble::Iterador i = l.primeiro();
++i;l.insere(i, 10);
cout << l << endl;
l.remove(i);
cout << l << endl;
l.tiraPrimeiro();
cout << l << endl;l.tiraUltimo();
cout << l << endl;l.tiraPrimeiro();
cout << l << endl;l.tiraUltimo();
cout << l << endl;l.poeInicio(10);
cout << l << endl;
l.poeInicio(20);
cout << l << endl;
l.poeInicio(30);
cout << l << endl;
l.poeInicio(40);
cout << l << endl;
l.poeFim(100);
cout << l << endl;
l.poeFim(200);
cout << l << endl;
l.poeFim(300);
cout << l << endl;
l.poeFim(400);
cout << l << endl;ListaDouble::Iterador j = l.ultimo();
--j;
--j;
--j;
l.remove(j);
cout << l << endl;
--j;
--j;
l.remove(j);
cout << l << endl;
l.insere(j, 1000);
cout << l << endl;
l.insere(j, 2000);
cout << l << endl;
l.insere(j, 3000);
cout << l << endl;
l.insere(j, 4000);
cout << l << endl;
l.tiraPrimeiro();
cout << l << endl;
l.tiraPrimeiro();
cout << l << endl;
l.tiraPrimeiro();
cout << l << endl;
l.tiraPrimeiro();
cout << l << endl;
l.tiraPrimeiro();
cout << l << endl;
l.tiraPrimeiro();
cout << l << endl;
l.tiraPrimeiro();
cout << l << endl;
l.tiraPrimeiro();
cout << l << endl;
l.tiraPrimeiro();
cout << l << endl;
l.tiraPrimeiro();
cout << l << endl;// A seguir o programa aborta porque tenta tirar um item de uma lista vazia:
l.tiraUltimo();
cout << l << endl;
}