【问题标题】:Best algorithm to find a key within a range from hashtable在哈希表范围内查找键的最佳算法
【发布时间】:2019-01-07 08:44:07
【问题描述】:

问题

从下面的项目列表中,我需要通过识别具有给定值的键范围来访问该项目,例如让我们说如果值是 2.1.1,它的单位是度、分和秒,我需要找到键 0.0.0- 30.0.0 性能是重中之重。

key: 0.0.0-30.0.0   value: x-y-z
key: 30.0.0-60.0.0  value: y-x-z
key: 60.0.0-90.0.0  value: z-y-z

解决方案 1: 到目前为止我尝试过的以下解决方案

如下重新创建新的键/值(json)文件

key: 0.0.0  value: x-y-z
key: 0.0.1  value: x-y-z
.
key: 0.0.59 value: x-y-z
.
key: 0.1.0 value x-y-z
key: 0.1.1 value x-y-z

key: 30.0.0  value: y-x-z
.
.
key: 30.0.59 value: y-x-z
.
key: 30.1.0 value: y-x-z
key: 30.1.1 value: y-x-z
key: 30.1.2 value: y-x-z
.
.
key: 30.1.59 value: y-x-z
key: 30.2.0 value: y-x-z
key: 30.2.1 value: y-x-z
key: 30-2.3 value: y-x-z
.
.
key: 60.0.0 value: z-y-x
key: 60.0.1 value: z-y-x
key: 60.0.2 value: z-y-x
.
.
key: 60.0.59 value: z-y-x
key: 60.1.0 value: z-y-x
key: 60.1.1 value: z-y-x
.
.

问题 上述解决方案的问题是文件大小将增加,这导致我的紧凑型应用程序中的堆溢出

解决方案2

?

【问题讨论】:

  • 范围是否重叠?是否有未映射的范围?我的第一个想法是将它们放入一个排序数组中,然后在其中进行二进制搜索。
  • 你的问题不够清楚。因此,您要做的是根据示例中从 0.0.0 到 30.0.0 的键范围获取键/值对的集合/列表,对吗?
  • Json 文件包含格式为 degfrom.minfrom.secfrom-degto.minto.secto 的密钥,输入将类似于 deg1.min1.sec1 我想要的是快速找到一个密钥范围其中 deg1.min1.sec1 属于
  • 键范围在排序数组中的二进制搜索可能很昂贵,因为这些不是直接数字,因此解析从 DMS 转换为十进制然后执行比较可能会出现性能问题,此函数每秒触发一次
  • 是否可以在内存中加载json文件内容。 json文件有多大?

标签: json hashmap hashtable


【解决方案1】:

使用 KD-tree 或 R-tree 数据结构而不是哈希映射。

【讨论】:

    【解决方案2】:

    由于您在第一个 json 中的条目是按顺序排序的,因此您可以解析您的输入并使用它来计算位置并生成条目的键。

    对于第一个列表,我会将输入值解析为 3 个整数。对于这个,我们只需要输入的第一部分(度)。 然后我们得到这样的位置:

     int position = input_degree / step_size;
    

    step_size 在您的第一个列表中为 30。

    如果您需要密钥,您现在可以使用位置生成它:

    String key_begin = position * step_size;
    String search_key = key_begin + ".0.0-" + key_begin+step_size + ".0.0";
    

    【讨论】:

      【解决方案3】:

      哈希表不太适合解决这个问题,因为当您可能查找的所有键都存储在表中时,哈希表效果最好:您说过您没有内存。二进制搜索确实是一个很好的方法,但是你提到......

      键范围在排序数组二进制搜索中可能很昂贵,因为这些不是直接数字,因此从 DMS 解析转换为十进制然后执行比较可能会出现性能问题,此函数每秒触发一次。

      首先,C++ 程序可以在不到一秒的时间内完成大量工作——即使是未经优化的查找也可能足够快地工作,但我们暂时假设你做到了需要更接近最佳速度...

      “从 DMS 解析”含糊不清,但我假设您的意思是您的程序中有一个键的文本表示,例如“2.1.1”:解析它几乎肯定比必须做一个更好使用文本比较查找。要以“C++ 风格”解析文本,您可以简单地使用...

      std::istringstream iss(the_incoming_key);
      int degree, minute, second;
      char c1, c2;
      if (iss >> degree >> c1 >> minute >> c2 >> seconds &&
          c1 == '.' && c2 == '.')
      {
          // have parsed a valid key...
      }
      else
          error_throw_exit_whatever();
      

      如果您准备使用较旧的 C 函数来提高速度,请考虑:

      if (sscanf(the_incoming_key.c_str(), "%d.%d.%d", &degree, &minute, &second) == 3)
          // have parsed a valid key...
      

      解析了密钥后,你可以合理地:

      1) 使用std::map<tuple<int8_t, int8_t, int8_t>, Value> values; 和使用std::make_tuple(degree, minute, second) 进行二分搜索,或者

      2) 使用std::map<int, Value> values; 和使用degree * 3600 + minute * 60 + second 进行二分搜索 - 总秒数 值可能会或可能不会更快地让您的计算机进行比较。

          虽然乘法有点慢,所以可以使用 (degree << 12) + (minute << 6) + second 来避免它,因为 6 位足以存储 0 到 59 之间的值。

      当然,在解析 json 文件和填充表时,您为创建密钥所做的任何转换都需要早先使用。

      为了进一步优化,您可以拥有一组 360 度地图,并索引到您想要查找分钟和秒组件的特定地图。将搜索空间除以 360 可以预期在每次地图查找时消除 8 或 9 次比较(因为每次比较都会使仍在争用的元素数量减半,而 360 介于 2^8 和 2^9 之间)。

      【讨论】:

      • 我想要 javascript 解决方案 thru' 您的解决方案看起来非常适合服务器端,但在我的情况下,每秒访问服务器可能也太贵了,希望这段代码可以移植到 javascript 让我试一试,谢谢反正
      • @Naga:哦,对不起——我通常专注于 C++ 问题,当我检查哈希表标签时忘记检查你使用的是哪种语言。一些谷歌搜索表明正则表达式通常用于 Javascript 中的解析 - 像 dms_string.match(/\\d+\\.?\\*/g) 这样的东西应该返回一个子字符串数组,您可以调用 Number 来提取整数值?对于您的客户端/服务器情况,我有点迷茫:如果您的搜索键来自客户端,那么您要么需要数据结构来在那里搜索,要么 ping 服务器 - 看不出那是怎么回事避免。
      猜你喜欢
      • 1970-01-01
      • 2012-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-19
      • 2015-07-09
      • 2021-08-03
      • 1970-01-01
      相关资源
      最近更新 更多