1

我正在使用递归函数(来自此处的一篇文章)来枚举从 n 中选择 k 项的所有组合。我已经修改了这个函数以保存并返回二维数组中的枚举组合(作为 arrPtr 传递给函数)。我在 for 循环(从 main)中为不同的 k 值(k 从 1 到 n-1)调用此递归函数,以生成 n 和 k 的任何值的所有组合。现在,将“count”定义为静态整数,该函数生成 k=1 的所有组合,然后转到 k=2,然后在某一点停止。原因是我使用变量“count”作为 arrPtr 中行的索引。由于它是一个静态变量,因此在其他轮次(k=2,3,4 等)调用该函数时它不会重置为 0。因此,在某个点之后会导致 arrPtr 的访问冲突。当我删除 'count' 的 'static' 时,它会生成不同 k 值的所有组合,但只有每轮中的最后一个组合保存在 arrPtr 中(同样由于删除了 'static')。如何将每个生成的组合保存在 arrPtr 中的一行中,以便我可以获取(并返回)保存在 arrPtr 最后指向的一个位置的所有组合?

我尝试使用按引用传递(传递变量的地址)将 arrPtr 中的行的索引传递给函数,但是当递归函数调用自身时会遇到麻烦。我搜索了很多,在这里找到了类似的主题(例如,从递归函数返回数组),但它们主要用于其他编程语言(我只使用 C;甚至没有 C++)。我花了很多时间来解决这个问题,现在真的需要帮助。先感谢您。

int** nCk(int n,int loopno,int ini,int *a,int **arrPtr, int k)
{
static int count=0;

int total; // equal to the total number of combinations of nCk
int i,j;

total = factorial(n)/(factorial(n-k)*factorial(k)); 

loopno--;
if(loopno<0)
{
    a[k-1]=ini;

    for(j=0;j<k;j++)
    {
    printf("%d,",a[j]);
    arrPtr[count][j]=a[j];
    }
    printf("count =%d\n",count);

    count++;

    return 0;
}

for(i=ini;i<=n-loopno-1;i++)
{
    a[k-1-loopno]=i+1;
    nCk(n,loopno,i+1,a,arrPtr,k);
}

if(ini==0)

return arrPtr; // arrPtr is in fact an array of pointers, where each pointer points to an array of size k (one of the combinations of selecting k out of n elements

else
return 0;
}
4

2 回答 2

0

GCC 4.7.3:gcc -Wall -Wextra -std=c99 enum-nck.c

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

// Textbook recursive definition of, n-choose-k.
int nCk(int n, int k) {
  assert(0 < k && k <= n);
  if (k == n) { return 1; }
  if (k == 1) { return n; }
  return nCk(n - 1, k) + nCk(n - 1, k - 1);
}

// But you asked for a procedure to enumerate all the combinations.
void aux_enum_nCk(int n, int k, int* all, int* j, int a[], int i) {
  a[i] = n;
  if (i == k - 1) {
    memcpy(&all[*j], &a[0], k * sizeof(int));
    *j += k;
    return;
  }
  for (int c = n - 1; c > 0; --c) {
    aux_enum_nCk(c, k, all, j, a, i + 1);
  }
}

void enum_nCk(int n, int k, int* arr) {
  assert(0 < k && k <= n);
  int j = 0;
  int a[k];
  for (int i = 0; i < k; ++i) { a[i] = 0; }
  for (int c = n; c >= n - k - 1; --c) {
    aux_enum_nCk(c, k, arr, &j, a, 0);
  }
}

int main(int argc, char* argv[]) {
  int n = 7;
  int k = 3;
  int x = nCk(n, k);

  printf("%d choose %d = %d\n", n, k, x);

  int arr[x][k];

  enum_nCk(n, k, &arr[0][0]);

  for (int i = 0; i < x; ++i) {
    for (int j = 0; j < k; ++j) {
      printf("%d ", arr[i][j]);
    }
    printf("\n");
  }

  return 0;
}
于 2013-09-10T12:56:23.147 回答
0

我的理解是

您想计算 nCk 中任何 n 和 k 值的组合,

在外面定义一个 factorial() 函数并定义一个 combi() 函数...计算 n 和 k 变量的组合值

这两个函数都在定义 main() 函数之前......这样你就可以避免声明然后定义(我的意思是避免额外的代码行)。

这是combi()函数的代码

function combi(int n , int k){
int nFact, kFact, n_kFact, p;
int comb;
nFact=factorial(n);
kFact=factorial(k);
p=n-k;
n_kFact=factorial(p);
comb= nFact / ((n_kFact) * kFact);
return comb;
}

你可以在你的主函数中调用这个函数......使用for循环来存储相对n和k的组合值......因此你会得到你需要的......也传递指针或

&array[0][0]

即数组的起始地址......这样您就可以在程序中的任何位置访问该数组。

希望这可以帮助你。谢谢

于 2013-09-10T03:14:10.540 回答