Вы можете сделать все это за ожидаемое амортизированное время. Суть в том, что нам не нужна полная мощность очереди с приоритетами, поскольку частота клавиш изменяется только на 1 при каждой вставке или удалении.O(1)
Мое решение, приведенное ниже, на самом деле является просто вашим решением с «неэффективной» очередью приоритетов, которая в данном случае работает хорошо: очередь с максимальным приоритетом, реализованная в виде двусвязных списков блоков ключей, имеет O (1) insertMin, deleteMax, removeFromBucket и increaseKey.
Поддерживайте двусвязный список Buckets, где у каждого Bucket есть непустой хэш-набор ключей (который я назову когортой) и положительное целое число (которое я назову ValCount). В сегменте b каждый ключ k в когорте b имеет одинаковое количество уникальных значений, связанных с ним в поддерживаемом вами наборе. Например, если в вашем наборе есть пары (a, яблоко), (a, авокадо), (b, банан), (c, огурец), (d, фрукт дракона), где отдельные буквы - это ключи, а фрукты - значения, то у вас будет два Buckets: один Bucket будет иметь ValCount 2 и Cohort, состоящий только из одного ключа: a. Другой Bucket будет иметь ValCount 1 и Cohort, состоящий из трех ключей b, c и d.
Список Bucket с двойной связью должен быть упорядочен ValCount. Будет важно, чтобы мы могли найти начало и конец списка за время и чтобы мы могли соединить новый Bucket за время O ( 1 ), если мы знаем его соседей. Единственно, я буду называть список Buckets BucketList.O(1)O(1)
В дополнение к BucketList нам понадобится SetMap, представляющий собой ключи отображения хеш-карты для ValueBuckets. ValueBucket - это пара, состоящая из ValueSet (непустой хэш-набор значений) и ненулевого указателя на Bucket. Набор значений, связанный с ключом k, содержит все уникальные значения, связанные с k. Указатель Bucket, связанный с ValueSet, имеет Cohort, равный размеру ValueSet. Bucket, связанный с ключом k в SetMap, также связан с ключом k в BucketList.
В 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;
Чтобы найти пару ключ-значение максимальной частоты, нам просто нужно взглянуть на заголовок BucketList, найти ключ в когорте, найти этот ключ в SetMap и найти значение в ValueSet его ValueBucket. (Уф!)
Вставить и удалить пары ключ-значение сложнее.
Чтобы вставить или удалить пару ключ-значение, мы сначала вставляем или удаляем ее в SetMap. Это изменит размер ValueSet, поэтому нам нужно изменить Bucket, связанный с ключом. Единственными Buckets, на которые нам нужно обратить внимание, чтобы внести это изменение, будут непосредственные соседи Bucket, в котором раньше находился ключ. Здесь есть несколько случаев, и их, вероятно, не стоит описывать полностью, хотя я был бы рад чтобы уточнить, если у вас все еще есть проблемы.