这就是问题:
给定一个包含一系列映射IP地址的平面文本文件 到某个地方(例如 192.168.0.0-192.168.0.255 =马萨诸塞州波士顿市,提出了一种算法,如果存在映射,它将为特定的IP地址找到一个城市。
我唯一的想法是解析文件,并将IP范围转换为整数(如果缺少数字则乘以10/100)并将它们放在一个列表中,同时将较低的范围放入哈希值中作为键将位置作为值。对列表进行排序并执行略微修改的二进制搜索。如果索引是奇数,则-1并查看散列。如果它是偶数,只需查看哈希。
我的计划中有任何错误,或更好的解决方案?
答案 0 :(得分:5)
你的方法似乎非常合理。
如果您对进行一些研究/额外编码感兴趣,那么算法将渐近地优于标准二进制搜索技术,该技术依赖于您的IP地址可以被解释为0到2范围内的整数这一事实 31 - 1.例如,van Emde Boas tree和y-Fast Trie数据结构可以实现您在时间O(日志日志U)中查看的前任搜索操作,其中U是最大可能的IP地址,而不是二进制搜索使用的O(log N)方法。然而,常数因素较高,这意味着无法保证这种方法会更快。但是,作为另一种可能更快的方法,可能值得探索。
希望这有帮助!
答案 1 :(得分:5)
问题是范围的气味,这个问题的一个好数据结构就是Segment Tree。 Some resources可帮助您入门。
段树的根可以表示地址(0.0.0.0 - 255.255.255.255)。左子树将表示地址(0.0.0.0 - 127.255.255.255),右子树将表示范围(128.0.0.0 - 255.255.255.255),依此类推。这将持续到我们达到无法进一步细分的范围。比方说,如果我们有一个范围32.0.0.0 - 63.255.255.255,映射到某个任意城市,它将是一个叶子节点,当我们到达那里时,我们不会进一步细分该范围,并将其标记到特定城市。
要搜索特定的映射,我们将按照树进行操作,就像在二进制搜索树中一样。如果您的IP位于左子树的范围内,请移至左侧子树,否则移至右侧子树。
好的部分:
请注意,在某些Segment Tree教程中,它们使用数组来表示树。这可能不是你想要的,因为我们不会填充整个树,所以动态分配节点,就像我们在标准二叉树中一样,是最好的。
答案 2 :(得分:1)
我唯一的想法是解析文件,并将IP范围转换为整数(如果缺少数字,则乘以10/100)...
如果遵循这种方法,您可能希望分别在地址A.B.C.D中将A,B,C和D乘以256 ^ 3,256 ^ 2,256和1。这有效地将IP地址重新创建为32位无符号数。
...并将它们放在列表中,同时还将范围中的较低者放入哈希值作为键,并将位置作为值。对列表进行排序并执行略微修改的二进制搜索。如果索引是奇数,则-1并查看散列。如果它是偶数,只需查看哈希。
我建议创建一个连续数组(std::vector
),其中包含具有较低和较高范围的结构(以及位置名称 - 在下面讨论)。然后正如你所说,你可以二元搜索包含特定值的范围,而不会有任何奇怪/偶然的麻烦。
使用范围的下端作为哈希中的键是避免在数组中为位置名称留出空间的一种方法,但考虑到城市名称中的平均字符数,指针的可能大小,a在稀疏填充的哈希表和长度位移列表之间进行选择,以便在连续的替代存储桶中搜索或进一步间接到任意长度的容器 - 你需要非常绝望地去尝试。首先,将结构中的位置与IP值范围一起存储似乎很好。
或者,您可以基于例如创建树。单个0-255个IP值:树中的每个级别可以是256个值的数组,用于直接索引,也可以是已填充值的已排序数组。这可以减少您可能需要进行的IP值比较(O(log2N)到O(1))。
答案 3 :(得分:0)
在您的示例中,192.168.0.0-192.168.0.255 =波士顿,MA。
条目中的两个IP地址的前三个八位字节(192.168.0)是否相同? 此外,前三个八位字节对于一个城市来说是独一无二的吗?
如果是这样,那么这个问题可以更容易解决