LISTAS Dilvan Moreira, parcialmente baseado em material do prof. Ricardo Campello.

Post on 16-Apr-2015

107 views 1 download

Transcript of LISTAS Dilvan Moreira, parcialmente baseado em material do prof. Ricardo Campello.

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?