【问题标题】:Efficient mapping from 2^24 values to a 2^7 index从 2^24 值到 2^7 索引的高效映射
【发布时间】:2011-05-20 12:30:30
【问题描述】:

我有一个数据结构,其中存储一个 24 位宽的值。我有很多这些对象。

为了最小化存储成本,我从 2^24 个可能的值中计算出 2^7 个最重要的值,并将它们存储在一个静态数组中。因此,我只需在我的数据结构中为该数组保存一个 7 位索引。

问题是:我得到了这些 24 位值,我必须即时将它们转换为我的 7 位索引(无法进行预处理)。计算基本上是搜索 2^7 个值中最适合的一个。显然,对于大量对象,这需要一些时间。

一个明显的解决方案是创建一个长度为 2^24 的简单字节映射数组。但这需要 16 MB 的 RAM。太多了。

对 16 MB 数组的观察:平均 31 个连续值是相同的。不幸的是,还有许多不同的连续值。


您将如何实现从 24 位值到 7 位索引的这种转换,以尽可能多地节省 CPU 和内存?

【问题讨论】:

  • 你在编程什么,16MB太多了?电话?
  • @Steve 如果 16MB 不是太多,他一开始就不会这样做 :)
  • @Karl:如果他正确认为 16MB 太多了,那么他一开始就不会这样做。但是,如果他弄错了,他会:-) 这就是为什么这是评论,而不是答案。其实我的问题是修辞。我不需要答案,只是有时人们(包括我)不会质疑我们的限制,直到其他人提出质疑。
  • 如果你有“最重要”的价值观,为什么不把所有不重要的价值观都扔掉?
  • @Steve:是的,它在手机上 :-)

标签: algorithm performance search data-structures mapping


【解决方案1】:

你有多少个 2^24?您能否对这些值进行排序并通过计算连续值的数量来计算它们。

【讨论】:

  • 2^24 值使用所有位。
  • 所以你有所有可能的 2^24 值,这些值可以出现任意次数,并且你想知道每个数字出现多少次而不使用太多内存。我只能假设您的原始数据结构尚未在内存中,因为这将不得不使用比您所说的 16 MB 更多的空间。
【解决方案2】:

很难说不知道“最合适”的定义是什么。也许kd-tree 将允许基于某个度量或其他度量的接近度进行合适的搜索,以便您快速排除大多数候选者,并且只需要实际测试 2^7 中的几个,看看哪个是最好的?

这听起来类似于图像处理器在减少到更小的调色板时遇到的问题。我实际上并不知道为此使用了哪些算法/结构,但我确信它们是可查找的,并且可能会有所帮助。

【讨论】:

  • 色板问题确实类似。我会尝试在谷歌上找到一些代码。
  • 这些 24 位值是向量(x,y,z - 每个 8 位)。最佳拟合意味着“找到索引值和当前值之间的最大点积。
  • @Lars:嗯。如果重要的向量都具有相同的大小,这听起来很容易通过接近来缩小范围,如果它们不具有相同的大小,那么就没有那么多了。
【解决方案3】:

作为一个想法... 将索引表增加到 8 位,然后将 24 位字的所有 3 个字节异或到其中。 那么您的表将包含这个 8 位哈希值,加上返回原始 24 位值的索引。

由于您的数据类似于 RGB,因此可能需要更复杂的散列方法。


 bit24var        & 0x000f gives you the right hand most char.
(bit24var >> 8)  & 0x000f gives you the one beside it.
(bit24var >> 16) & 0x000f gives you the one beside that.

是的,你的想法是正确的。由于pigeon hole principal,一个或多个 24 位值很可能会散列到同一个索引。

解决哈希冲突的一种方法是使用某种链接。

【讨论】:

  • 我不确定我是否完全理解您的回答。 a) 我如何异或 3 个字节? (b1 ^ b2) ^ b3 ? b) 我的表将包含 8 位哈希值和返回 24 位值的一个索引列表?!
【解决方案4】:

由于您已经知道需要保留 2^24 值中的哪一个(即您确定重要的 2^7 值),我们可以简单地过滤传入的数据并分配一个值,从 0 开始到 2^7-1,当我们遇到这些值时。当然,我们需要一些方法来跟踪我们已经看到哪些重要值并​​在 [0,2^7) 中分配了标签。为此,我们可以使用某种基于树或哈希表的字典实现(例如 C++ 中的 std::map,Java 中的 HashMapTreeMap,或 Python 中的 dict)。

代码可能看起来像这样(我使用的值范围要小得多):

import random

def make_mapping(data, important):
    mapping=dict() # dictionary to hold the final mapping
    next_index=0 # the next free label that can be assigned to an incoming value
    for elem in data:
        if elem in important: #check that the element is important
            if elem not in mapping: # check that this element hasn't been assigned a label yet
                mapping[elem]=next_index
                next_index+=1 # this label is assigned, the next new important value will get the next label 
    return mapping

if __name__=='__main__':
    important_values=[1,5,200000,6,24,33]
    data=range(0,300000)
    random.shuffle(data)
    answer=make_mapping(data,important_values)
    print answer

您可以通过对重要值集使用基于散列/树的集合数据结构来加快搜索速度。这将使整个过程 O(n*log(k))(或 O(n),如果它是一个哈希表),其中 n 是输入的大小,k 是重要值的集合。

【讨论】:

    【解决方案5】:

    另一个想法是将您的重要值放在一个不同的数组中,然后简单地先搜索它。如果您在那里没有找到可接受的答案,那么您可以颤抖,搜索更大的数组。

    【讨论】:

      【解决方案6】:

      另一个想法是在位图中表示 24BitValue 数组。一个不错的 unsigned char 可以容纳 8 位,因此需要 2^16 个数组元素。那是 65536。如果设置了相应的位,那么您知道该特定的 24BitValue 存在于数组中,需要检查。

      需要一个迭代器来遍历数组并找到下一个设置位。有些机器实际上在其指令集中提供了“查找第一位”操作。

      祝你的任务好运。 让我们知道结果如何。

      邪恶。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-02-04
        • 1970-01-01
        • 1970-01-01
        • 2014-03-28
        • 2013-05-03
        • 1970-01-01
        相关资源
        最近更新 更多