Análise de Algoritmos - Análise de operações em struturas de

Propaganda
Análise de complexidade de tempo em estruturas de dados lineares
Análise de Algoritmos
Análise de operações em struturas de dados lineares
Profa. Sheila Morais de Almeida
DAINF-UTFPR-PG
março - 2016
Listas ligadas
Análise de complexidade de tempo em estruturas de dados lineares
Listas ligadas
Pilhas e Filas
Pilhas e filas são estruturas onde os elementos a serem removidos
são pré-especificados.
Na pilha: o último que entra é o primeiro a ser removido.
Na fila: o primeiro que entra é o primeiro a ser removido.
Análise de complexidade de tempo em estruturas de dados lineares
Pilha
A operação de inserção em uma pilha é chamada de PUSH.
A operação de remoção em uma pilha é chamada de POP.
Pode-se implementar uma pilha de no máximo n elementos
utilizando-se um vetor com n posições.
Listas ligadas
Análise de complexidade de tempo em estruturas de dados lineares
Pilha
Considere que:
• S[1..n] é o vetor que contém a pilha;
• top(S) guarda a posição do topo da pilha no vetor;
• a pilha contém os elementos de S[1] a S[top(S)];
• S[1] é o elemento no fundo da pilha;
• S[top(S)] é o elemento no topo da pilha.
Exemplo...
Listas ligadas
Análise de complexidade de tempo em estruturas de dados lineares
Pilha
Quando top(S) = 0, a pilha está vazia.
stack-empty(S)
if(top(S) == 0)
return true;
else
return false;
Listas ligadas
Análise de complexidade de tempo em estruturas de dados lineares
Listas ligadas
Pilha
Se uma pilha vazia sofre operação de POP, dizemos que ocorre o
erro de stack underflows.
Se uma pilha cheia sofre operação de PUSH, dizemos que ocorre o
erro de stack overflows.
PUSH(S,x) //insere o elemento x no topo da pilha
if(top(S) < n)
{
top(S) = top(S) + 1;
S[top(S)] = x;
}
else
printf(“erro: stack overflows \n”);
Análise de complexidade de tempo em estruturas de dados lineares
Pilha
POP(S) //insere o elemento x no topo da pilha
if(stack-empty(S))
printf(“erro: stack underflows\n”);
else
{
top(S) = top(S) − 1;
return S[top(S) + 1];
}
Listas ligadas
Análise de complexidade de tempo em estruturas de dados lineares
Listas ligadas
Pilha
Todas as operações em uma pilha têm complexidade de tempo
O(1).
Análise de complexidade de tempo em estruturas de dados lineares
Listas ligadas
Fila
A operação de inserção em uma fila é chamada de ENQUEUE.
A operação de remoção de uma fila é chamada de DEQUEUE.
Em uma fila, o primeiro elemento inserido é o primeiro elemento
removido.
Filas têm cauda e cabeça. Quando um elemento é inserido, entra
na cauda.
Um elemento na cabeça é o próximo a ser removido.
Exemplo...
Análise de complexidade de tempo em estruturas de dados lineares
Listas ligadas
Fila
• head(Q): posição da cabeça da fila;
• tail(Q): posição em que um próximo elemento será inserido.
• Todos os elementos da fila estão entre as posições
head(Q), head(Q) + 1, head(Q) + 2, . . . , tail(Q) − 1,
considerando que se a fila atingir a posição n, então ela
continua na posição 1, em ordem circular.
• A fila está vazia quando head(Q) == tail(Q).
• Inicialmente, head(Q) = tail(Q) = 1.
• Quando a fila está cheia, head(Q) = tail(Q) + 1.
Análise de complexidade de tempo em estruturas de dados lineares
Fila
ENQUEUE(Q,x)
if(head(Q) == tail(Q) + 1)
printf(“erro: queue overflows\n”);
else
{
Q[tail(Q)] = x;
if(tail(Q) == length(Q))
tail(Q) = 1;
else
tail(Q) = tail(Q) + 1;
}
Listas ligadas
Análise de complexidade de tempo em estruturas de dados lineares
Fila
DEQUEUE(Q)
if(head(Q) == tail(Q))
printf(“erro: queue underflows\n”);
else
{
x = Q[head(Q)];
if(head(Q) == length(Q))
head(Q) = 1;
else
head(Q) = head(Q) + 1;
}
return x;
Listas ligadas
Análise de complexidade de tempo em estruturas de dados lineares
Listas ligadas
Fila
Cada operação na fila tem complexidade de tempo O(1) na fila.
Análise de complexidade de tempo em estruturas de dados lineares
Listas ligadas
Listas ligadas
Suponha uma lista ligada não-ordenada.
Busca na lista ligada
A função list-search(L,k) encontra o primeiro elemento com chave
k na lista L, realizando uma busca linear simples e retornando um
apontador para esse elemento.
Se não houver elemento com a chave k na lista, a função retorna
Nil.
Análise de complexidade de tempo em estruturas de dados lineares
Listas ligadas
list-search(L,k)
x = head(L);
while(x 6= Nil && key (x) 6= k)
x = next(x);
return x;
Pior caso da função list-search: Θ(n).
Listas ligadas
Análise de complexidade de tempo em estruturas de dados lineares
Listas ligadas
Inserção na lista ligada
list-insert(L,x)
next(x) = head(L);
if(head(L) 6= Nil)
prev [head(L)] = x;
head(L) = x;
prev (x) = Nil;
O tempo de execução da função list-insert(L,x) é O(1).
Listas ligadas
Análise de complexidade de tempo em estruturas de dados lineares
Listas ligadas
Listas ligadas
Remoção da lista ligada
O procedimento de remoção da lista retira o elemento da lista L.
Primeiro executa-se a função list-search(L,x) que procura pelo
elemento x, na lista L; depois atualizam-se os apontadores:
list-delete(L,x)
if(prev (x) 6= Nil)
next(prev (x)) = next(x);
else
head(L) = next(x);
if(next(x) 6= Nil)
prev (next(x)) = prev (x);
Análise de complexidade de tempo em estruturas de dados lineares
Listas ligadas
Listas ligadas
list-delete executa em tempo O(1), mas Θ(n) é necessário no pior
caso para procurar o elemento na lista L.
Análise de complexidade de tempo em estruturas de dados lineares
Listas ligadas
Listas ligadas - Sentinelas
Sentinelas
O uso de sentinelas pode simplificar o código da função list-delete.
Podemos ignorar os limites da cabeça e da cauda, criando uma
lista duplamente ligada circurlar.
Exemplo...
Análise de complexidade de tempo em estruturas de dados lineares
Listas ligadas
Listas ligadas - Sentinelas
Cria-se um objeto nil(L) que representa Nil, mas tem todos os
campos da estrutura nó.
Essa sentinela e colocada entre a a cabeça e a cauda da lista.
O campo next(nil(L)) aponta para a cabeça da lista.
O campo prev (nil(L)) aponta para a cauda da lista.
O campo next da cauda aponta para nil(L).
O campo prev da cabeça aponta nil(L).
Assim, pode-se eliminar head(L).
Exemplo...
Análise de complexidade de tempo em estruturas de dados lineares
Listas ligadas - Sentinelas
list-delet’(L,x)
next(prev (x)) = next(x);
prev (next(x)) = prev (x);
list-searc’(L,x)
x = next(nil(L));
while(x 6= nil(L) && key (x) 6= k)
x = next(x);
return x;
Listas ligadas
Análise de complexidade de tempo em estruturas de dados lineares
Listas ligadas - Sentinelas
list-inser’(L,x)
next(x) = next(nil(L));
prev (next(nil(L))) = x;
next(nil(L)) = x;
prev (x) = nil(L);
Listas ligadas
Análise de complexidade de tempo em estruturas de dados lineares
Listas ligadas
Listas ligadas - Sentinelas
Sentinelas raramente reduzem a complexidade assintótica das
estruturas de dados, mas podem reduzir as constantes.
O ganho de se usar sentinelas é mais relacionado à clareza do
código que ao tempo de execução.
No caso das listas, o tempo melhorou em O(1).
Existem casos em que o uso de sentinelas reduz o tempo de
execução de um laço, melhorando o tempo em O(n) ou O(n2 ).
Sentinelas não devem ser usadas indiscriminadamente. Se
houverem muitas listas pequenas, o uso de sentinelas pode ser um
desperdı́cio de memória significativo.
Download