Aumentar-chave e diminuir-chave em um min-heap binário


16

Em muitas discussões sobre heap binário, normalmente apenas a tecla de diminuição é listada como operação suportada para um min-heap. Por exemplo, o capítulo 6.1 do CLR e esta página da Wikipedia . Por que a chave de aumento normalmente não está listada para min-heap? Imagino que seja possível fazer isso em O (altura) trocando iterativamente o elemento aumentado (x) pelo mínimo de seus filhos, até que nenhum deles seja maior que x.

por exemplo

IncreaseKey(int pos, int newValue)
{
   heap[pos] = newValue;
   while(left(pos) < heap.Length)
   {
      int smallest = left(pos);
      if(heap[right(pos)] < heap[left(pos)])
         smallest = right(pos);
      if(heap[pos] < heap[smallest])
      { 
         swap(smallest, pos);
         pos= smallest;
      }
      else return;
   }   
}

O acima está correto? Se não, por que? Se sim, por que a chave de aumento não está listada para min-heap?


1
Depois de ler todas as respostas, eu diria que é uma omissão estranha, provavelmente causada pelo primeiro uso histórico de min-heap no algoritmo Dijkstra.
maaartinus 29/09

3
É claro que você sempre pode implementar a tecla de aumento usando uma exclusão seguida por uma inserção e a própria exclusão pode ser implementada como chave de diminuição (para -∞) seguida por delete-min.
Davmac

O comentário @maaartinus é a resposta correta.
max

Respostas:


6

O algoritmo que você sugere é simplesmente heapify. E, de fato - se você aumentar o valor de um elemento em um min-heap e, em seguida, amontoar sua subárvore, você terminará com um min-heap legal.


então por que o CLR ou a lista da Wikipedia aumenta a chave para ser uma operação suportada? Meio que me enganou ao pensar que não é possível em um heap min
GatotPujo 2/13

Concordo que é enganoso, mas não vejo nenhum erro no algoritmo.
Shaull 02/03

5

A razão pela qual sua operação não está listada é que uma não está simplesmente interessada em todas as operações que podem ser facilmente implementadas usando uma determinada estrutura de dados, mas na outra maneira. Dado um conjunto de operações, qual é a maneira mais eficiente (em termos de espaço e tempo) de implementar essas operações. (Mas eu adiciono mais a isso depois)

Montes binários implementam a fila de prioridade da estrutura de dados abstratos, que solicita operações is_empty, add_element (uma chave com sua prioridade), find_min e delete_min. Filas mais avançadas também permitem diminuir a prioridade da chave (em um min_heap) ou até aumentá-la. De fato, você deu uma implementação.

Duas observações. Sua operação é usada na função heapify, que constrói eficientemente um heap a partir de uma matriz. No heapify, sua operação é repetida (a partir da última tecla).

Então, o mais importante, seu código usa a posição do nó. Para a fila de prioridade pura da estrutura de dados que está trapaceando. Essa estrutura de dados pede para executar uma certa operação dada uma chave. Portanto, para diminuir ou aumentar a prioridade de um elemento, você primeiro precisará localizá-lo. Eu acho que é a principal razão pela qual não está listado.


1
Obrigada pelo esclarecimento. No entanto, no CLR, a chave de diminuição também tem posição como nó como parâmetro.
GatotPujo

Você está certo. Não consegui encontrar uma razão para essa assimetria na definição de filas de prioridade na Seção.6.5 do CLRS. Observe que a tecla de aumento não é usada no Heapsort, a aplicação deste capítulo. Parece que a assimetria entre aumento e diminuição está relacionada apenas à maneira como a estrutura de dados é usada no algoritmo de Dijkstra, por exemplo. Lá (usando um min-heap), alguns nós selecionados podem se tornar mais urgentes e são movidos 'para cima' no heap.
Hendrik Jan

0

Penso que a primeira coisa a considerar é o que é uma operação suportada?

"Inserir um valor com uma chave fixa específica" (por exemplo, para chaves obtidas da região inteira, inserindo com a chave = 3) corresponde a uma operação suportada para a pilha mínima?

Não, porque essa operação pode ser implementada trivialmente com operações suportadas mais gerais. Da mesma forma, a inserção de 2 elementos de uma só vez pode ser feita com a insertoperação existente .

Por outro lado, a insertoperação não pode ser definida senão expondo os detalhes da implementação. É praticamente o mesmo para as operações listadas na página da Wikipedia, heapifyexceto, que provavelmente poderiam ser implementadas por uma sequência de insert.

Em outras palavras, existem operações elementares fornecidas no tipo, que estão fortemente vinculadas aos detalhes da implementação para que elas tenham um bom desempenho, e há outras operações que não cumprem essa regra e, portanto, podem ser implementadas como combinações dos canônicos.

Com essa definição em mente, você acha que a chave de aumento pode ser implementada com outras operações suportadas exclusivamente, sem perda de desempenho? Nesse caso, não é uma operação suportada pela definição acima; caso contrário, você pode estar certo.

Indiscutivelmente, a definição de uma operação suportada que forneço é minha, até onde eu sei. Não é formal e, portanto, sujeito a discussão (embora me pareça bastante claro). No entanto, eu ficaria feliz se alguém pudesse fornecer uma fonte que defina clara e inequivocamente o que é uma operação suportada para tipos de dados ou, pelo menos, defina-a em termos melhores que os meus (essa definição é dada no CLR? Não tenho uma cópia )

Meu segundo ponto será sobre como definimos uma fila de prioridade (que é a razão de ser dos heaps binários). A increase_keyoperação é necessária para esse tipo de dados, ou seja, para seu uso adequado?

Como você pode ver, meu ângulo é sobre definições. Na verdade, eu não respondo suas perguntas, apenas alguns indicadores; portanto, as melhorias são bem-vindas.


1
um exemplo de caso de uso pode ser se eu quiser manter uma fila prioritária de objetos com base nos usados ​​menos recentemente (por exemplo, para que eu possa excluir facilmente os objetos usados ​​menos recentemente). Eu posso usar um min-heap com a data do último acesso como chave. Se um objeto for acessado, sua chave precisará ser aumentada.
GatotPujo

Muito bom ponto. Meu ponto de vista é um pouco limitado, parece. Realmente, a resposta @HendrikJan traz uma explicação muito boa.
didierc
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.