Projetos de Algoritmos II
UFPA
Aplicações: cálculo de árvores geradoras mínimas e busca por menores caminhos dada uma
origem.
É um bom exemplo de estrutura de dados projetada com análise amortizada em mente.
Não foi projetada para dar um suporte eficiente a operação SEARCH.
Um Heap Mesclável é qualquer estrutura de dados que suporta as cinco seguintes operações,
nas quais cada elemento tem uma chave:
Heap Mesclável
1. MAKE-HEAP(), cria e retorno um heap vazio.
2. INSERT(H,X), insere o elemento x, cuja chave já tenha sido definida, no heap H.
3. MINIMUN(H), retorna um ponteiro para o elemento no heap H cuja chave é mínima.
4. EXTRACT-MIN(H), deleta o elemento do heap H cujoa chave é mínima, retornando um
ponteiro para o elemento.
5. UNION(H1,H2), cria e retorno um heap que contem todos os elementos dos heaps H1 e H2.
Os heaps h1 e H2 são destruídos nesta operação.
Heap de Fibonacci
Estrutura
Um Heap de Fibonacci é um conjunto de árvores que são heaps mínimos. Cada árvore
obedece a propriedade do heap mínimo:
A chave de um dado nodo é maior ou igual da chave do seu pai.
Cada nodo x do heap de Fibonacci tem um ponteiro x.p para seu pai e um ponteiro x.child
para cada um de seus filhos.
Todos os filhos do nodo x são unidos por meio de uma lista.
Circular e duplamente encadeada. Esta lista é uma chamada de lista de filhos de x.
Cada filho y tem os ponteiros y.left e y.right que apontam para os seus irmãos da esquerda
e direita respectivamente.
Se o nodo y não tiver irmãos, então y.left = y.right = y.
Os irmãos podem aparecer na lista de filhos em qualquer ordem.
As listas circulares têm duas vantagens:
Um Heap de Fibonacci H é acessado por um ponteiro H.min para a raiz de uma árvore
contendo a menor chave.
Este nodo é chamado de nodo mínimo do Heap de Fibonacci.
As raízes de todas as árvores são unidas por ponteiros left e right em um lista
circular e duplamente encadeada, chamada lista de raízes do Heap de Fibonacci.
Existe ainda o atributo H.n que armazena o número de nodos correntes no Heap H.
Para um Heap de Fibonacci H, indica-se por t(H) o número de árvores na lista de Raízes
de H e m(H) o número de nodos marcados em H.
Criação
Para criar um Heap de Fibonacci vazio, a função MAKE-FIB-HEAP aloca e retorna um
objeto tipo Heap de Fibonacci H, onde.
H.n = 0
H.min = NIL
Não existem árvores em H
Devido ao fato de t(H) = 0 e m(H) = 0, o potencial é Φ (H) = 0.
Assim, o custo amortizado da função MAKE-FIB-HEAP é O(1)
Inserção
Assumindo que um dado nodo x já tenha sido alocado e que x.key já tenha sido
preenchida, é possível inserir este nodo em um Heap de Fibonacci da seguinte forma,
FIB-HEAP-INSERT(H, x)
1 x.degree = 0
2 x.p = NIL
3 x.child = NIL
4 x.mark = FALSE
5 if H.min == NIL
6 create a root list for H containing just x
7 H.min = x
8 else insert x into H0s root list
9 if x.key < H.min.key
10 H.min = x
11 H.n = H.n + 1
Uma vez que o custo atual é O(1), o custo amortizado é O(1) + 1 = O(1).
Mínimo
O nodo mínimo de um Heap de Fibonacci é sempre dado pelo ponteiro H.min.
Assim, é possível encontrar o nodo mínimo em tempo constante O(1).
Devido ao fato que o potencial de H não se alterar, o custo amortizado desta operação
também é O(1).
União
FIB-HEAP-UNION(H1,H2)
1 H =MAKE-FIB-HEAP()
2 H.min = H1
3 concatenate the root list of H2 with the root list of H
4 if (H1.min == NIL) or (H2.min 6= NIL and H2.min.key < H1.min.key)
5 H.min = H2.min
6 H.n = H1.n + H2.n
7 return H
Extração
A extração do nodo mínimo é a operação mais complicada desta seção.
O pseudo código a seguir extrai o nodo mínimo de um Heap de Fibonacci.
É assumido que quando um nodo é extraído de uma lista encadeada, os
ponteiros remanescentes da lista são atualizados, mas os ponteiro do
nodo extraído são deixados inalterados.
Este pseudo código também realiza a chamada a função CONSOLIDATE,
a qual consolida as árvores presentes na lista de raiz de H.
FIB-HEAP-EXTRACT-MIN(H)
1 z = H.min
2 if z 6= NIL
3 for each child of z
4 add x to the root list of H
5 x.p = NIL
6 remove z from the root list of H
7 if z == z.right
8 H.min = NIL
9 else H.min = z.right
10 CONSOLIDATE(H)
11 H.n = H.n − 1
12 return z
Na linha 1, o ponteiro z aponta para o o nodo mínimo de H, H.min. O função retorna este
ponteiro ao termino.
Se z = NIL então o Heap de Fibonacci ´e vazio.
Caso contrário, deleta-se z de H fazendo todos os filhos de z raízes de H (linhas
3-5), removendo-se z da lista de raiz de H (linha 6).
Se z é o seu próprio irmão direito apos a linha 6, então z era o único nodo na
lista de raiz e este não tinha filhos, faltando apenas fazer o Heap de Fibonacci
ser vazio (linha 8).
Caso contrário, H.min ´e ajustado ser o irmão direito de z. Observe que não
necessariamente este ´e o nodo mínimo.
O próximo passo é reduzir o número de árvores no Heap de
Fibonacci, consolidando a lista de raiz de H – invoca-se a
função CONSOLIDATE.
Consolidar a lista de raiz ´e repetidamente executar os seguintes passos até toda raiz na lista
de raízes ter um grau distinto.
1. Encontre duas raízes x e y na lista de raiz com o mesmo grau.
Sem perda de generalidade, faça x.key ≤ y.key.
2.Una y a x: remova y da lista de raiz, e faça y ser um filho de x invocando a função
FIB-HEAP-LINK. Esta função incrementa o atributo x.degree e limpa a marca de y.
Fib-Heap-Link (H,y,x)
1 remove y da lista raiz de H
2 cria um child no x, incrementando x.degree
3 y.mark = false
Decrease-key
Aqui mostramos como a redução de uma chave de um nó em um HF pode ser realizada com
custo amortizado O(1).
Mais adiante, mostraremos que a deleção de um nó pode ser executada em tempo amortizado
O(D(n)).
Essas operações não preservam a propriedade de que todas as árvores no HF são árvores
binomiais não ordenadas.
Estas árvores são “próximas” o suficiente para se limitar o grau máximo D(n) por o(lgn).
((t(H) + c) + 2 (m(H) – c +2)) – (t(H)+2m(H))=4 – c.
O(c) + 4 - c = O(1),
Delete
Conclusão