我已經張貼了下面的例子在其他地方,但讓我重複在這裏:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
typedef char element_t;
typedef unsigned long permutation_t;
static permutation_t factorial(const permutation_t n)
{
permutation_t i, result = 1;
for (i = 2; i <= n; i++) {
const permutation_t newresult = result * i;
if ((permutation_t)(newresult/i) != result)
return 0;
result = newresult;
}
return result;
}
int permutation(element_t *const buffer,
const element_t *const digits,
const size_t length,
permutation_t index)
{
permutation_t scale;
size_t i, d;
if (!buffer || !digits || length < 1)
return errno = EINVAL;
scale = factorial(length);
if (!scale)
return errno = EMSGSIZE;
if (index >= scale)
return errno = ENOENT;
/* Copy original ordered set to mutable buffer */
memmove(buffer, digits, length * sizeof (element_t));
for (i = 0; i < length - 1; i++) {
scale /= (permutation_t)(length - i);
d = index/scale;
index %= scale;
if (d > 0) {
const element_t c = buffer[i + d];
memmove(buffer + i + 1, buffer + i, d * sizeof (element_t));
buffer[i] = c;
}
}
return 0;
}
的factorial()
功能僅僅是一個緩慢但謹慎地執行factorial。自13以來! > 2 ,21! > 2 和35! > 2 ,對於32,64或128位無符號整數permutation_t
類型,只有很少可能的結果,因此最好僅爲階乘使用數組查找(如rcgldr already mentioned)。
的permutation(buffer, digits, length, index)
函數採用長度length
的目標buffer
,並與digits
的index
「日排列填充。 (該digits
的,不可變的只讀的。)
這不是最快的實現,但它會計算任意排列在O(length)
時間複雜度(忽略memmove()
操作;如果你考慮到memmove()
O(length²)
)。它是次優的,因爲它使用memmove()
來重新排列目標buffer
中的項目,並且每個元素需要兩個除法(並且具有相同除數的一個模)。
考慮最大實際長度的限制(12,20,或34層的元件,這取決於permutation_t
類型的大小),使用的memmove()
不是問題(因爲數據內的一個或至多幾個緩存行)。
這是線程安全的,只要一個線程同時在同一個目標buffer
上運行;多個線程從同一個來源生成不同的目標buffer
digits
緩衝區是線程安全的。