ESTRUTURA DE DADOS E ALGORITMOS HEAPS E LISTAS DE …boeres/slides_ed/ed_Heap.pdf · 2018. 10....

Post on 14-Oct-2020

1 views 0 download

Transcript of ESTRUTURA DE DADOS E ALGORITMOS HEAPS E LISTAS DE …boeres/slides_ed/ed_Heap.pdf · 2018. 10....

ESTRUTURA DE DADOS E ALGORITMOS

HEAPS E LISTAS DE PRIORIDADES

Listas de Prioridades

!  Em muitas aplicações, dados de uma coleção são acessados por ordem de prioridade

!  A prioridade associada a um dado pode ser qualquer coisa:

●  tempo, custo, etc, mas precisa ser um escalar

!  operações comuns (eficientes)

●  Seleção do elemento com maior (ou menor) prioridade

●  Remoção do elemento de maior (ou menor) prioridade

●  Inserção de um novo elemento

Listas de Prioridades

!  Implementação

Operação Lista Lista ordenada Árvore balanceada

Heap

Seleção O(n) O(1) O(log n) O(1)

Inserção O(1) O(n) O(log n) O(log n)

Remoção (do menor)

O(n) O(1) O(log n) O(log n)

Alteração de prioridade

O(n) O(n) O(log n) O(log n)

Construção O(n) O(n log n) O(n log n) O(n)

Heaps - Listas de Prioridades

!  A relação entre as chaves pode ser MODELADA por árvores binárias ●  mas não é implementado por AB e nem ABB

!  Cada nó possui as propriedades ●  chave do nó i > chave à esquerda (se houver)

●  chave do nó i > chave à direita (se houver)

●  ainda não definimos quem está a esquerda e direita

!  a raiz contém a chave de maior prioridade !  este é elemento 1 da lista

!  Implementação: não como árvores ●  heaps são implementados usando vetores ou listas sequenciais

Heaps - Listas de Prioridades

!  Dado um nó armazenado no índice i, o índice ●  filho esquerdo de i : 2 i

●  filho direito de i : 2i + 1

●  nó pai de i : i div 2

!  A relação entre os elementos

si < s i/2

a b c d e f g h i j k 1 2 3 4 5 6 7 8 9 10 11

1 2 3 4 níveis

Heaps - Listas de Prioridades

!  Para armazenar uma árvore de altura h precisamos de um vetor de 2h – 1 elementos (no máximo)

●  número de nós de uma árvore cheia de altura h

a b c d e f g h i j k 1 2 3 4 5 6 7 8 9 10 11

1 2 3 4 níveis g f

a

c b

e d

i h k j

Heaps - Listas de Prioridades

Alteração do valor de uma chave (prioridade)

!  para manter a propriedade de heap, chaves podem migrar ●  para baixo (se ele diminuir de valor)

●  para cima (se ele aumentar de valor)

Heaps - Listas de Prioridades

Alteração do valor de uma chave (prioridade)

!  Para cada uma dessas situações utiliza-se um algoritmo de migração:

●  subir (i, n, S) - migra o nó i para cima no heap S

●  descer (i,n,S) - migra o nó i para baixo no heap S

"  n o número total de nós da heap

subir() – Alteração de prioridade

!  Pai de si – elemento si/2

subir (i, n, S [1 .. n]) {

se i > 1 e S [i/2] < S [i] então {

temp = S[i]; S[i]=S[i/2]; S[i/2]=temp;

Subir (i/2, n, S)

} }

descer() – Alteração de prioridade

descer (i, n, S [1 .. n]) {

se 2i+1 ≤ n e S [2i+1] > S [2i]

então filho = 2i+1;

senão filho = 2i;

se filho ≤ n e S [filho] > S [i] então {

temp = S[i]; S[i]=S[filho]; S[filho]=temp;

descer (filho, n, S)

}

}

Construindo uma lista de prioridades

!  o valor na primeira posição, é o maior

construir_heap (S, n){ para i = 2, ..., n faça

subir (i, n, S); }

Construindo uma lista de prioridades

!  podemos também arranjar usando o descer

!  observamos que os elementos de n/2+ 1 em diante não tem filhos

!  então podemos descer de n/2 em direção a 1

arranjar (S, n){ para i = n/2, ..., 1 faça

descer(i, n, S); }

Construindo uma lista de prioridades

arranjar (S, n){ para i = n/2, ..., 1 faça

descer(i, n, S); }

1 2 3 4 5 6 7

i=3 40 37 95 42 23 51 27

descer (i, n, S [1 .. n]) { se 2i+1 ≤ n e S [2i+1] > S [2i] então filho = 2i+1; senão filho = 2i;

se filho ≤ n e S [filho] > S [i] então { temp = S[i]; S[i]=S[filho]; S[filho]=temp; descer (filho, n, S) }

}

Construindo uma lista de prioridades

1 2 3 4 5 6 7

i=3 40 37 95 42 23 51 27

i=2 40 42 95 37 23 51 27

arranjar (S, n){ para i = n/2, ..., 1 faça

descer(i, n, S); }

descer (i, n, S [1 .. n]) { se 2i+1 ≤ n e S [2i+1] > S [2i] então filho = 2i+1; senão filho = 2i;

se filho ≤ n e S [filho] > S [i] então { temp = S[i]; S[i]=S[filho]; S[filho]=temp; descer (filho, n, S) }

}

