問題一 列印出一個集合中的元素的所有可能的組合.
思路如下:元素個數為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++;}}