【问题标题】:Implementing a lookup array for an array of N integers of limited range为范围有限的 N 个整数数组实现查找数组
【发布时间】:2014-01-05 21:06:29
【问题描述】:

我有一个arr[N],需要为arr 可以采用的所有可能值集实现一个查找数组,例如数组为bool arr[N] 的最简单情况的 2^N 个可能值。

这可以通过定义一个 N 维布尔查找数组来完成。例如,对于 N=4 和 arr 是布尔值,它将是 bool lookup[2][2][2][2]。然后lookup 可以通过lookup[arr[0]][arr[1]][arr[2]][arr[3]] 存储和检索arr 的任何可能值。

这写起来很尴尬,而且性能可能也低效,因为N 变化很大,所以实际实现必须使用for 循环进行存储和检索。这是一个问题,因为查找是一种非常常见的操作,而使它们尽可能快是本练习的重点。

还有其他方法可以实现这个想法吗?我对布尔值arr 的解决方案感兴趣,可能使用某种位表示,以及更通用的解决方案,其中arr 中的值范围大于2。

【问题讨论】:

  • @FredOverflow:我相信。我正在遍历一个排列图,节点必须不会被访问两次,否则算法将无法在合理的时间内完成。此外,我正在以特定方式遍历图表,在大多数情况下,不必遍历所有排列或任何接近的排列。
  • 可能与 stackoverflow.com/questions/19709529/… 相关,但应适用于 bool,因为 std::vector<bool> 是专门的...

标签: c++ c arrays algorithm data-structures


【解决方案1】:

对于布尔值的情况,您确实应该使用位:任何易于处理的N 必须适合N^2 条目到内存中,在现代机器上的顺序为 2^32 到 2^38,所以无论如何你都无法联系到N = 64

也就是说,您可以为每个数组条目使用最低有效位,并简单地分配 2^N 值的存储区。然后,您的数组的位表示可以简单地用作此存储的索引。

类似这样的:

uint64_t compressArray(long length, bool* array) {
    uint64_t result = 0;
    for(long i = length; i--; ) result = (result << 1) | (array[i] ? 1 : 0);
    return result;
}

...

int* store = malloc(sizeof(*store) * (1 << N));
bool* array = ...;
// Now you can access the ints in store like this:
store[compressArray(N, array)] = 3;

【讨论】:

  • 谢谢,我认为对于可能值的范围为宽度 2 的情况(即 array 为布尔值),这是一个非常优雅的解决方案。仍然想考虑一个更宽的情况,例如 3 个可能的值。
  • 在这种情况下,您只需将(result &lt;&lt; 1) | (array[i] ? 1 : 0) 替换为result*3 + array[i](当然,这假设您使用值范围0、1、2)并将存储大小计算为@987654329 @ 我不会使用 pow() 函数来计算存储大小,它提供的精度比整数计算少。
【解决方案2】:

如果我理解正确的话... 对于布尔类型,如果您使用一维数组中的元素索引来表示您的位就足够了。 例如对于 arr[4]

ar[0] = 0, ar[1] = 0, ar[2] = 0, ar[3] = 0    0000 
ar[0] = 1, ar[1] = 0, ar[2] = 0, ar[3] = 0    0001
ar[0] = 0, ar[1] = 1, ar[2] = 0, ar[3] = 0    0010
ar[0] = 1, ar[1] = 1, ar[2] = 0, ar[3] = 0    0011

等等……

例如,对于包含从 1 到 3 的值的 arr,您可以对每个值使用两位。

【讨论】:

  • 是的,对于布尔情况,仅在单维布尔数组上使用索引的位表示既高效又简洁。但我不完全确定当可能有超过 2 个值时它仍然是最佳解决方案。例如,对于 3 个可能的值,每个存储的值都会浪费 1 位(因为您将使用两个位来存储 3 个可能的值)。
  • 不完全丢失,但我理解你的意思。可以使用某种方式来压缩数据,但它需要有关数据本身的知识。例如,如果 90% 的数据为“假”,您可能只将真值存储在某种哈希表中。
【解决方案3】:

以下可能会有所帮助:

因此,从您的示例中,ValueRange = 2 as bool 可以采用 2 个值; Size = N

#include <cassert>
#include <cstddef>

#include <vector>

template<typename T, int ValueRange, int Size>
class MultiArray
{
    static_assert(ValueRange > 1, "Need at least 2 or more values");
    static_assert(Size > 0, "Size should be strictly positive");
public:
    MultiArray() : values(computeTotalSize())
    {
        assert(!values.empty());
    }

    const T& get(const std::vector<size_t>& indexes) const
    {
        return values[computeIndex(indexes)];
    }
    T& get(const std::vector<size_t>& indexes)
    {
        return values[computeIndex(indexes)];
    }

    size_t computeIndex(const std::vector<size_t>& indexes) const
    {
        assert(indexes.size() == Size);

        size_t index = 0;
        size_t mul = 1;

        for (size_t i = 0; i != Size; ++i) {
            assert(indexes[i] < ValueRange);
            index += indexes[i] * mul;
            mul *= ValueRange;
        }
        assert(index < values.size());
        return index;
    }

    std::vector<size_t> computeIndexes(size_t index) const
    {
        assert(index < values.size());

        std::vector<size_t> res(Size);

        size_t mul = values.size();
        for (size_t i = Size; i != 0; --i) {
            mul /= ValueRange;
            res[i - 1] = index / mul;
            assert(res[i - 1] < ValueRange);
            index -= res[i - 1] * mul;
        }
        return res;
    }

private:
    size_t computeTotalSize() const
    {
        size_t totalSize = 1;

        for (int i = 0; i != Size; ++i) {
            totalSize *= ValueRange;
        }
        return totalSize;
    }

private:
    std::vector<T> values;
};

所以像这样使用它:

int main()
{
    MultiArray<int, 2, 4> m;

    m.get({0, 0, 1, 0}) = 42;
    m.get({1, 1, 0, 0}) = 42;

    // Just for test purpose:
    for (size_t i = 0; i != 16; ++i) {
        assert(m.computeIndex(m.computeIndexes(i)) == i);
    }
    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-27
    • 1970-01-01
    • 2019-10-17
    • 2013-02-23
    • 1970-01-01
    • 2013-11-19
    • 2020-01-10
    相关资源
    最近更新 更多