我想要一种非递归方法来解决生成某些字符或数字组合的问题。
因此,给定数字n的子集k,生成所有可能的组合n!/ k!(n-k)!
给定前一个组合,递归方法会给出一个组合。
非递归方法会生成循环索引 i 的给定值的组合。
我用这段代码解决了这个问题:
使用n = 4和k = 3进行测试,它可以工作,但是如果我将k更改为数字> 3它不起作用。
是否是因为(n-k)!在n = 4且k = 3的情况下,如果k> 1,则k = 3。 3它将超过1?
感谢。
int facto(int x);
int len,fact,rem=0,pos=0;
int str[7];
int avail[7];
str[0] = 1;
str[1] = 2;
str[2] = 3;
str[3] = 4;
str[4] = 5;
str[5] = 6;
str[6] = 7;
int tot=facto(n) / facto(n-k) / facto(k);
for (int i=0;i<tot;i++)
{
avail[0]=1;
avail[1]=2;
avail[2]=3;
avail[3]=4;
avail[4]=5;
avail[5]=6;
avail[6]=7;
rem = facto(i+1)-1;
cout<<rem+1<<". ";
for(int j=len;j>0;j--)
{
int div = facto(j);
pos = rem / div;
rem = rem % div;
cout<<avail[pos]<<" ";
avail[pos]=avail[j];
}
cout<<endl;
}
int facto(int x)
{
int fact=1;
while(x>0) fact*=x--;
return fact;
}
答案 0 :(得分:2)
错误..为什么不使用std::next_permutation
?它完全符合您的要求,不需要您自己编写(以及调试和维护)。
答案 1 :(得分:0)
考虑你的迭代器是基数n中的k个数字。在C / C ++中,您可以将其表示为大小为k的ints
数组,其中每个元素都在0
到n-1
的范围内。
然后,要从一个位置迭代到下一个位置,您只需要增加数字。
这会给你所有的排列。为了获得组合,您必须施加一个附加条件,即数字必须按升序排列。
例如k = 3, n = 3: 000 001 002 011 012 022 111 112 122 222
在C中实现该约束也非常简单,在用于迭代的递增操作中,而不是在有进位时将最右边的数字设置为零,您必须将它们设置为与最左边的数字相同的值。
更新:一些代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXK 100
int
main(int argc, char *argv[]) {
int digits[MAXK];
int k = atol(argv[1]);
int n = atol(argv[2]);
int i, left;
memset(digits, 0, sizeof(digits));
while(1) {
for (i = k; i--; ) {
printf("%d", digits[i]);
printf((i ? "-" : "\n"));
}
for (i = k; i--; ) {
left = ++digits[i];
if (left < n) {
while (++i < k) digits[i] = left;
break;
}
}
if (i < 0) break;
}
}
答案 2 :(得分:0)
这与计算速度差不多 - 实际的组合功能是使用两行代码完成的。 但是,这并不是最直观易懂的! 这项工作是通过实现格雷码序列来完成的。
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <stdint.h>
using namespace std;
//'Combinations' over a set of n objects with k bins, eg n=3,k=2 = 3
//The combination function.
//It takes a combination and returns the next combination.
//It uses GCC's '__builtin_ctzll' which returns the number of
//trailing 0-bits in v, starting at the least significant bit position.
uint64_t combination(uint64_t v) {
uint64_t t = v | (v - 1ULL); // t gets v's least significant 0 bits set to 1
return (t + 1ULL) | (((~t & -~t) - 1ULL) >> (__builtin_ctzll(v) + 1ULL));
}
//arg 1 is number of bins (n) arg 2 is number of samples (k/r)
int main (int argc, char *argv[]) {
uint64_t n = min(64ULL,argc > 1ULL ? atoi(argv[1]) : 3ULL); //max bins = 63
uint64_t k = min( n,argc > 2 ? atoi(argv[2]) : 2ULL); //max samples = bins.
uint64_t v = (1ULL << k) - 1; //start value;
uint64_t m = n == 64 ? UINT64_MAX: (1ULL << n) - 1ULL; //size of n is used as a mask.
string index = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz+*";
cout << index.substr(0,n) << endl;
do {
cout << bitset<64>(v & m).to_string().substr(64ULL-n) << endl;
v=combination(v);
} while (v < m);
return 0;
}