C或C ++ - 与重复相结合

时间:2014-04-13 14:49:41

标签: c++ c

如何在k组中生成n个元素的所有组合? 例如,从[aaa]到[ddd]的3个组中的takig“abcd”?

编辑:到目前为止我“完成了什么”:

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]++;
    }
}

它会尝试向后生成最新的字母数字字符组合,但它是硬编码的,不会很好用。

3 个答案:

答案 0 :(得分:2)

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

以下代码将生成&#34; abcd&#34;的所有可能组合。分为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 %c\n",ch1,ch2,ch3);
            }
            printf("\n"); //just to have clean and understandable output
       }
       printf("\n\n\n"); //just to have clean and understandable output
    }
 return 0;
}

答案 1 :(得分:2)

#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 3\n");
        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;
}

答案 2 :(得分:1)

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

计数算法
我们以“数字”为例:a,b,c和d。

第一个号码是:aaaa。与十进制非常相似: 0000 第二个是:aaab。十进制: 0001
第三个数字是:aaac,十进制: 0002 第四个数字是:aaad,十进制: 0003

此过程称为递增,例如每次添加一个常量值。

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

因此,在上面的示例中,序列中的下一个数字是:aaba

这被称为 carry ,因为您将溢出传送到下一个数字。

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

#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 ++组合排列算法”。