C或C++-与重复的组合

C or C++ - Combination with repetition

本文关键字:组合 C++-      更新时间:2023-10-16

如何生成k组中n个元素的所有组合?例如,将"abcd"分成3组,从[aaa]到[ddd]?

编辑:到目前为止我所"完成的":

int main (int argc, char * argvc[]) {
    int tComb = 0, array[7] = { 48 , 48 , 48 , 48 , 48 , 48 , 48 };
    while ( tComb < atoi(argvc[1]) ) {
        for (int i = 6 ; i>0 ; i--) {
            if (array[i] == 58)
                array[i] = 65;
            if (array[i] == 91)
                array[i] = 97;
            if (array[i] == 123){
                array[i] = 48;
                array[i-1]++;
            }
        }
        std::cout << "Current Combination: ";
        std::cout << array;
        std::cout << "n";
        tComb++;
        array[6]++;
    }
}

它将尝试向后生成最新的字母数字字符组合,但它是硬编码的,不能很好地工作。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
unsigned powu(unsigned base, unsigned exp){
    unsigned result = 1;
    while(exp > 0){
        if(exp & 1)
            result *= base;
        base = base * base;
        exp >>=1;
    }
    return result;
}
int main(int argc, char *argv[]){
    if(argc != 3){
        fprintf(stderr, "Usage : RepeatedPermutation abcd 3n");
        return -1;
    }
    char *list = argv[1];
    unsigned gp_len = atoi(argv[2]);
    unsigned list_len = strlen(list);
    char *gp = calloc(gp_len+1, sizeof(char));
    int total_n = powu(list_len, gp_len);
    int i, j;
    for(i=0;i<total_n;++i){
        int n = i;
        for(j=0;j<gp_len;++j){
            gp[gp_len -j -1] = list[n % list_len];
            n /= list_len;
        }
        printf("[%s]n", gp);
    }
    free(gp);
    return 0;
}

我不确定,但我认为这就是你问题的答案。如果你想要三组,那么你应该有三个不同的循环当你看到这个程序的输出时,它非常简单。你只需要增加你想要生成的可能组合的值。

以下代码将生成"abcd"的所有可能组合,每组3个,从[aaa]到[ddd]。

int main()
{
   char ch1;
   char ch2;
   char ch3;
    for(ch1='a';ch1<='d';ch1++)
    {
       for(ch2='a';ch2<='d';ch2++)
       {
            for(ch3='a';ch3<='d';ch3++)
            {
               printf("%c %c %cn",ch1,ch2,ch3);
            }
            printf("n"); //just to have clean and understandable output
       }
       printf("nnn"); //just to have clean and understandable output
    }
 return 0;
}

生成所有组合的一种方法是将其视为一个数字计数程序。

计数算法
让我们以"数字"为例:a、b、c和d。

第一个数字是:aaaa。很像十进制:0000
第二个是:aaab。小数:0001
第三个数字是:aaac,十进制:0002
第四个数字是:aaad,小数:0003

这个过程被称为递增,例如每次添加一个常数值。

现在是棘手的部分,增加最后一个数字。根据计数规则,当到达最后一位时,最后一位将被第一位替换,下一个列中的数字将被替换。这相当于一个十进制数从09增加到10。

所以在上面的例子中,序列中的下一个数字是:aaba

这被称为进位,因为您正在将溢出进位到下一位。

将算法转换为代码
看起来有一个从第一位到最后一位的循环计数:

#define MAXIMUM_DIGIT_POSITIONS 4
const char FIRST_CHAR = 'a';
const char LAST_CHAR = 'd';
std::vector<char> number(MAXIMUM_DIGIT_POSITIONS); // Reserve some slots.
void Print_Number(const std::vector<char>& number);
int main(void)
{
  // Initialize the number
  int position = 0;
  for (position = 0; position < MAXIMUM_DIGIT_POSITIONS; ++position)
  {
     number.push_back(FIRST_CHAR);
  }
  Print_Number(number);
  // Loop:  incrementing
  position = MAXIMUM_DIGIT_POSITIONS - 1; // Because arrays are zero based indexing
  while (number[position] < LAST_CHAR)
  {
    number[position] = number[position] + 1; // Increment to next digit, same position.
    Print_Number(number);
  }
  // Pause before closing
  std::cout << "Paused. Press ENTER to close.n";
  std::cin.ignore(100000, 'n');
  return EXIT_SUCCESS;
}
void Print_Number(const std::vector<char>& number)
{
  for (std::vector<char>::const_iter iter = number.begin();
       iter != number.end();
       ++iter)
  {
    std::cout << *iter;
  }
  cout << "n";
}

搬运搬运
上面的程序演示了单列中的计数。但是如何处理最后一个数字的递增呢?

看起来我们需要递增前一个位置的数字
展望未来,前一列中的值将递增,直到它也需要递增为止。因此,进位将传播到前一列。看起来像是另一个循环:

  // Loop: number of positions
  int propagation_position = position - 1;
  while (propagation_position >= 0)
  {
      while (number[position] < LAST_CHAR)
      {
        number[position] = number[position] + 1; // Increment to next digit, same position.
        Print_Number(number);
      }
      // Propagate the carry.
      while (propagation_position >= 0)
      {
        if (number[propagation_position] != LAST_CHAR)
        {
          ++number[propagation_position];
          number[propagation_position + 1] = FIRST_CHAR;
          break;
        }
        --propagation_position;
      }
      position = 0;
  }

上述新片段具有外部while循环和第二内部while循环。外部while循环控制数字位置。第二个while内部循环处理进位。

整个程序的设计使您可以调整数字位置的数量和序列中的数字数量。

摘要
打印所有组合的强力方法就像数数字一样。同样的原理也适用:当最后一个数字递增时,它被第一个数字取代,下一列的数字递增。重复此操作,直到所有位置都已计数。

使用调试器或纸笔遍历以上代码,以发现任何缺陷并理解算法。

了解算法后,在您喜欢的C++参考中搜索"C++组合置换算法"。