我的问题是,它们是如何工作的以及如何实施?什么是
stl映射、哈希表和查找表之间的区别。
您正在寻找一种有效的机制,通过它您可以查找与给定键对应的值。
您当前的机制(一长串 if/else-if 命令)效率相当低,因为如果您有 N 个可能的值可供选择,您将(平均)必须将您的候选键与 (N/2) 个其他键进行比较找到匹配的键之前,您可以停止查找。 (这称为 O(N) 复杂度)
那么还有哪些其他选择呢?
最简单的一个实际上只是一个值数组,例如
const char* const myLookupTable[1000] = {
"zero",
"one",
"two",
[...]
"nine hundred and ninety-nine"
};
...使用这样的查找表,您可以获取一个键(在本例中是 0 到 999 之间的数字,包括 0 和 999),并使用单个数组查找来查找相应的值:
const char* val = myLookupTable[myKeyIndex];
这是超级高效的(O(1) 复杂度——无论数组有多大,它总是在恒定时间内完成!),但它只适用于键是连续(且相对较小)范围内的无符号整数的情况的价值观。例如,如果您的键是字符串,则此方法不适用。
为了获得更大的灵活性,下一个选择是 STLstd::map
. std::map
为您提供从任何键类型到任何值类型的快速键->值查找。在内部它被实现为tree https://en.wikipedia.org/wiki/Red%E2%80%93black_tree:每个键值对都以这样的方式插入树中,使得树保持排序,最小的键位于树的左侧,最大的键位于右侧。因此,在 a 中查找键(及其关联值)std::map
只需从树的根节点开始并将该节点的键与您正在查找的键进行比较:它是否小于您的键?然后转到右边的孩子。或者它比你的钥匙大?然后移动到左边的孩子。重复此操作,直到到达树的底部,此时您要么找到要查找的键值对,要么发现它不存在。这是一个复杂度为 O(log(N)) 的算法,因为对于其中有 N 个值的树,需要 log(N) 次比较才能完成查找。 O(log(N)) 被认为是相当不错的效率。
您提到的最终数据结构是哈希表 https://en.wikipedia.org/wiki/Hash_table(如所见std::unordered_map
)。哈希表的作用有点不同——在内部它是一个数组,但为了避免查找表方法的限制,它还附带了一种算法,用于找出给定键/值对在其数组中的位置被存储。它通过计算a来做到这一点哈希码对于您传入的键对象 - 然后使用该代码计算数组的偏移量(例如int array_offset = hash_code % array_size
)并查看数组中的该槽以查看请求的键值对是否存在。如果是,则完成(再次执行 O(1) 性能!);或者如果槽为空,则它知道您的密钥不在表中,并且可以立即返回失败(再次为 O(1))。如果该槽被其他一些键/值对占用,那么哈希表将需要回退到另一种算法来排序hash collision
;不同的哈希表处理方式不同,但通常仍然相当有效。