您可以在预期摊销时间内完成所有这些操作。基本技巧是,我们不需要优先级队列的全部功能,因为在每次插入或删除期间,密钥频率只会改变1。O(1)
我下面的解决方案实际上只是您的解决方案,它具有一个“低效”优先级队列,该队列在这种情况下恰好适用:作为优先级双重存储桶列表实现的最大优先级队列具有O(1)insertMin,deleteMax,removeFromBucket和增加密钥。
维护一个双向链接的Bucket列表,其中每个Bucket都有一个非空的哈希键集(我将其称为Cohort)和一个正整数(即我的ValCount)。在存储桶b中,群组b中的每个键k在您要维护的集合中具有相同数量的唯一值。例如,如果您的集合包含(a,apple),(a,鳄梨),(b,香蕉),(c,黄瓜),(d,龙果)对,其中单个字母是键,而水果是值,那么您将拥有两个存储桶:一个存储桶的ValCount为2,而同类群组仅包含一个键:另一个Bucket的ValCount为1,而Cohort由三个键b,c和d组成。
双向链接的Bucket列表应由ValCount保持排序。这将是重要的是我们能找到的头和名单的尾巴时间,我们可以在一个新桶剪接Ø (1 )的时间,如果我们知道它的邻居。难以想象,我将“ Buckets”列表称为“ BucketList”。O(1)O(1)
除了BucketList,我们还需要一个SetMap,它是一个将键映射到ValueBuckets的哈希映射。ValueBucket是一对,由ValueSet(值的非空哈希集)和指向Bucket的非null指针组成。与键k关联的ValueSet包含与k关联的所有唯一值。与ValueSet关联的Bucket指针的Cohort等于ValueSet的大小。与SetMap中的键k关联的Bucket也与BucketList中的键k关联。
在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中查找该键并在其ValueBucket的ValueSet中找到一个值即可。(phe!)
插入和删除键值对比较麻烦。
要插入或删除键值对,我们首先将其插入或删除SetMap。这将更改ValueSet的大小,因此我们需要修改与键关联的Bucket。我们需要进行更改的唯一存储桶将是曾经使用该密钥的存储桶的直接邻居。这里有几种情况,尽管我很乐意,但它们可能不值得详细说明详细说明您是否仍然遇到麻烦。