DEV Community

Alex Reis
Alex Reis

Posted on

Estruturas de Dados: Lista

Uma Lista linear é um conjunto de n >= 0 elementos L[1], L[2], ..., L[n]. Tal que:

  • se n > 0, L[1] é o primeiro elemento
  • para 1 <= k <= n, o nó L[k] é precidido pelo L[k-1].

As operações mais frequentes em listas são a busca, a inclusão e a remoção de um determinado elemento.

Se as inserções e remoções são permitidas apenas nas extremidades da lista, ela recebe o nome de deque (double end queue). Se as inserções e as remoções são realizadas somente em um extremo, a lista é chamada pilha, sendo denominada fila no caso em que inserções são realizadas em um extremo e remoções em outro.

O tipo de armazenamento de uma lista linear pode ser classificado de acordo com a posição relativa (sempre contígua ou não) na memória de dois nós consecutivos na lista.

Alocação sequencial

A maneira mais simples de se manter uma lista linear na memória do computador é colocar seus nós em posições contíguas. Nesse caso, o endereço real do (j + 1)-ésimo nó da lista se encontra c unidades adiante daquele correspondente ao j-ésimo. A constante c é o número de palavras de memória que cada nó ocupa.

Seja uma lista linear. Cada nó é formado por campos, que armazenam as características distintas dos elementos da lista. Além disso, cada nó da lista possui, geralmente, um identificador, denominado chave. Para evitar ambiguidades supõe-se que todas as chaves são distintas. Os nós podem ser ordenadso ou não, segundo suas chaves.

Busca por um nó conhecendo sua chave

 busca1(x): i := 1; busca1 := 0 enquanto i <= n faça se L[i].chave == x então busca1 := i i := n+1 senão i := i+1 
Enter fullscreen mode Exit fullscreen mode

Algoritmo que cria um novo nó com a chave procurada

 busca(x): L[n+1] := x; i := 1 enquanto L[i].chave != x faça i := i+1 se i != n+1 busca := i senão busca := 0 
Enter fullscreen mode Exit fullscreen mode

Ambos algoritmos tem complexidade do pior caso O(n). Mas o segundo é mais rápido por fazer menos comparações.

Busca por um elemento na lista ordenada

 busca-ordenada(x): L[n+1] := x; i := 1 enquanto L[i].chave < x faça i := i+1 se i == n+1 ou L[i].chave != x então busca-ordenada := 0 senão busca-ordenada := i 
Enter fullscreen mode Exit fullscreen mode

Complexidade O(n).

Busca Binária

 busca-bin(x): inf := 1; sup := n; busca-bin := 0 enquanto inf <= sup faça meio := (inf+sup)/2 se L[meio].chave == x então busca-bin:=meio inf := sup+1 senão se L[meio].chave < x então inf := meio+1 senão sup := meio-1 
Enter fullscreen mode Exit fullscreen mode

Complexidade O(log n).

As operações de inserção e remoção utilizam a busca, tanto para evitar chaves duplicadas quanto para encontrar o elemento a ser removido. Os algoritmos de inserir e remover a seguir consideram uma lista não ordenada. A memória pressuposta disopnível tem M posições (M+1 pois é necessária uma posição extra para a busca).

Inserção de um nó com chave x

 se n < M então se busca(x) == 0 então L[n+1] := novo-valor n := n+1 senão "elemento já existe" senão overflow 
Enter fullscreen mode Exit fullscreen mode

Remoção de um nó com chave x

 se n != 0 então indice := busca(x) se indice != 0 então valor-recuperado:=L[indice] para i := indice até n-1 faça L[i] := L[i+1] n := n-1 senão "elemento não existe" senão underflow 
Enter fullscreen mode Exit fullscreen mode

Complexidade de ambos é O(n).

Alocação encadeada

Também conhecida por aloção dinamica uma vez que as posições de memória são alocadas conforme o necessário. Os nós de uma lista então encontram-se dispersos na memória e são interligados por ponteiros.

Qualquer estrutura, inclusive listas, que seja armazenada em alocação encadeada requer o uso de um ponteiro que indique o endereço de seu primeiro nó. O percurso de uma lista é feito então a partir desse ponteiro.

Imprimir uma lista encadeada
*ptlista é o ponteiro para o primeiro nó.

 pont := ptlista enquanto pont != null faça imprimir(pont->.info) pont := pont->.prox 
Enter fullscreen mode Exit fullscreen mode

Busca em uma lista ordenada
*pont é retornado apontando para o elemento procurado, ant aponta para o anterior e ptr vai percorrer a lista

 busca-enc(x, pont, ant) ant := ptlista; pont := null ptr := ptlista->.prox enquanto ptr != null faça se ptr->.chave < x então ant := ptr ptr := ptr->.prox senão se ptr->.chave == x então pont := ptr ptr := null 
Enter fullscreen mode Exit fullscreen mode

Complexidade O(n).

Inserção de um nó novo

 busca-enc(x, pont, ant) se pont == null então // alocar pt pt->.info := novo-valor pt->.chave := x pt->.prox := ant->.prox ant->.prox := pt senão "elemento já existe" 
Enter fullscreen mode Exit fullscreen mode

Remoção de um nó

 busca-enc(x, pont, ant) se pont != null então ant->.prox := pont->.prox // desalocar pt senão "nó não encontrado" 
Enter fullscreen mode Exit fullscreen mode

Complexidade de ambos é O(n).

Busca em uma lista não ordenada

 busca-enc(x, pont, ant) ant := ptlista; pont := null ptr := ptlista->.prox enquanto ptr != null faça se ptr->.chave == x então pont := ptr ptr := null senão ant := ptr ptr := ptr->.prox 
Enter fullscreen mode Exit fullscreen mode

Complexidade O(n).

Referência

Livro Estruturas de Dados e Seus Algoritmos

Top comments (0)