EILineares - Dei-Isep

Propaganda
Estruturas Lineares
Estruturas de Informação
_____________________________________________________________________________________________________
ESTRUTURAS DE INFORMAÇÃO
Já sabemos que os tipos de dados básicos ( tais como inteiro, caracter,...) são
implicitamente tratados pelas linguagens de programação assim como o tipo array,
string, registo. Este últimos já são colecções que guardam dados e fornecem
operações de acesso que permitem juntar, retirar ou actualizar dados. O estudo de
colecções de dados e formas como se organizam com as respectivas operações de
acesso serão o objectivo principal da disciplina.
Podemos classificar as colecções de dados em duas grandes categorias:
LINEARES e NÃO LINEARES
Uma estrutura de informação será do tipo linear se contiver listas de elementos em
que existe uma relação de ordem entre eles, isto é, podemos dizer o 1º elemento, o 2º
elemento, o 3º elemento,... Um array é um exemplo elementar de uma estrutura
linear, neste caso é o índice que reflecte a ordem do elemento.
No caso de estrutura não linear, os elementos não mantem este tipo de ordem entre si,
existem outras relações, tal como é evidenciado po exemplo pela estrutura que
representa o organigrama de uma empresa. Neste caso particular verifica-se uma
relação hierárquica entre eles, mas conforme os casos outros tipo de relacionamento
poderão existir.
As figuras abaixo esquematizam os diferentes tipos de estruturas LINEARES e NÃO
LINEARES que consideraremos ao longo da disciplina.
LINEARES
Indexadas
Acesso
Directo
Acesso
Sequencial
Tabela
Fichei
Fila
Array
Registo
Lista
Pilha
Fila
Hash
ro
Prioridade
HHhh
ash
hash
HhHas
_____________________________________________________________________________________________________
Departamento de
h
Diccio
nário
Engª Informática do ISEP
1
Estruturas Lineares
Estruturas de Informação
_____________________________________________________________________________________________________
NÃO
LINEARES
Hierárquico
Árvore
Grupo
Heap
Grafo
Conjunto
ESTRUTURAS LINEARES (Revisão)
Estes conceitos dentro das estruturas lineares já foram vistos em anos anteriores, por
isso aconselha-se uma breve revisão.
ARRAY
È uma colecção de elementos todos do mesmo tipo que são directamente acedidos
através de um índice inteiro
Um array estático contem um número fixo de elementos e é alocado durante o tempo
de compilação.
Um array dinâmico é criado usando técnicas de alocação e gestão dinâmica de
memória e pode ser redimensionado.
Esta estrutura pode ser usada para guardar uma lista. No caso de uma lista sequencial,
um array permite uma eficiente adição de elementos no fim da lista. É no entanto
menos eficiente quando se retira um elemento, dado que a maioria das vezes temos
necessidade de deslocar os elementos. Esta mesma deslocação também se verifica se o
array guarda uma lista ordenada e se vamos inserir novos elementos.
REGISTO
_____________________________________________________________________________________________________
Departamento de
Engª Informática do ISEP
2
Estruturas Lineares
Estruturas de Informação
_____________________________________________________________________________________________________
É uma estrutura básica que permite guardar colecções de dados de diferentes tipos. O
seu uso aconselha-se quando um objecto tem diferentes atributos, por exemplo, um
bilhete de avião inclui o número do voo, o número do lugar, o nome do passageiro, a
agência de viagens,..., isto é, contem campos de diferentes tipos. O registo agrupa os
campos mantendo um acesso directo aos dados dos campos individuais.
LISTA
Lista linear é a colecção de dados mais geral que guarda os elementos numa ordem
sequencial..
Pode conter um número qualquer de elementos expandindo-se ou contraindo-se
conforme o elementos são juntos ou retirados à lista. A limitação desta estrutura
reside quando pretendemos aceder a um determinado elemento, teremos que percorrer
a lista desde o início até esse elemento já que não permite acesso directo.
A implementação desta estrutura poderá ser feita através de um array, mas neste caso
a implementação fica limitada ao dimensionamento do array ou através de lista ligada
em que as estruturas são criadas dinamicamente.
Seguidamente faremos uma implementação através de lista ligada, usando a
linguagem C++, com uma abordagem orientada para objecto e recorrendo ao uso de
"templates" e de classes e funções "friend".
Podemos ainda falar de lista ordenada, em que os seus elementos se dispõem na lista
atendendo a um dado critério de ordenação (numérico, alfabético,...).Neste caso a
pesquisa de um elemento pode fazer-se recorrendo ao algoritmo de pesquisa binária,
cuja ordem de complexidade temporal é muito mais favorável (log2 n ) que a da
pesquisa sequencial, mas só é possível se a implementação for feita através de array.
PILHA ("STACK")
Esta estrutura é um tipo especial de lista com acesso restrito aos seus elementos. Na
pilha os elementos são colocados e retirados por um único lado da lista, referenciado
por topo (ex: rima de pratos para um jantar,..) As operações de inserir e remover
elementos da pilha são designadas por "push" e "pop" respectivamente.
Este tipo de estrutura tem uma ordenação "LIFO- last in first out". Sempre que um
elemento é adicionado ou retirado da pilha o topo é alterado.
Usam-se pilhas, por exemplo,
na avaliação de expressões numéricas, na
recursividade, em que percorremos os elementos e a seguir acedemo-los por ordem
LIFO. Os compiladores passam parâmetros às funções usando a pilha e usam-na
também para guardar os valores das variáveis locais.
FILA ("QUEUE")
_____________________________________________________________________________________________________
Departamento de
Engª Informática do ISEP
3
Estruturas Lineares
Estruturas de Informação
_____________________________________________________________________________________________________
Esta estrutura, tal como a pilha , é uma versão especial de lista, cujo acesso aos seus
elementos é feito através do início da lista para retirar elementos e do fim da lista para
adicionar elementos( ex: fila para o autocarro,...). Usando ambos os lados da lista, os
elementos permanecem na fila na mesma ordem em que chegaram, obtem-se uma
ordenação do tipo "FIFO - first in, first out".
A fila é uma colecção útil para manter listas de espera . Em computação são utilizadas
em estudos de simulação, no escalonamento de impressões de tarefas num sistema
operativo.
FILA DE PRIORIDADE
Nalgumas aplicações altera-se a estrutura da fila dando prioridades aos seus
elementos. Quando se retira um elemento desta estrutura é seleccionado aquele que
tem maior prioridade (ex: chegada à urgência de um hospital,..). Tal como a estrutura
anterior também é usada em sistemas operativos para escalonamento de "jobs", os de
maior prioridade correm primeiro.
FICHEIRO
Ficheiro é uma colecção externa de dados que tem associada uma estrutura de dados
designada por "stream". Acesso directo relaciona-se com ficheiros em disco, mas
ficheiros em "tape" têm acesso sequencial.
A operação de leitura retira dados de um "stream" de entrada e a operação de escrita
junta novos dados ao fim de um "stream" de saída. Os ficheiros são muitas vezes
usados para guardar grandes quantidades de dados . Por exemplo, na compilação de
um programa, grandes tabelas que são criadas são muitas vezes guardadas em
ficheiros temporários.
TABELA DE HASH
Este tipo de estrutura guarda a informação associada a uma chave. A chave é
transformada num índice inteiro que é usado para aceder aos dados. Num dos métodos
mais frequentes de tabela de hash, o valor inteiro é um índice de um array de
informações. Depois de transformar a chave num índice, os dados associados são
acedidos. A chave não precisa de ser um inteiro, pode ser um string,... terá que haver
uma função que transforme essa chave num inteiro (função de hash).
DICIONÁRIOS
A palavra dicionário significa um conjunto de palavras e a respectiva definição, usase a palavra como uma chave. No caso de estruturas de dados, o dicionário consiste
num conjunto de pares chave-valor chamados associações. Neste tipo de associação o
valor é directamente acedido usando a chave como um índice. Resultado: um
_____________________________________________________________________________________________________
Departamento de
Engª Informática do ISEP
4
Estruturas Lineares
Estruturas de Informação
_____________________________________________________________________________________________________
dicionário é semelhante a um array excepto que os índices não têm que ser valores
inteiros. Os dicionários são muitas chamados arrays associativos.
_____________________________________________________________________________________________________
Departamento de
Engª Informática do ISEP
5
Estruturas Lineares
Estruturas de Informação
_____________________________________________________________________________________________________
LISTA LIGADA
DEFINIÇÃO EM C++
Temos que fazer a declaração forward da classe Lista uma vez que na classe No está
declarada como sendo uma classe friend de No, aparecendo referenciada antes de ter
sido definida (estão definidas no mesmo ficheiro). Cosiderando Lista como "friend"
de No, os métodos da classe lista têm acesso aos membros privados de No.
No
Lista
cabeça
*No
info prox
*T
?
*No
template<class T>
class Lista; // declaração forward
class No
{
friend class Lista<T>;
private:
T * info;
No<T> * prox;
public:
No()
{
info=NULL;
prox=NULL;
}
~No()
{
delete info;
}
};
template<class T>
class Lista
{
private:
No<T> *cabeca;
_____________________________________________________________________________________________________
Departamento de
Engª Informática do ISEP
6
Estruturas Lineares
Estruturas de Informação
_____________________________________________________________________________________________________
public:
Lista<T>();
//construtor
Lista<T>(const Lista<T>& l);
//construtor cópia
~Lista<T>(); //destrutor
bool vazia() const;
Lista<T> & insere(int k,const T & elem); //junta o elemento elem na
//posição imediatamente a seguir a K e devolve a nova lista
//devolve o nº de elementos da lista
//devolve a posição na lista onde se
//encontra o elemento x
Lista<T> & elimina(int k,T & x); //remove o elemento que se encontra na
//posição K,traz em x o respectivo valor e devolve a nova
//lista
bool encontra(int k,T & x) const; //devolve true se encontra a posiçao k e
traz em x o valor do elemento nessa
posiçao
void escreve(ostream & ostr) const;
//lista os elementos da lista
Lista<T> operator=(const Lista<T> & l); //operador de atribuição
int comprimento() const;
int pesquisa(const T & x) const;
};
Construtores
//Construtor sem parâmetros
template <class T>
Lista<T>::Lista()
{
cabeca = NULL;
}
//Construtor Cópia
template <class T>
Lista<T>::Lista<T>(const Lista<T>& l)
{
No<T> * apno =new No<T>;
if(l.cabeca)
cabeca=apno;
else cabeca=NULL;
No<T> * apnoaux=l.cabeca;
while(apnoaux !=NULL)
{
apno->info=new T(*(apnoaux->info));
if(apnoaux->prox ==NULL)
{
apno->prox=NULL;
apnoaux=apnoaux->prox;
}
else
{
apno->prox=new No<T>;
apno=apno->prox;
_____________________________________________________________________________________________________
Departamento de
Engª Informática do ISEP
7
Estruturas Lineares
Estruturas de Informação
_____________________________________________________________________________________________________
apnoaux=apnoaux->prox;
}
}
}
Destrutor
template <class T>
Lista<T>::~Lista()
{
No<T> * temp;
while(cabeca)
{
temp=cabeca->prox;
delete cabeca;
cabeca=temp;
}
cabeca=NULL;
}
Outra forma que podemos ter para o destrutor será à custa de outro método que
elimine todos os elementos da lista -- destroilista()
template <class T>
Lista<T>::~Lista()
{
destroilista();
cabeca=NULL;
}
template <class T>
void Lista<T>::destroilista()
{
No<T> * temp;
while(cabeca)
{
temp=cabeca->prox;
delete cabeca;
cabeca=temp;
}
}
_____________________________________________________________________________________________________
Departamento de
Engª Informática do ISEP
8
Estruturas Lineares
Estruturas de Informação
_____________________________________________________________________________________________________
Juntar elementos à lista
A inserção do elemento elem, é feita imediatamente a seguir à posição k
template<class T>
Lista<T> & Lista<T>::insere(int k,const T & elem)
{
if (k<0)
cout<<"ERRO --- Posiçao incorrecta"<<'\n';
else
{
No<T> *temp=cabeca;
for(int i=1;i<k && temp;i++)
temp=temp->prox;
if(k>0 && !temp)
{
cout<<"ERRO --- Posiçao incorrecta"<<'\n';
}
else
{
No<T>* apno= new No<T>;
apno->info= new T(elem);
if(k)
{
apno->prox=temp->prox;
temp->prox=apno;
}
else
{
apno->prox=cabeca;
cabeca=apno;
}
}
}
return *this;
}
Operador de atribuição
template <class T>
Lista<T> Lista<T>::operator=(const Lista<T> & l)
{
if(this==& l)
return *this;
destroilista();
No<T> * apno =new No<T>;
if(l.cabeca)
cabeca=apno;
_____________________________________________________________________________________________________
Departamento de
Engª Informática do ISEP
9
Estruturas Lineares
Estruturas de Informação
_____________________________________________________________________________________________________
else cabeca=NULL;
No<T> * apnoaux=l.cabeca;
while(apnoaux !=NULL)
{
apno->info= new T(*(apnoaux->info));
if(apnoaux->prox ==NULL)
{
apno->prox=NULL;
apnoaux=apnoaux->prox;
}
else
{
apno->prox=new No<T>;
apno=apno->prox;
apnoaux=apnoaux->prox;
}
}
return *this;
}
//Método booleano que determina se a lista está ou não vazia.
template<class T>
bool Lista<T>::vazia() const
{
return (cabeca==NULL);
}
//Método que devolve o números de elementos que constituem a lista
template<class T>
int Lista<T>::comprimento() const
{
No<T> *temp;
int comp=0;
temp =cabeca;
while (temp)
{
comp++;
temp=temp->prox;
}
return comp;
}
Eliminar elemento
//Este método retira da lista o nó da posição k, traz em x o valor do elemento nessa
//posição e devolve a lista alterada.
template<class T>
Lista<T> & Lista<T>::elimina(int k,T & x)
{
_____________________________________________________________________________________________________
Departamento de
Engª Informática do ISEP
10
Estruturas Lineares
Estruturas de Informação
_____________________________________________________________________________________________________
if (k<1 || !cabeca)
cout<<"ERRO --- Posiçao incorrecta"<<endl;
else
{
No<T> * apt=cabeca;
No<T> * anterior=NULL;
int i=1;
while (apt && i<k)
{
anterior=apt;
apt=apt->prox;
i++;
}
if (i==k)
{
if(anterior)
anterior->prox=apt->prox; //elimina do meio ou fim
else
cabeca=cabeca->prox;
//elimina do inicio
x= *(apt->info);
delete apt;
}
else
cout<<"ERRO --- Posiçao incorrecta"<<endl;
}
return *this;
}
Pesquisar
//Método booleano, que devolve true se encontra a posição k, traz em x o valor do
//elemento (info da classe T) nessa posição. Devolverá false caso não exista a posição
//k.
template<class T>
bool Lista<T>::encontra(int k,T & x) const
{
if (k>0)
{
No<T> *temp=cabeca;
for(int i=1;i<k && temp;i++)
temp=temp->prox;
if(temp !=NULL)
{
x= *(temp->info); // haverá que implementar o operador == na classe a
//que T for instanciada
return true;
}
}
_____________________________________________________________________________________________________
Departamento de
Engª Informática do ISEP
11
Estruturas Lineares
Estruturas de Informação
_____________________________________________________________________________________________________
cout<<"ERRO --- Posiçao incorrecta"<<endl;
return false;
}
// Este método devolve a posição na lista onde se encontra o elemento x, devolverá 0
//caso esse elemento não exista na lista.
template<class T>
int Lista<T>::pesquisa(const T & x)const
{
No<T> * apt=cabeca;
int enc=0,i=0;
while (apt && !enc)
{
if(* (apt->info)==x) // haverá que implementar o operador == na classe a que T
//for instanciada
enc=1;
else apt=apt->prox;
i++;
}
if (enc) return i;
else return 0;
}
Sobrecarga do operador <<
O método escreve é invocado na função template que faz a sobrecarga do operador
<<. Esta função template, será definida fora de qualquer classe e o método escreve
deverá a parecer em todas as classes que pretendemos visualizar os seus atributos.
template <class T>
ostream & operator<<(ostream & ostr,const T & x)
{
x.escreve(ostr);
return ostr;
}
template<class T>
void Lista<T>::escreve(ostream & ostr) const
{
No<T>* temp=cabeca;
if (cabeca)
do
{
ostr<<*(temp->info);
temp=temp->prox;
}while (temp);
else
cout << "Lista Vazia";
cout << endl;
}
_____________________________________________________________________________________________________
Departamento de
Engª Informática do ISEP
12
Download