LISTASDilvan 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 depende da organização da lista manipulação distinta de listas ordenadas e não ordenadas
TAD para Lista
Inicializar lista (p. ex. vazia): void Definir(Lista *L);
Inserir elemento: void 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 de ponteiros unidirecional
Duplamente Encadeada: Encadeamento 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 MAX 100 /* Max. Tamanho da Lista */#define TRUE 1#define FALSE 0#define bool int
typedef struct{ Tipo_1 chave; /* P. ex. int chave; */Tipo_2 info; /* P. ex. char info[50] */
} elem; /* Tipo do Elemento */
typedef struct{ int nelem;elem A[MAX+1];
} Lista; /* Tipo da Lista */
Lista L; /* Exemplo de Declaração*/
Lista Estática Sequencialvoid 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 Sequencialint 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 Sequencialbool 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 Sequencialint 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 Sequencialbool 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 Sequencialbool 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)) */
int atual;if(p >= Fim(L) || p < 1 || Lista_vazia(L)) return
FALSE;else {
for (atual = p+1; atual <= L->nelem; atual++) 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 MAX 100 /* Max. Tamanho da Lista */#define TRUE 1#define FALSE 0#define bool int
typedef struct{ char info[50]; /* P. ex. char info[50] */
} elem; /* 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 MAX 100 /* Max. Tamanho da Lista */#define TRUE 1#define FALSE 0#define bool int
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 Origint 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 Origbool 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 Origbool 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)) */
int atual;if(p >= Fim(L) || p < 1 || Lista_vazia(L)) return
FALSE;else {
for (atual = p+1; atual <= L->nelem; atual++) 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)) */
int atual;if(p >= Fim() || p < 1 || Lista_vazia()) return
FALSE;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. 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.
2. 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.
3. 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.
4. 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
5. 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. 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
6. 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. Qual o tempo de execução assintótico (BIG-O) de pior caso da operação acima ? Qual o pior caso? Justifique.
7. 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?
Top Related