关于 unorderedset 等容器的手写实现

引入

众所周知,\(C++11\) 的很多容器都非常好用,但是同时我们考试是不支持 \(C++11\) 的,于是我们必须手写,那么这里就来讨论一下手写两个非常好用的容器:\(unorderedset\)\(unorderedmap\)

准确的说是不去重的 \(unorderedmultiset\)

正文

问题

假设我们需要支持插入一个元素到集合内部,同时支持删除和判断存在性,求值等于一个数个数,以及遍历所有元素。

实现

实现1(懒删除栈+哈希表)

可以考虑维护一个懒删除的栈,具体来说就是先维护一个普通的栈,然后两个哈希表,一个维护每一个值对应的位置,另外一个维护每一个值的个数。(就是哈希当桶用)

然后我们每次添加和正常的栈一样,只不过要判断其本身是否出现。

而删除这里就是懒惰删除的办法,每次删除某个元素并把这个元素删除到0个时,直接把栈顶移动到那个位置去即可(我们之前也有记录每一个值对应的位置)。

当然,如果数据可以离散化或者值域范围并没有很大,那么可以直接使用桶来代替哈希表。

实现2(哈希表+链表)

我们的哈希表本身就可以实现“一个元素到集合内部,同时支持删除和判断存在性,求值等于一个数个数”,但是实现不了遍历所有元素。

但是其实这样也很简单,我们直接遍历哈希表所有的边,不就实现了遍历所有元素的目的吗?

但是这样复杂度可能会出问题,因为我们每次遍历都是 \(O(\)总边数\()\) 的,有了删除的话,就算加上垃圾回收,遍历也会变成 \(O(\)历史最大边数\()\)

那么考虑优化,其实删除不就是把一些位置变成了 0,就没有用了嘛,所以我们可以直接考虑链表来维护每一条边,把他们串起来即可。

代码实现

懒得写了,待补。

总结

实现 1 是我在CF1000F One Occurrence这道题当中的懒删除栈当中得到的启发,然后实现 2 是大佬给我说的,之前从未想到还可以遍历所有边来实现遍历哈希表的所有元素.......

总之,两种实现相对来说第一种比较简单,第二种稍显麻烦,代码实际运行效率还没有测试过,有兴趣测试的同学测试了的话可以自行比较各种做法的效率。

posted @ 2021-05-08 09:08  __Anchor  阅读(48)  评论(0编辑  收藏  举报