Você pode fazer tudo isso em tempo esperado de amortização. O truque essencial é que não precisamos de toda a potência de uma fila prioritária, pois a frequência principal muda apenas 1 em cada inserção ou exclusão.O(1)
Minha solução abaixo é realmente apenas sua solução com uma fila de prioridade "ineficiente" que funciona bem para este caso: uma fila de prioridade máxima implementada como uma lista de baldes de chaves duplamente vinculada tem O (1) insertMin, deleteMax, removeFromBucket e raiseKey.
Mantenha uma lista de Buckets duplamente vinculada, em que cada Bucket possui um conjunto de chaves de hash não vazio (que chamo de Coorte) e um número inteiro positivo (que chamo ValCount). Em um Balde b, cada tecla k na Coorte de b tem o mesmo número de valores exclusivos associados a ela no conjunto que você está mantendo. Por exemplo, se o seu conjunto tiver os pares (a, maçã), (a, abacate), (b, banana), (c, pepino), (d, fruta do dragão) em que as letras únicas são as teclas e as frutas são os valores, você teria dois baldes: um balde teria um ValCount de 2 e um grupo que consistisse em apenas uma chave: a. O outro Balde teria um ValCount de 1 e uma Coorte que consistisse nas três chaves b, ce ed.
A lista duplamente vinculada de Bucket deve ser mantida ordenada pelo ValCount. Será importante que possamos encontrar a cabeça e o final da lista no tempo e que possamos dividir em um novo Balde no tempo O ( 1 ) se conhecermos seus vizinhos. Sem imaginação, chamarei a lista de Buckets de BucketList.O(1)O(1)
Além do BucketList, precisamos de um SetMap, que é um mapeamento de chaves de mapeamento de hash para ValueBuckets. Um ValueBucket é um par que consiste no ValueSet (um conjunto de valores de hash não vazio) e um ponteiro não nulo para um Bucket. O ValueSet associado a uma chave k contém todos os valores exclusivos associados a k. O ponteiro de bucket associado a um ValueSet tem uma coorte igual ao tamanho do ValueSet. O Balde associado a uma chave k no SetMap também está associado à chave k no BucketList.
Em C ++:
struct Bucket {
unsigned ValCount;
unordered_set<Key> Cohort;
Bucket * heavier;
Bucket * lighter;
};
Bucket * BucketListHead;
Bucket * BucketListTail;
struct ValueBucket {
unordered_set<Value> ValueSet;
Bucket * bucket;
};
unordered_map<Key, ValueBucket> SetMap;
Para encontrar um par de valores-chave de frequência máxima, basta olhar para o cabeçalho do BucketList, encontrar uma chave no Cohort, procurar essa chave no SetMap e encontrar um valor no ValueSet do ValueBucket. (ufa!)
Inserir e excluir pares de valores-chave é mais complicado.
Para inserir ou excluir um par de valores-chave, primeiro insira ou exclua-o no SetMap. Isso alterará o tamanho do ValueSet, portanto, precisamos modificar o Bucket associado à chave. Os únicos Buckets que precisaremos analisar para fazer essa alteração serão os vizinhos imediatos do Bucket que a chave costumava estar. Existem vários casos aqui, e provavelmente não valem a pena ser detalhados, embora eu fique feliz para elaborar se você ainda está tendo problemas.