Construindo uma lista de prioridades

1 2 3 4 5 6 7

i=3 40 37 95 42 23 51 27

i=2 40 42 95 37 23 51 27

i = 1 95 42 40 37 23 51 27

95 42 51 37 23 40 27

arranjar (S, n){ para i = n/2, ..., 1 faça

descer(i, n, S); }

descer (i, n, S [1 .. n]) { se 2i+1 ≤ n e S [2i+1] > S [2i] então filho = 2i+1; senão filho = 2i;

se filho ≤ n e S [filho] > S [i] então { temp = S[i]; S[i]=S[filho]; S[filho]=temp; descer (filho, n, S) }

}

HeapSort

Ordenação

● Construir o heap

"  então, o valor na primeira posição, é o de maior valor

● Repetidamente trocar esse valor com o de sua posição ao final da lista m, naquela iteração, acertando o heap

HeapSort

Ordenação

arranjar (S, n); // controi o heap m = n;

enquanto m > 1 fazer { temp = S[1]; S[1]=S[m]; S[m]=temp;

m = m-1; descer (1, m, S);

}

HeapSort

arranjar(S,n); m = n;

enquanto m > 1 fazer { temp = S[1]; S[1]=S[m]; S[m]=temp;

m = m-1; descer (1, m, S)

}

1 2 3 4 5 6 7

arranjar 95 42 51 37 23 40 27

m=7 27 42 51 37 23 40 95

descer 51 42 27 37 23 40 95

51 42 40 37 23 27 95

m=6 27 42 40 37 23 51 95

....

Inserção em Heap

!  Para inserir nova chave em um heap H:

●  inserir um novo valor na posição n + 1 do heap

●  chamar subir(): acha a posição apropriada do novo valor x em relação aos valores já existentes no heap H

Proc inserir (x, n, H [1 ... TMAX]) { if ((n+1) <= TMAX) n ← n + 1; H [n] ← x; subir (n, n, H);

}

Remoção em um Heap

!  substituir a raiz H[1] por H[n]

!  Chamar descer()

!  Obs.: em heap, remoção é da chave de maior prioridade

proc Remover (n, H [1 .. n]) { H [1] ← H [n] n ← n – 1 Descer (1, n, H)

}

Construção de Heap

!  Se queremos construir um heap com n elementos, podemos recorrer a um algoritmo ingênuo, isto é, inserir os n elementos um a um num heap inicialmente vazio

● procedimento inserir()

!  Complexidade O(n log n)

● Por que?

Construção de Heap

!  Tem como melhorar a construção?

!  O que fazer?

Construção de Heap

!  Entretanto, pode-se construir o heap em O(n) pois:

●  As folhas da árvore não têm descendentes e portanto já estão em seus lugares na definição de heap (em relação aos filhos inexistentes)

"  são os elementos H [n/2 + 1] até H[n])

●  Somente os nós internos devem ser colocados em suas posições em relação a seus descendentes com descer()

"  elementos H [1] até H[n/2]

●  É preciso trabalhar de trás para frente desde n/2 até 1 pois as propriedades da heap são observadas apenas nos níveis mais baixos

Construção de Heap

!  Por isso o arranjar()

arranjar (n, H){ para i = n/2, ..., 1 faça descer(i,n, H); }

Complexidade da Construção de Heap

!  Suponhamos que a árvore seja cheia, sem perda de generalidade. Então,

●  n = 2h – 1, onde h é a altura

"  desses, apenas 2h–1 – 1 são nós internos

●  A raiz (1 nó) da árvore pode descer no máximo h – 1 níveis

●  Os dois (21) nós de nível 2 podem descer h – 2 níveis

●  Os quatro (22) nós do nível 3 podem descer h – 3 níveis

●  .....

●  Os 2h – 2 nós de nível h – 1 podem descer 1 nível

●  Então, cada nível j tem no máximo piso(n/2j) nós

1

2

3

4

Complexidade da Construção de Heap

!  Logo, o número de passos totais é o somatório de :

●  j n/2j

●  que é O(n)

1

2

3

4

27

Máximos e Mínimos

#  Lista de prioridades #  acesso constante ao elemento de maior prioridade

#  Em uma generalização #  permitir acesso constante ao de menor prioridade

heap min-max #  lista linear S de chaves si

#  nivel(i) = log i +1 #  nó i está em

#  nível máximo se for par, #  senão, em nível mínimo

28

Máximos e Mínimos

S é um heap min-max se s1 é a menor chave e para todo i #  i está em um nível minimo

#  si <= si/2

#  si >= si/4

#  i está em um nível máximo #  si >= si/2

#  si <= si/4

29

Máximos e Mínimos

S é um heap min-max se s1 é a menor chave e para todo i #  i está em um nível mínimo

#  si <= si/2

#  si >= si/4

#  i está em um nível máximo #  si >= si/2

#  si <= si/4

20

70

8

4

35

38

19

30 28 18 25 36 37 26 22

s1

s2 s3

s4 s5 s6 s7

s8 s9

mínimo

máximo

mínimo

máximo

30

Máximos e Mínimos

•  s1 é a menor elemento •  o maior elemento é o maior entre os filhos da raiz

20

70

8

4

35

38

19

30 28 18 25 36 37 26 22

s1

s2 s3

s4 s5 s6 s7

s8 s9

mínimo

máximo

mínimo

máximo