Listas Estáticas
Download
Report
Transcript Listas Estáticas
LISTAS
Dilvan Moreira, parcialmente baseado em material
do prof. Ricardo Campello
Lista Linear
Estrutura de representação de informação em que
os elementos são mantidos de forma linear, ou seja,
dispostos um após o outro
Ex.
listas de nomes, de valores, de pessoas, etc.
Pode ser ordenada ou não
Estruturação de informação em listas ocorre em
vários domínios
P.
ex. lista telefônica
Lista Linear
Operação Básica em Listas:
Busca
por
um elemento através de uma “chave”
Ex. busca na lista telefônica: dado um nome, buscamos o
telefone
Inserção e Remoção de elementos:
Implementação
manipulação
depende da organização da lista
distinta de listas ordenadas e não ordenadas
TAD para Lista
Inicializar lista (p. ex. vazia):
void
Inserir elemento:
void
Definir(Lista *L);
Inserir(tipo_elem e, Lista *L);
Localizar a posição (na lista) de um elemento dado:
int
Localizar(tipo_elem e, Lista
*L);
retorna a posição do elemento na lista retorna um
valor inválido caso ele não esteja na lista
TAD para Lista
Acessar elemento em posição dada:
tipo_elem Buscar(intp, Lista *L);
retorna o elemento da lista na posição fornecida sem alterá-la
se posição não existir, retorna um valor inválido
Eliminar elemento na posição dada:
int Remover(intp, Lista *L);
Retorna 1 (true) se bem sucedida
Retorna 0 (false) se posição dada é inválida
Obter número de elementos na lista:
int Tamanho(Lista *L);
TAD para Lista
Apagar a lista:
void
Apagar(Lista *L);
Destruir a lista:
void
Destruir(Lista *L);
lista
não é mais acessível (só para implementações
dinâmicas)
Obter posição seguinte à do último elemento:
int
Fim(Lista *L);
Verificar se lista está vazia, verificar se está cheia...
...
EDs Estáticas para Listas
Realizações Estáticas (vetores):
Seqüencial:
seqüência
de elementos disponíveis de forma consecutiva
Encadeada:
seqüência
de elementos disponíveis de forma não
consecutiva
EDs Dinâmicas para Listas
Realizações Dinâmicas (ponteiros e memória):
Simplesmente
Encadeada:
Encadeamento
Duplamente
Encadeada:
Encadeamento
de ponteiros unidirecional
de ponteiros bidirecional
Cada realização possui vantagens e desvantagens
Lista Estática Sequencial
Implementação a Seguir:
Exemplo
de Lista Estática Seqüencial em C
Projetada para Lista Não Ordenada
Adaptação
para lista ordenada como exercício no final
Lista Estática Sequencial
#define
#define
#define
#define
MAX 100
TRUE 1
FALSE 0
bool int
/* Max. Tamanho da Lista */
typedef struct{
Tipo_1 chave;
Tipo_2 info;
} elem;
/* P. ex. int chave;
*/
/* P. ex. char info[50] */
/* Tipo do Elemento */
typedef struct{
int nelem;
elem A[MAX+1];
} Lista;
/* Tipo da Lista */
Lista L;
/* Exemplo de Declaração*/
Lista Estática Sequencial
void Definir(Lista *L){ /*
O(1)
*/
/* Define uma lista vazia */
L->nelem= 0;
L->A[0].chave = 0;
/* Célula não utilizada */
L->A[0].info[0] = '\0'; /* Célula não utilizada */
}
int Tamanho(Lista *L){
/*
O(1)
*/
/* Retorna o tamanho da Lista (0 caso vazia) */
return L->nelem;
}
Lista Estática Sequencial
int Fim(Lista *L){
/* O(1) */
/* Retorna a posição após o último elemento da
lista */
return (L->nelem + 1);
}
bool Lista_vazia(Lista *L){
/* O(1) */
/* Retorna true se lista vazia, false caso
contrário */
return (L->nelem == 0);
}
bool Lista_cheia(Lista *L){
/* O(1) */
/* Retorna true se lista cheia, false caso
contrário */
return (L->nelem == MAX);
}
Lista Estática Sequencial
bool Inserir(elem* x, int p, Lista *L){
/* Insere elemento x na posição p da Lista L. Se a lista é tal
que L=a1,a2,...,ap,...,an então L=a1,a2,...,ap-1,x,ap+1,...,an.
Se p=Fim(L) então L=a1,a2,...,an,x. Devolve true se sucesso,
false c.c. (L cheia ou não tem posição p). L não ordenada! */
int atual;
if (Lista_cheia(L))
return FALSE; /* lista cheia */
else if (p > Fim(L) || p < 1)
return FALSE; /* posição não existe */
else {
for(atual = L->nelem; atual >= p; atual--)
L->A[atual+1] = L->A[atual];
L->A[p]= *x;
L->nelem++;
return TRUE; /* inserção com sucesso */
}
} /* O(L.nelem) no pior caso. Qual o pior caso? */
Lista Estática Sequencial
int Localizar(elem* x, Lista *L){
/* Retorna a posição de x na Lista. Se x ocorre mais de
uma vez, retorna posição da 1a ocorrência. Se x não
ocorre, retorna 0 */
int atual = 1;
if (!Lista_vazia(L)){
while(atual <= L->nelem){
if(igual(&A[atual], x)) /* iguais ?*/
return atual; /* retorno
sucesso */
else atual++;
}
}
return 0; /* retorno em insucesso ou lista vazia */
}
/* O(L.nelem) no pior caso. Qual o pior caso? */
Lista Estática Sequencial
bool igual(elem* a, elem* b) {
/* Testa igualdade entre elementos por algum critério
particular */
}
return (a->chave==b->chave);
/* O(1) */
elem* Buscar(int p, Lista *L){
/* Retorna elem. da posição p, ou elem. inválido se p é
inválida */
}
if (p >= Fim(L) || p < 1 || Lista_vazia(L))
return x;
/* retorna elemento inválido */
else return &(L->A[p]);
/* O(1) */
Lista Estática Sequencial
bool Remover(int p, Lista *L){
/* Remove o elemento da posição p da Lista. Se L =
a1,a2,...,an então tem-se a1,a2,...,ap-1,ap+1,...,an.
Devolve true se sucesso, false c.c. (L não tem posição p,
inclusive se p = Fim(L)) */
FALSE;
int atual;
if(p >= Fim(L) || p < 1 || Lista_vazia(L)) return
else {
atual++)
for (atual = p+1; atual <= L->nelem;
L->A[atual-1] = L->A[atual];
L->nelem--;
} return TRUE;
} /* O(L.nelem) no pior caso. Qual o pior caso? */
Lista Estática Sequencial em C++
Como ficaria essa implementação em C++?
Seria muito diferente?
Lista Estática Sequencial Orig.
#define
#define
#define
#define
MAX 100
TRUE 1
FALSE 0
bool int
typedef struct{
char info[50];
} elem;
/* Max. Tamanho da Lista */
/* P. ex. char info[50] */
/* Tipo do Elemento */
typedef struct{
int nelem;
tipo_elem A[MAX+1];
} Lista;
/* Tipo da Lista */
Lista L;
/* Exemplo de Declaração*/
Lista Estática Sequencial em C++
#define
#define
#define
#define
MAX 100
TRUE 1
FALSE 0
bool int
/* Max. Tamanho da Lista */
class Elem {
char info[50];
/* P. ex. char info[50] */
…
}
/* Tipo do Elemento */
class List {
int nelem;
tipo_elem A[MAX+1];
…
}
/* Tipo da Lista */
Lista Estática Sequencial Orig.
void Definir(Lista *L){ /*
O(1)
*/
/* Define uma lista vazia */
L->nelem= 0;
L->A[0].info[0] = '\0'; /* Célula não utilizada */
}
int Tamanho(Lista *L){
/*
O(1)
*/
/* Retorna o tamanho da Lista (0 caso vazia) */
return L->nelem;
}
Lista Estática Sequencial em C++
void Lista::Lista(){ /*
O(1)
*/
/* Define uma lista vazia */
nelem= 0;
A[0].info[0] = '\0'; /* Célula não utilizada */
}
int Lista::Tamanho(){
/*
O(1)
*/
/* Retorna o tamanho da Lista (0 caso vazia) */
return nelem;
}
Lista Estática Sequencial Orig.
int Fim(Lista *L){
/* O(1) */
/* Retorna a posição após o último elemento da
lista */
return (L->nelem + 1);
}
bool Lista_vazia(Lista *L){
/* O(1) */
/* Retorna true se lista vazia, false caso
contrário */
return (L->nelem == 0);
}
bool Lista_cheia(Lista *L){
/* O(1) */
/* Retorna true se lista cheia, false caso
contrário */
return (L->nelem == MAX);
}
Lista Estática Sequencial C++
int List::Fim(){
/* O(1) */
/* Retorna a posição após o último elemento da
lista */
return (nelem + 1);
}
bool List::Lista_vazia(){
/* O(1) */
/* Retorna true se lista vazia, false caso
contrário */
return (nelem == 0);
}
bool List::Lista_cheia(){
/* O(1) */
/* Retorna true se lista cheia, false caso
contrário */
return (nelem == MAX);
}
Lista Estática Sequencial Orig.
bool Inserir(elem* x, int p, Lista *L){
/* Insere elemento x na posição p da Lista L. Se a lista é tal
que L=a1,a2,...,ap,...,an então L=a1,a2,...,ap-1,x,ap+1,...,an.
Se p=Fim(L) então L=a1,a2,...,an,x. Devolve true se sucesso,
false c.c. (L cheia ou não tem posição p). L não ordenada! */
int atual;
if (Lista_cheia(L))
return FALSE; /* lista cheia */
else if (p > Fim(L) || p < 1)
return FALSE; /* posição não existe */
else {
for(atual = L->nelem; atual >= p; atual--)
L->A[atual+1] = L->A[atual];
L->A[p] = *x;
L->nelem++;
return TRUE; /* inserção com sucesso */
}
} /* O(L.nelem) no pior caso. Qual o pior caso? */
Lista Estática Sequencial C++
bool List::Inserir(Elem* x, int p){
/* Insere elemento x na posição p da Lista L. Se a lista é tal
que L=a1,a2,...,ap,...,an então L=a1,a2,...,ap-1,x,ap+1,...,an.
Se p=Fim(L) então L=a1,a2,...,an,x. Devolve true se sucesso,
false c.c. (L cheia ou não tem posição p). L não ordenada! */
int atual;
if (Lista_cheia())
return FALSE; /* lista cheia */
else if (p > Fim() || p < 1)
return FALSE; /* posição não existe */
else {
for(atual = nelem; atual >= p; atual--)
A[atual+1] = A[atual];
A[p] = *x;
nelem++;
return TRUE; /* inserção com sucesso */
}
} /* O(L.nelem) no pior caso. Qual o pior caso? */
Lista Estática Sequencial Orig
int Localizar(elem* x, Lista *L){
/* Retorna a posição de x na Lista. Se x ocorre mais de uma vez,
retorna posição da 1a ocorrência. Se x não ocorre, retorna 0 */
int atual = 1;
if (!Lista_vazia(L)){
while(atual <= L->nelem){
if(igual(&L->A[atual], x))
return atual; /* retorno em sucesso
*/
else atual++;
}
}
return 0; /* retorno em insucesso ou lista vazia */
}
/* O(L.nelem) no pior caso. Qual o pior caso? */
Lista Estática Sequencial C++
int List::Localizar(Elem* x){
/* Retorna a posição de x na Lista. Se x ocorre mais de uma vez,
retorna posição da 1a ocorrência. Se x não ocorre, retorna 0 */
int atual = 1;
if (!Lista_vazia()){
while(atual <= nelem){
if(A[atual].Igual(x))
return atual; /* retorno em sucesso
*/
else atual++;
}
}
return 0; /* retorno em insucesso ou lista vazia */
}
/* O(L.nelem) no pior caso. Qual o pior caso? */
Lista Estática Sequencial Orig
bool igual(elem* a, elem* b) {
/* Testa igualdade entre elementos por algum critério
particular */
}
return (strcmp(a->chave,b->chave)==0);
/* O(1) */
elem* Buscar(int p, Lista *L){
/* Retorna elem. da posição p, ou elem. inválido se p é
inválida */
}
if (p >= Fim(L) || p < 1 || Lista_vazia(L))
return x;
/* retorna elemento inválido */
else return L->A[p];
/* O(1) */
Lista Estática Sequencial C++
bool Elem::igual(elem* b) {
/* Testa igualdade entre elementos por algum critério
particular */
}
return (strcmp(info,b->info)==0);
/* O(1) */
Elem* List::Buscar(int p){
/* Retorna elem. da posição p, ou elem. inválido se p é
inválida */
}
if (p >= Fim() || p < 1 || Lista_vazia())
return null;
/* retorna inválido */
else return &A[p];
/* O(1) */
Lista Estática Sequencial Orig
bool Remover(int p, Lista *L){
/* Remove o elemento da posição p da Lista. Se L =
a1,a2,...,an então tem-se a1,a2,...,ap-1,ap+1,...,an.
Devolve true se sucesso, false c.c. (L não tem posição p,
inclusive se p = Fim(L)) */
FALSE;
int atual;
if(p >= Fim(L) || p < 1 || Lista_vazia(L)) return
else {
atual++)
for (atual = p+1; atual <= L->nelem;
L->A[atual-1] = L->A[atual];
L->nelem--;
} return TRUE;
} /* O(L.nelem) no pior caso. Qual o pior caso? */
Lista Estática Sequencial C++
bool List::Remover(int p){
/* Remove o elemento da posição p da Lista. Se L =
a1,a2,...,an então tem-se a1,a2,...,ap-1,ap+1,...,an.
Devolve true se sucesso, false c.c. (L não tem posição p,
inclusive se p = Fim(L)) */
FALSE;
int atual;
if(p >= Fim() || p < 1 || Lista_vazia()) return
else {
for (atual = p+1; atual <= nelem; atual++)
A[atual-1] = A[atual];
nelem--;
} return TRUE;
} /* O(L.nelem) no pior caso. Qual o pior caso? */
.
Checando
1.
2.
3.
4.
Modifique a operação Remover do TAD Lista Estática Seqüencial
para que esta retorne o elemento removido e não um valor lógico.
Modifique a operação Localizar do TAD Lista Estática Seqüencial
para que esta receba apenas a chave do elemento procurado e
não o elemento todo.
Modifique a operação Localizar do TAD Lista Estática Seqüencial
para que esta retorne um ponteiro para uma cópia do elemento
localizado, cópia esta alocada dinamicamente em memória.
Retorne NULL se o elemento não existir na lista.
Implemente o TAD Lista Estática Seqüencial em C, de forma
modular, com módulos separados de interface (arquivo .h) e
implementação (arquivo .c), e faça alguns testes.aula
Checando
Modifique a oImplemente uma nova operação de
inserção para o TAD Lista Estática Seqüencial para
substituir aquela que foi apresentada anteriormente
nesses slides (Inserir). Essa nova operação deve inserir
o novo elemento de forma a manter sempre a lista
ordenadapelas chaves dos seus elementos.
5.
5.
OBS: Como a lista deve ser mantida ordenada, essa
operação deve determinar a posição de inserção
automaticamente, não recebê-la como parâmetro. Nesse
exercício, faça isso percorrendo um a um os elementos da
lista a partir do início (depois vide exercício 7).
Checando
Considerando que a operação de inserção utilizada
no TAD Lista Estática Seqüencial é aquela
implementada no exercício 5, reimplemente também a
operação Localizar do TAD para que esta faça uso
do fato da lista estar ordenada para realizar uma
busca muito mais eficiente (binária) pelo elemento
desejado.
6.
6.
7.
Qual o tempo de execução assintótico (BIG-O) de pior
caso da operação acima ? Qual o pior caso? Justifique.
Estando a nova operação de localização via busca
binária do exercício 6 disponível, é possível utilizá-la
para simplificar a implementação da operação de
inserção ordenada do exercício 5? Explique.
Bibliografia
N. Ziviani, Projeto de Algoritmos, Thomson, 2a.
Edição, 2004
A. M. Tenembaum et al., Data Structures Using C,
Prentice-Hall, 1990
J. L. Szwarcfiter & L. Markenzon, Estruturas de
Dados e seus Algoritmos, LTC, 1994
Perguntas?