迭代[0..n]没有数组。

时间:2021-11-18 11:33:23

I know of a couple of routines that work as follows:

我知道有几个程序可以工作如下:

Xn+1 = Routine(Xn, max)

Xn + 1 =例程(Xn马克斯)

For example, something like a LCG generator:

例如,LCG发生器:

Xn+1 = (a*Xn + c) mod m

Xn+1 = (a*Xn + c)对m取余

There isn't enough parameterization in this generator to generate every sequence.

这个生成器中没有足够的参数化来生成每个序列。

Dream Function:

梦的功能:

Xn+1 = Routine(Xn, max, permutation number)

Xn+1 =例程(Xn, max,置换数)

This routine, parameterized by an index into the set of all permutations, would return the next number in the sequence. The sequence may be arbitrarily large (so storing the array and using factoradic numbers is impractical.

该例程由索引参数化到所有排列的集合中,将返回序列中的下一个数字。这个序列可能是任意大的(所以存储数组和使用因子号是不切实际的。

Failing that, does anyone have pointers to similar functions that are either stateless or have a constant amount of state for arbitrary 'max', such that they will iterate a shuffled list.

如果做不到这一点,是否任何人都有指向类似函数的指针,这些函数要么是无状态的,要么是为任意的“max”具有恒定数量的状态,这样它们就会迭代一个打乱的列表。

6 个解决方案

#1


4  

There are n! permutations of n elements. Storing which one you're using requires at least log(n!) / log(2) bits. By Stirling's approximation, this takes roughly n log(n) / log (2) bits.

有n !n个元素的排列。存储您正在使用的日志至少需要log(n!) / log(2)位。通过斯特林近似,这大约需要n log(n) / log(2)位。

Explicitly storing one index takes log(n) / log(2) bits. Storing all n, as in an array of indices takes n times as many, or again n log(n) / log(2). Information-theoretically, there is no better way than explicitly storing the permutation.

显式存储一个索引需要日志(n) / log(2)位。存储所有n,就像在一个索引数组中那样需要n倍的数量,或者同样需要n log(n) / log(2)从理论上讲,没有比显式存储置换更好的方法了。

In other words, the index you pass in of what permutation in the set you want takes the same asymptotic storage space as just writing out the permutation. If, for, example, you limit the index of the permutation to 32 bit values, you can only handle permutations of up to 12 elements. 64 bit indices only get you up to 20 elements.

换句话说,你在你想要的集合中传递什么置换的索引具有和写出置换一样的渐近存储空间。例如,如果将排列的索引限制为32位值,则只能处理最多12个元素的排列。64位索引只能得到20个元素。

As the index takes the same space as the permutation would, either change your representation to just use the permutation directly, or accept unpacking into an array of size N.

由于索引占用的空间与置换的空间相同,因此要么将表示形式更改为直接使用置换,要么接受对大小为N的数组进行解压。

#2


3  

From my response to another question:

从我对另一个问题的回答:

It is actually possible to do this in space proportional to the number of elements selected, rather than the size of the set you're selecting from, regardless of what proportion of the total set you're selecting. You do this by generating a random permutation, then selecting from it like this:

实际上,在空间上做这个是有可能的,它与所选元素的数量成正比,而不是与所选的集合的大小成反比,无论所选的集合占多大的比例。通过生成随机排列,然后像这样选择:

Pick a block cipher, such as TEA or XTEA. Use XOR folding to reduce the block size to the smallest power of two larger than the set you're selecting from. Use the random seed as the key to the cipher. To generate an element n in the permutation, encrypt n with the cipher. If the output number is not in your set, encrypt that. Repeat until the number is inside the set. On average you will have to do less than two encryptions per generated number. This has the added benefit that if your seed is cryptographically secure, so is your entire permutation.

选择一个块密码,如茶或茶。使用XOR折叠将块的大小减少到比您选择的集合大2倍的最小功率。使用随机种子作为密码的钥匙。要在置换中生成元素n,请使用密码加密n。如果输出号不在集合中,请加密它。重复,直到数字在设置中。平均来说,每个生成的数字必须进行少于两个的加密。这有一个额外的好处,如果您的种子是加密安全的,那么您的整个排列也是安全的。

I wrote about this in much more detail here.

我在这里写了更多的细节。

Of course, there's no guarantee that every permutation can be generated (and depending on your block size and key size, that may not even be possible), but the permutations you can get are highly random (if they weren't, it wouldn't be a good cipher), and you can have as many of them as you want.

当然,不能保证每个排列可以生成(取决于你的块大小和关键尺寸,甚至是不可能的),但排列可以得到高度随机的(如果他们不是,它不会是一个很好的密码),你可以尽可能多的你想要的。

#3


1  

If you are wanting a function that takes up less stack space, then you should look into using an iterated version, rather than a function. You can also use a datastructure like a TreeMap, and have it stored on disk, and read on an as needed basis.

如果您想要一个占用较少堆栈空间的函数,那么应该使用迭代版本,而不是函数。您还可以使用TreeMap之类的数据结构,并将其存储在磁盘上,并根据需要进行读取。

X(n+1) = Routine(Xn, max, permutation number)
for(i = n; i > 0; i--)
 {
   int temp = Map.lookup(i) 
   otherfun(temp,max,perm)
 }

#4


0  

Is it possible to index a set of permutations without previously computing and storing the whole thing in memory? I tried something like this before and didn't find a solution - I think it is impossible (in the mathematical sense).

是否可以索引一组排列,而不需要以前计算和存储整个东西在内存中?我以前尝试过类似的方法,但没有找到解决方案——我认为这是不可能的(从数学的角度来看)。

Disclaimer: I may have misunderstood your question...

免责声明:我可能误解了你的问题……

#5


0  

Code that uses an iterate interface. Time complexity is O(n^2), Space complexity has an overhead of: copy of n (log n bits), an iteration variable (log n bits), keeping track of n-i (log n bits), , copy of current value (log n bits), copy of p (n log n bits), creation of next value (log n bits), and a bit set of used values (n bits). You can't avoid an overhead of n log n bits. Timewise, this is also O(n^2), for setting the bits. This can be reduced a bit, but at the cost of using a decorated tree to store the used values.

使用迭代接口的代码。时间复杂度是O(n ^ 2),空间复杂性的开销:副本n(log n比特),迭代变量(log n比特),跟踪n(log n位),当前值(log n比特)的副本,副本p(n O(log n)比特),创造未来价值(log n比特),和一点组使用的值(n比特)。你无法避免n log n位的开销。Timewise,这也是O(n ^ 2),设置部分。这可以减少一点,但代价是使用装饰树来存储所使用的值。

This can be altered to use arbitrary precision integers and bit sets by using calls to the appropriate libraries instead, and the above bounds will actually start to kick in, rather than being capped at N=8, portably (an int can be the same as a short, and as small as 16 bits). 9! = 362880 > 65536 = 2^16

这可以改变使用任意精度整数和点集通过调用适当的库相反,和上面的界限会开始发挥作用,而不是限制在N = 8,轻松(int可以一样短,和小至16位)。9 != 362880 > 65536 = 2 ^ 16

#include <math.h>
#include <stdio.h>

typedef signed char index_t;
typedef unsigned int permutation;

static index_t permutation_next(index_t n, permutation p, index_t value)
{
    permutation used = 0;
    for (index_t i = 0; i < n; ++i) {
        index_t left = n - i;
        index_t digit = p % left;
        p /= left;
        for (index_t j = 0; j <= digit; ++j) {
            if (used & (1 << j)) {
                digit++;
            }
        }
        used |= (1 << digit);
        if (value == -1) {
            return digit;
        }
        if (value == digit) {
            value = -1;
        }
    }
    /* value not found */
    return -1;
}

static void dump_permutation(index_t n, permutation p)
{
    index_t value = -1;
    fputs("[", stdout);
    value = permutation_next(n, p, value);
    while (value != -1) {
        printf("%d", value);
        value = permutation_next(n, p, value);
        if (value != -1) {
            fputs(", ", stdout);
        }
    }
    puts("]");
}

static int factorial(int n)
{
    int prod = 1;
    for (int i = 1; i <= n; ++i) {
        prod *= i;
    }
    return prod;
}

int main(int argc, char **argv)
{
    const index_t n = 4;
    const permutation max = factorial(n);
    for (permutation p = 0; p < max; ++p) {
        dump_permutation(n, p);
    }
}

#6


0  

Code that unpacks a permutation index into an array, with a certain mapping from index to permutation. There are loads of others, but this one is convenient.

将置换索引解包到数组中的代码,具有从索引到置换的某种映射。还有很多其他的,但是这个很方便。

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

typedef unsigned char index_t;
typedef unsigned int permutation;

static void permutation_to_array(index_t *indices, index_t n, permutation p)
{
    index_t used = 0;
    for (index_t i = 0; i < n; ++i) {
        index_t left = n - i;
        index_t digit = p % left;
        for (index_t j = 0; j <= digit; ++j) {
            if (used & (1 << j)) {
                digit++;
            }
        }
        used |= (1 << digit);
        indices[i] = digit;
        p /= left;
    }
}

static void dump_array(index_t *indices, index_t n)
{
    fputs("[", stdout);
    for (index_t i = 0; i < n; ++i) {
        printf("%d", indices[i]);
        if (i != n - 1) {
            fputs(", ", stdout);
        }
    }
    puts("]");
}

static int factorial(int n)
{
    int prod = 1;
    for (int i = 1; i <= n; ++i) {
        prod *= i;
    }
    return prod;
}

int main(int argc, char **argv)
{
    const index_t n = 4;
    const permutation max = factorial(n);
    index_t *indices = malloc(n * sizeof (*indices));
    for (permutation p = 0; p < max; ++p) {
        permutation_to_array(indices, n, p);
        dump_array(indices, n);
    }
    free(indices);
}

#1


4  

There are n! permutations of n elements. Storing which one you're using requires at least log(n!) / log(2) bits. By Stirling's approximation, this takes roughly n log(n) / log (2) bits.

有n !n个元素的排列。存储您正在使用的日志至少需要log(n!) / log(2)位。通过斯特林近似,这大约需要n log(n) / log(2)位。

Explicitly storing one index takes log(n) / log(2) bits. Storing all n, as in an array of indices takes n times as many, or again n log(n) / log(2). Information-theoretically, there is no better way than explicitly storing the permutation.

显式存储一个索引需要日志(n) / log(2)位。存储所有n,就像在一个索引数组中那样需要n倍的数量,或者同样需要n log(n) / log(2)从理论上讲,没有比显式存储置换更好的方法了。

In other words, the index you pass in of what permutation in the set you want takes the same asymptotic storage space as just writing out the permutation. If, for, example, you limit the index of the permutation to 32 bit values, you can only handle permutations of up to 12 elements. 64 bit indices only get you up to 20 elements.

换句话说,你在你想要的集合中传递什么置换的索引具有和写出置换一样的渐近存储空间。例如,如果将排列的索引限制为32位值,则只能处理最多12个元素的排列。64位索引只能得到20个元素。

As the index takes the same space as the permutation would, either change your representation to just use the permutation directly, or accept unpacking into an array of size N.

由于索引占用的空间与置换的空间相同,因此要么将表示形式更改为直接使用置换,要么接受对大小为N的数组进行解压。

#2


3  

From my response to another question:

从我对另一个问题的回答:

It is actually possible to do this in space proportional to the number of elements selected, rather than the size of the set you're selecting from, regardless of what proportion of the total set you're selecting. You do this by generating a random permutation, then selecting from it like this:

实际上,在空间上做这个是有可能的,它与所选元素的数量成正比,而不是与所选的集合的大小成反比,无论所选的集合占多大的比例。通过生成随机排列,然后像这样选择:

Pick a block cipher, such as TEA or XTEA. Use XOR folding to reduce the block size to the smallest power of two larger than the set you're selecting from. Use the random seed as the key to the cipher. To generate an element n in the permutation, encrypt n with the cipher. If the output number is not in your set, encrypt that. Repeat until the number is inside the set. On average you will have to do less than two encryptions per generated number. This has the added benefit that if your seed is cryptographically secure, so is your entire permutation.

选择一个块密码,如茶或茶。使用XOR折叠将块的大小减少到比您选择的集合大2倍的最小功率。使用随机种子作为密码的钥匙。要在置换中生成元素n,请使用密码加密n。如果输出号不在集合中,请加密它。重复,直到数字在设置中。平均来说,每个生成的数字必须进行少于两个的加密。这有一个额外的好处,如果您的种子是加密安全的,那么您的整个排列也是安全的。

I wrote about this in much more detail here.

我在这里写了更多的细节。

Of course, there's no guarantee that every permutation can be generated (and depending on your block size and key size, that may not even be possible), but the permutations you can get are highly random (if they weren't, it wouldn't be a good cipher), and you can have as many of them as you want.

当然,不能保证每个排列可以生成(取决于你的块大小和关键尺寸,甚至是不可能的),但排列可以得到高度随机的(如果他们不是,它不会是一个很好的密码),你可以尽可能多的你想要的。

#3


1  

If you are wanting a function that takes up less stack space, then you should look into using an iterated version, rather than a function. You can also use a datastructure like a TreeMap, and have it stored on disk, and read on an as needed basis.

如果您想要一个占用较少堆栈空间的函数,那么应该使用迭代版本,而不是函数。您还可以使用TreeMap之类的数据结构,并将其存储在磁盘上,并根据需要进行读取。

X(n+1) = Routine(Xn, max, permutation number)
for(i = n; i > 0; i--)
 {
   int temp = Map.lookup(i) 
   otherfun(temp,max,perm)
 }

#4


0  

Is it possible to index a set of permutations without previously computing and storing the whole thing in memory? I tried something like this before and didn't find a solution - I think it is impossible (in the mathematical sense).

是否可以索引一组排列,而不需要以前计算和存储整个东西在内存中?我以前尝试过类似的方法,但没有找到解决方案——我认为这是不可能的(从数学的角度来看)。

Disclaimer: I may have misunderstood your question...

免责声明:我可能误解了你的问题……

#5


0  

Code that uses an iterate interface. Time complexity is O(n^2), Space complexity has an overhead of: copy of n (log n bits), an iteration variable (log n bits), keeping track of n-i (log n bits), , copy of current value (log n bits), copy of p (n log n bits), creation of next value (log n bits), and a bit set of used values (n bits). You can't avoid an overhead of n log n bits. Timewise, this is also O(n^2), for setting the bits. This can be reduced a bit, but at the cost of using a decorated tree to store the used values.

使用迭代接口的代码。时间复杂度是O(n ^ 2),空间复杂性的开销:副本n(log n比特),迭代变量(log n比特),跟踪n(log n位),当前值(log n比特)的副本,副本p(n O(log n)比特),创造未来价值(log n比特),和一点组使用的值(n比特)。你无法避免n log n位的开销。Timewise,这也是O(n ^ 2),设置部分。这可以减少一点,但代价是使用装饰树来存储所使用的值。

This can be altered to use arbitrary precision integers and bit sets by using calls to the appropriate libraries instead, and the above bounds will actually start to kick in, rather than being capped at N=8, portably (an int can be the same as a short, and as small as 16 bits). 9! = 362880 > 65536 = 2^16

这可以改变使用任意精度整数和点集通过调用适当的库相反,和上面的界限会开始发挥作用,而不是限制在N = 8,轻松(int可以一样短,和小至16位)。9 != 362880 > 65536 = 2 ^ 16

#include <math.h>
#include <stdio.h>

typedef signed char index_t;
typedef unsigned int permutation;

static index_t permutation_next(index_t n, permutation p, index_t value)
{
    permutation used = 0;
    for (index_t i = 0; i < n; ++i) {
        index_t left = n - i;
        index_t digit = p % left;
        p /= left;
        for (index_t j = 0; j <= digit; ++j) {
            if (used & (1 << j)) {
                digit++;
            }
        }
        used |= (1 << digit);
        if (value == -1) {
            return digit;
        }
        if (value == digit) {
            value = -1;
        }
    }
    /* value not found */
    return -1;
}

static void dump_permutation(index_t n, permutation p)
{
    index_t value = -1;
    fputs("[", stdout);
    value = permutation_next(n, p, value);
    while (value != -1) {
        printf("%d", value);
        value = permutation_next(n, p, value);
        if (value != -1) {
            fputs(", ", stdout);
        }
    }
    puts("]");
}

static int factorial(int n)
{
    int prod = 1;
    for (int i = 1; i <= n; ++i) {
        prod *= i;
    }
    return prod;
}

int main(int argc, char **argv)
{
    const index_t n = 4;
    const permutation max = factorial(n);
    for (permutation p = 0; p < max; ++p) {
        dump_permutation(n, p);
    }
}

#6


0  

Code that unpacks a permutation index into an array, with a certain mapping from index to permutation. There are loads of others, but this one is convenient.

将置换索引解包到数组中的代码,具有从索引到置换的某种映射。还有很多其他的,但是这个很方便。

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

typedef unsigned char index_t;
typedef unsigned int permutation;

static void permutation_to_array(index_t *indices, index_t n, permutation p)
{
    index_t used = 0;
    for (index_t i = 0; i < n; ++i) {
        index_t left = n - i;
        index_t digit = p % left;
        for (index_t j = 0; j <= digit; ++j) {
            if (used & (1 << j)) {
                digit++;
            }
        }
        used |= (1 << digit);
        indices[i] = digit;
        p /= left;
    }
}

static void dump_array(index_t *indices, index_t n)
{
    fputs("[", stdout);
    for (index_t i = 0; i < n; ++i) {
        printf("%d", indices[i]);
        if (i != n - 1) {
            fputs(", ", stdout);
        }
    }
    puts("]");
}

static int factorial(int n)
{
    int prod = 1;
    for (int i = 1; i <= n; ++i) {
        prod *= i;
    }
    return prod;
}

int main(int argc, char **argv)
{
    const index_t n = 4;
    const permutation max = factorial(n);
    index_t *indices = malloc(n * sizeof (*indices));
    for (permutation p = 0; p < max; ++p) {
        permutation_to_array(indices, n, p);
        dump_array(indices, n);
    }
    free(indices);
}