我们如何为 C++ 无序集定制我们自己的哈希函数以获得特定的顺序?
Posted
技术标签:
【中文标题】我们如何为 C++ 无序集定制我们自己的哈希函数以获得特定的顺序?【英文标题】:How can we customize our own hash function for C++ unordered set to gain a specific order? 【发布时间】:2020-07-22 16:01:36 【问题描述】:在竞争性编码中,我们面临许多问题,我们必须按输入顺序提供输出。所以,我们需要制作自己的哈希函数。知道如何编写自己的哈希函数吗?
【问题讨论】:
您想订购一个无序的集合或映射吗? 如果您能找到一个具有 1 对 1 映射的哈希函数,那么您也可以找到它的逆函数,这将为您提供原始排序。 【参考方案1】:...你不能。 unordered_set
是无序的。编写自己的哈希函数不会改变这一点。一个特定的标准库实现可以为一个特定的散列函数和存储在unordered_set
中的一组特定数据持有一个订单。但是这样的代码不仅不能移植,而且可以通过向该集合添加更多内容来更改顺序。
如果您需要按照输入的顺序提供一些输出,那么您应该使用一个容器来保留您给它的顺序,例如vector
。
【讨论】:
【参考方案2】:由于无序容器的实现使用哈希表(标准几乎要求它们)和链表的单独链接,如果你确保桶的数量超过你的哈希函数的范围(使用reserve()
)那么很有可能 - 尽管不能保证 - 元素将按其哈希值的顺序存储,并且对于具有相同哈希值的元素按插入顺序存储。
我重申,这不能保证,但在一个知道你实现的编码竞赛中你可能会侥幸逃脱。
此外,这当然是低效的,因为您要么需要保留大量存储桶,需要大量内存使用,要么限制哈希函数的范围,从而导致冲突。使用有序容器会更好。
【讨论】:
【参考方案3】:我们如何为 C++ 无序集定制自己的哈希函数以获得特定的顺序?
你不能可靠地做你想做的事。
但是你为什么不使用std::set
(或std::map
)来达到这个目的呢?查看this C++ reference,并阅读好的C++ programming book(和C++11 标准n3337),了解更多信息。
我们不知道您的实际用例是什么,但我可能建议您创建自己的 class
,遵循 C++ rule of five,并拥有两者
std::map
和 std::hash_map
表示相同数学关系。
class YourClass
// incomplete, should follow the rule of five
private:
std::map<std::string, long> mapstr;
std::unordered_map<std::string, long> hashstr;
public:
void put(const std::string&str, long n)
mapstr.insert(str,n);
hashstr.insert(str,n);
/// etc...
;
当然,如果您正在编写多线程程序,则需要在上面的类中有一些 std::mutex
字段,以使用 std::lock_guard
序列化访问......
知道如何编写自己的哈希函数吗?
编写一个足够好的哈希函数通常很容易。
编写一个非常有效的哈希函数仍然可以让你获得博士学位,并且你会在ACM 赞助的会议上找到许多关于该主题的论文。
这是一个 simple 和 naive 对字符串的哈希函数:
std::size_t naive_string_hash(const std::string&str)
constexpr unsigned k1 = 78139; // a prime number
constexpr unsigned k2 = 98129; // another prime number
std::size_t h = 38197; // yet another prime number
for (char c: str)
h = (k1 * h) ^ (k2 * (unsigned)c);
return h;
您可以用+
替换按位独占或^
并阅读Bézout's identity。
推荐:研究现有 open source代码
我强烈建议寻找现有 C++ 开源代码(包括GCC 和Clang 的代码,它们都是C++ 编译器;或FLTK 或Qt) 可在 github 或 gitlab 等网站上找到。您可能需要征得您的经理的许可才能研究此类代码。
建议:阅读文档
我邀请您阅读您的 C++ 编译器(可能是 GCC 或 Clang)、您的链接器(可能是 binutils)、您的 source code editor(我喜欢 GNU emacs)、您的文档版本控制系统(例如git)。如果允许的话,我建议在你的电脑上使用 GNU/Linux 系统(例如Debian 或Ubuntu)(因为 Linux 主要是由开源组件组成的,其源代码你可以下载学习)。
另见http://linuxfromscratch.org/和https://norvig.com/21-days.html
【讨论】:
以上是关于我们如何为 C++ 无序集定制我们自己的哈希函数以获得特定的顺序?的主要内容,如果未能解决你的问题,请参考以下文章