我需要一个简单的置换生成器算法,它可以应用于简单的C语言。
答案 0 :(得分:5)
对数字进行置换:
为了使用每个排列,你必须连接到打印功能。
#include <stdio.h>
#include <stdlib.h>
/**
Read a number, N, from standard input and print the
permutations.
*/
void print(const int *v, const int size)
{
if (v != 0) {
for (int i = 0; i < size; i++) {
printf("%4d", v[i] );
}
printf("\n");
}
} // print
void swap(int *v, const int i, const int j)
{
int t;
t = v[i];
v[i] = v[j];
v[j] = t;
}
void rotateLeft(int *v, const int start, const int n)
{
int tmp = v[start];
for (int i = start; i < n-1; i++) {
v[i] = v[i+1];
}
v[n-1] = tmp;
} // rotateLeft
void permute(int *v, const int start, const int n)
{
print(v, n);
if (start < n) {
int i, j;
for (i = n-2; i >= start; i--) {
for (j = i + 1; j < n; j++) {
swap(v, i, j);
permute(v, i+1, n);
} // for j
rotateLeft(v, i, n);
} // for i
}
} // permute
void init(int *v, int N)
{
for (int i = 0; i < N; i++) {
v[i] = i+1;
}
} // init
int main()
{
int *v = (int*) malloc(sizeof(int)*10);
init(v, 10);
permute(v, 0, 10);
free(v);
}
答案 1 :(得分:4)
所有
我找到了算法,以“计算机编程艺术”(TAOCP)的词典顺序生成排列:
http://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order
按字典顺序生成 有许多方法可以系统地生成给定序列的所有排列[需要引证]。一种既简单又灵活的经典算法基于在词典排序中找到下一个排列(如果存在的话)。它可以处理重复的值,在这种情况下,它每次生成不同的多集排列。即使对于普通的排列,它也比在词典顺序中生成Lehmer代码的值(可能使用阶乘数系统)并将它们转换为排列更有效。要使用它,首先要按顺序(弱)递增顺序对序列进行排序(这使其按字典顺序排列最小的排列),然后只要找到一个,就重复前进到下一个排列。这种方法可以追溯到14世纪印度的Narayana Pandita,从那时起就经常被重新发现。
以下算法在给定排列后按字典顺序生成下一个排列。它就地改变了给定的排列。
在步骤1之后,人们知道严格地在位置k之后的所有元素形成弱递减序列,因此这些元素的排列不会使其按字典顺序前进;提前一个必须增加一个[k]。步骤2找到最小值a [l]来替换[k],并且在步骤3中交换它们使位置k之后的序列以弱降序排列。在步骤4中反转该序列然后产生其按字典顺序排列的最小排列,以及整个序列的初始状态的词典继承器
答案 2 :(得分:2)
这是在Knuth的TAOCP中找到的经典算法(在其他地方)。
这是我用于项目euler问题的一个例子。它以字典顺序创建字符串的所有排列,并将它们打印到标准输出。
#include<stdio.h>
int main()
{
char set[10]="0123456789";
char scratch;
int lastpermutation = 0;
int i, j, k, l;
printf("%s\n",set);
while (!lastpermutation)
{
//find largest j such that set[j] < set[j+1]; if no such j then done
j = -1;
for (i = 0; i < 10; i++)
{
if (set[i+1] > set[i])
{
j = i;
}
}
if (j == -1)
{
lastpermutation = 1;
}
if (!lastpermutation)
{
for (i = j+1; i < 10; i++)
{
if (set[i] > set[j])
{
l = i;
}
}
scratch = set[j];
set[j] = set[l];
set[l] = scratch;
//reverse j+1 to end
k = (9-j)/2; // number of pairs to swap
for (i = 0; i < k; i++)
{
scratch = set[j+1+i];
set[j+1+i] = set[9-i];
set[9-i] = scratch;
}
printf("%s\n",set);
}
}
return 0;
}
答案 3 :(得分:1)
这是一个简单的递归解决方案,用于生成在命令行上传递的一组字符的所有排列:
#include <stdio.h>
#include <string.h>
int perm(const char *src, int len, char *dest, char *destbits, int n) {
if (n == len) {
printf("%.*s\n", len, dest);
return 1;
} else {
int count = 0;
for (int i = 0; i < len; i++) {
if (destbits[i] == 0) {
destbits[i] = 1;
dest[n] = src[i];
count += perm(src, len, dest, destbits, n + 1);
destbits[i] = 0;
}
}
return count;
}
}
int main(int argc, char *argv[]) {
const char *src = (argc > 1) ? argv[1] : "123456789";
int len = strlen(src);
char dest[len], destbits[len];
memset(destbits, 0, sizeof destbits);
int total = perm(src, len, dest, destbits, 0);
printf("%d combinations\n", total);
return 0;
}
答案 4 :(得分:1)
我正在寻找更迭代的东西,然后实现我的较差版本。我可以看到一些优化,但是现在对我有帮助。我希望这对任何人都有帮助。
#include <stdio.h>
#include <stdlib.h>
#define PERM_T int
#define PERM_T_PFLAG "%d"
void swap(PERM_T *array, int i, int j) {
PERM_T aux = array[i];
array[i] = array[j];
array[j] = aux;
}
void print_array_perm(PERM_T *array, int n) {
printf("[");
n -= 1;
for (int i = 0; i < n; i++) {
printf(PERM_T_PFLAG", ", array[i]);
}
if (n >= 0)
printf(PERM_T_PFLAG, array[n]);
printf("]\n");
}
void print_array_int(int *array, int n) {
printf("[");
n -= 1;
for (int i = 0; i < n; i++) {
printf("%d, ", array[i]);
}
if (n >= 0)
printf("%d", array[n]);
printf("]\n");
}
void copy_array_T(
PERM_T *src, PERM_T *dst,
int start, int end) {
for (int i = start; i < end; i++) {
dst[i] = src[i];
}
}
void copy_array_int(
int *src, int *dst,
int start, int end) {
for (int i = start; i < end; i++) {
dst[i] = src[i];
}
}
void rotate_array(
PERM_T *array,
int start, int end) {
PERM_T aux = array[start];
copy_array_T(
array + 1, array, start, end);
array[end - 1] = aux;
}
int factorial(int n) {
int result = 1;
while (n > 1) {
result *= n;
n--;
}
return result;
}
typedef struct {
PERM_T *data;
int length;
int *ks;
int kn;
int _i;
} Perm;
Perm perm_(
PERM_T *data, PERM_T *array, int n) {
copy_array_T(array, data, 0, n);
int kn = n > 1 ? n - 1 : 0;
int *ks = kn
? malloc(sizeof(PERM_T) * kn)
: NULL;
for (int i = 0; i < kn; i++)
ks[i] = i;
int max_iterations = factorial(n);
Perm p = {
.data = data,
.length = n,
.ks = ks,
.kn = kn,
._i = max_iterations
};
return p;
}
Perm perm(PERM_T *array, int n) {
PERM_T *data =
malloc(sizeof(PERM_T) * n);
return perm_(data, array, n);
}
Perm copy_perm(Perm p) {
Perm copy = perm(p.data, p.length);
copy_array_int(p.ks, copy.ks, 0, p.kn);
return copy;
}
void clear_perm(Perm* p) {
free(p->data);
if (p->kn) free(p->ks);
}
int completed_perm(Perm *p) {
return p->_i < 1;
}
void next_perm_self(Perm *p) {
int n = p->length;
if (completed_perm(p)) return;
p->_i--;
int k = p->kn - 1;
int *ks = p->ks;
PERM_T *data = p->data;
if (ks[k] + 1 != n) {
rotate_array(data, k, n);
ks[k] += 1;
} else {
while (k >= 0 && ks[k] + 1 == n) {
ks[k] = k;
rotate_array(data, k, n);
k -= 1;
}
if (k >= 0) {
rotate_array(data, k, n);
ks[k] += 1;
}
}
}
Perm next_perm_(Perm *p) {
Perm next = copy_perm(*p);
next_perm_self(&next);
return next;
}
Perm next_perm(Perm *p) {
Perm next = next_perm_(p);
clear_perm(p);
return next;
}
void print_perm(Perm p) {
print_array_perm(p.data, p.length);
}
void print_perm_(Perm p) {
printf("%p\n", p.data);
print_perm(p);
print_array_int(p.ks, p.kn);
}
Perm next_print(Perm *p) {
print_perm(p);
return next_perm(p);
}
void next_print_self(Perm *p) {
print_perm(*p);
next_perm_self(p);
}
int main() {
int a1[] = {1,2,3,4,5};
Perm p = perm(a1, 5);
int i = 0;
while (!completed_perm(&p)) {
printf("%3d ", i++);
// p = next_print(&p);
next_print_self(&p);
}
clear_perm(&p);
return 0;
}