排列组合问题汇总

来源:互联网 发布:互联网金融 算法 编辑:程序博客网 时间:2024/06/07 16:22

问题一 打印出一个集合中的元素的所有可能的组合.

思路如下:元素个数为n,可以用一个n位二进制数的每一个bit对应集合中的每一个元素。任取一个n位二进制数即能够表示对该集合中元素的一种选择方案。规则如下:某bit为1,表示选中该元素,为0表示不选中该元素。则从1,累加到(2^n) - 1,即可得到所有组合方案。程序如下:

void combine(const char* str, const int nLen){unsigned int uCount = pow(2, nLen)-1;for (unsigned int i=1; i<=uCount; i++){unsigned int bitmap = i;// go through each bit of bitmapfor (unsigned int idx=0; idx < nLen; idx++){if (bitmap & 0x1)printf("%c", str[idx]);bitmap >>= 1;}printf("\n");}}

问题二 打印出从给定集合中选取指定个元素的所有组合。例如,从集合 {1, 2, 3, 4}中任取两个元素的所有取法为{(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)}。

思路:借用多叉树深度遍历的方法。程序如下

#include <stdio.h>#include <stdlib.h>//          --- --- ---// pAssign | . | . | . |//          -*- -#- -$-////          -*- -#- --- -$- ---// list    | 2 | 6 | 7 | 9 | 8 //          --- --- --- --- ---// Idea: multiple tree traversal algorithm.//// Parameters://    list [in], defines the list of data.//    list_len [in], defines the length of the list.//    cmb [in], defines number of elements in the list to be combined.//void Combine(int* list, int list_len, int cmb){int** pAssign;// pointers that point to element in list.int curAssign = 0;int i;if (NULL == list || 0 == list_len || 0 == cmb){return;}pAssign = (int**)malloc(sizeof(int*) * cmb);pAssign[0] = list;curAssign = 1;while (1){// (Still need to assign)// and (amount need to assign <= amount available for assignment)while ((curAssign < cmb) &&(cmb-curAssign) <= (list_len - (pAssign[curAssign-1]-list) - 1)){pAssign[curAssign] = pAssign[curAssign-1] + 1;curAssign++;}// If all cmb have assigned then output.if (curAssign>=cmb){printf("(");for(i = 0; i < cmb; i++){printf("%d, ", *pAssign[i]);}printf("\b\b)\n");curAssign--;}// Find the position to walk right.while (pAssign[curAssign]-list >= list_len-1){curAssign--;}// If no cmb can walk right then return.if (-1 == curAssign){free(pAssign);return;}// walk right.pAssign[curAssign]++;curAssign++;}}

问题三。全排列。实现一个函数,打印给定集合元素的全排列。

例如,集合{1, 2, 3}的全排列如下:{(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)}。

思路和问题二基本一致,是深度优先遍历多叉树的方法。

#include <stdio.h>#include <stdlib.h>int FindFirstAvailableIdxFrom(bool* list, int start, int list_len){int i;for(i = start+1; i < list_len; i++){if(false == list[i])return i;}return -1;}// Parameters://     list [in], defines the list of data.//     list_len [in], defines the length of the list.void Permutation(int* list, int list_len){int** pointers; // 指针数组,其中每个元素都指向list中的元素,表示输出结果int** curLevel; // pointers中当前正在分配的元素bool* isOccupied;int i;int idx;pointers = (int**)malloc(sizeof(int*) * list_len);isOccupied = (bool*)malloc(sizeof(bool) * list_len);for(i=0; i<list_len; i++){pointers[i] = NULL;isOccupied[i] = false;}while(true){curLevel = pointers;while(list_len > curLevel - pointers){idx = FindFirstAvailableIdxFrom(isOccupied, 0, list_len);if(NULL != *curLevel){isOccupied[*curLevel - list] = false;}*curLevel = list + idx;isOccupied[idx] = true;curLevel++;}printf("{");for(i=0; i<list_len; i++){printf("%d, ", *(*(pointers+i)));}printf("\b}\n");while(-1 == (idx=FindFirstAvailableIdxFrom(isOccupied, *curLevel - list, list_len))){if (curLevel == pointers){return;}isOccupied[*curLevel - list] = false;curLevel--;}isOccupied[idx] = true;curLevel++;}}


原创粉丝点击