时间复杂度 当具有复合数据类型(如元组或对)时?

Time complexity when have composite data type such as tuple or pair?

本文关键字:元组 复合 数据类型 时间复杂度      更新时间:2023-10-16

在哈希映射数据结构中,例如C++中的unordered_map:

unodered_map<char, int> mp = { {'a', 10}, {'b', 20} };
if (mp.find('a') != mp.end())
cout << "found you";

我们知道 find(( 方法需要恒定的时间。 但是如果我有复合数据作为键:

unodered_map<tuple<char, string, int>, int> mp = { {'a', "apple", 10}, 100};
if (mp.find( {'a', "apple", 10} ) != mp.end())
cout << "found you";

find(( 方法还会占用常量时间吗? 现在如何评估时间复杂度?

通常,键中的数据字节越多,哈希函数生成值所需的时间就越长(尽管某些哈希函数不会查看每个字节,因此可以降低 big-O 复杂性(。 字节可能更多或更少,因为元组具有更多值,或者元组中的某些元素大小可变(如std::string(。 同样,对于更多的字节,测试两个键的相等性通常需要更长的时间,这是哈希表的另一个关键操作。

因此,您可以说表的操作与键的大小 - O(K( - 在所有其他条件相同的情况下线性缩放。

但是,更常见的是,你有兴趣比较任何给定插入/擦除/查找的性能与其他类型的容器所需的时间相比,并且在许多其他类型的容器中,随着您添加越来越多的键,性能往往会下降。 这就是人们将哈希表描述为通常具有摊销平均情况 O(1( 操作复杂性的地方,而例如平衡二叉树可能是 O(logN(,其中 N 是存储的元素数。

还有一些其他的考虑因素,例如平衡二叉树中的操作往往涉及比较(即key1 < key2(,它可能在第一个不同的字节处短路,而哈希函数往往必须处理密钥中的所有字节。

现在,如果在你的问题域中,键的大小可能变化很大,那么从 O(K( 复杂性的角度来考虑是有意义的,但如果键的大小倾向于徘徊在相同的典型范围内 - 无论您存储的键数量如何,那么表属性合理地表示为 O(1( - 删除近恒定的乘法因子。


我认为考虑一个熟悉的类比会有所帮助。 如果你的电话通讯录中存储了100个朋友的名字,或者你有一个大城市的电话簿中有数百万个名字,那么名字的平均长度可能非常相似,所以你可以非常合理地谈论数据结构的大O效率,用"N"来谈论你的数据结构,而忽略它随着名字长度"K"而缩小或增长的方式。

另一方面,如果您正在考虑将任意长度的密钥存储在哈希表中,并且有些人可能会尝试放置百科全书的XML版本,而其他人则存储小说,诗歌或单个单词,那么密钥长度有足够的多样性,可以用K来描述不同的性能是有意义的。

如果您正在存储二进制视频数据的信息,并且有人正在考虑使用原始二进制视频数据作为哈希表键,则同样如此:一些 8k HDR 和数小时长,还有一些微小的动画 GIF。 (更好的方法是生成视频数据的64+位哈希并将其用于密钥,对于大多数实际目的,该密钥将是可靠的唯一;如果处理数十亿个视频,则使用128位(。

理论上的运行时间实际上不是恒定的。在合理的用例下,运行时间仅在平均时保持不变。

在实现中使用哈希函数。如果为在常量时间内运行的元组实现(好的(哈希函数,则find的渐近运行时间不受影响。