判断一串unicode字符在C ++中是否具有唯一字符的最有效方法是什么?

时间:2014-03-29 20:56:18

标签: c++ unicode hashmap unique

如果它只是ASCII字符,我只使用大小为256的bool数组。但是Unicode有很多字符。  维基百科说,unicode有超过110000个字符。那么bool [110000]可能不是个好主意?  2.假设这些字符正在流中,我只想在检测到重复时停止。我该怎么做呢?  由于集合太大,我在想哈希表。但是我怎么知道碰撞发生的时间,因为一旦检测到碰撞我不想继续。有没有办法在哈希表的STL实现中执行此操作?

在速度和内存利用率方面高效。

1 个答案:

答案 0 :(得分:1)

您的选项

有几种可能的解决方案:

  1. bool[0x110000](请注意,这是一个十六进制常量,而不是问题中的十进制常量)

  2. vector<bool>,尺寸为0x110000

  3. 对包含每个遇到的代码点的vector<uint32_t>list<uint32_t>进行排序

  4. map<uint32_t, bool>unordered_map<uint32_t, bool>包含代码点映射到是否遇到过

  5. set<uint32_t>unordered_set<uint32_t>包含遇到的每个代码点

  6. 自定义容器,例如a bloom filter为这类问题提供高密度概率存储

  7. 分析

    现在,让我们对6种变体进行基本分析:

    1. 确切地要求0x110000字节= 1.0625 MiB加上单个分配的开销。设置和测试都非常快。

    2. 虽然这似乎是完全相同的解决方案,但它只需要大约1/8的内存,因为它会将bool存储在一个中而不是一个每个字节。设置和测试都非常快,相对于第一个解决方案的性能可能更好或更差,这取决于cpu缓存大小,内存性能以及测试数据等。

    3. 虽然可能占用最少的内存(每个遇到的代码点需要4个字节,因此只要输入流最多包含0x110000 / 8/4 = 34816,它就需要更少的内存),此解决方案的性能将为非常糟糕:测试需要O(log(n))用于向量(二进制搜索)和O(n)用于列表(二进制搜索需要随机访问),而插入需要O(n)用于向量(所有后续元素必须移动)和O(1)列表(假设您保留了测试失败的结果)。这意味着,测试+插入周期需要O(n)。因此,您的总运行时间将为O(n ^ 2)...

    4. 如果不进行大量讨论,很明显我们不需要bool,而只是测试存在,导致解决方案5.

    5. 两个集的性能非常相似,set通常使用二叉树实现,unordered_set使用哈希映射。这意味着两者都是相当低效的内存:两者都包含额外的开销(树中的非叶节点和包含散列图中的散列的实际表)意味着它们可能每个条目需要8-16个字节。测试和插入是set的O(log(n))和unordered_set的摊销的O(1)。 要回答评论,请测试uint32 const x中是否包含unordered_set<uint32_t> data,如下所示:if(data.count(x))if(data.find(x) != data.end())

    6. 这里的主要缺点是开发商必须投入大量的工作。此外,作为示例给出的布隆过滤器是概率数据结构,意味着可能存在误报(在这种特定情况下不会出现假阴性)。

    7. 结论

      由于您的测试数据不是实际的文本数据,因此使用任何一种类型的实际上都非常低效(很有可能)。由于这也是实现比天真解决方案1和2更好的性能的唯一可能性,因此它很可能也会显着变慢。

      考虑到它更容易处理并且你似乎对内存消耗的相当意识这一事实,最终的结论是vector<bool>似乎是最合适的解决方案。

      注释

      Unicode旨在表示文本。这意味着您的测试用例以及随后的任何分析都可能存在严重缺陷。

      此外,虽然检测重复的代码点很简单,但字符的概念更加模糊,可能需要某种规范化(例如“ä”) “可以是one codepoint,也可以是”a“和diacritical mark,甚至可以基于cyrillic "a"。)