排列組合是演算法常用的基本工具,如何在c語言中實現排列組合呢。思路如下:
首先看遞迴實現,由於遞迴將問題逐級分解,因此相對比較容易理解,但是需要消耗大量的棧空間,如果線程棧空間不夠,那麼就運行不下去了,而且函數調用開銷也比較大。
(1) 全排列:
全排列表示把集合中元素的所有按照一定的順序排列起來,使用P(n, n) = n!表示n個元素全排列的個數。
例如:{1, 2, 3}的全排列為:
123;132;
213;231;
312;321;
共6個,即3。=321=6。
這個是怎麼算出來的呢。
首先取一個元素,例如取出了1,那麼就還剩下{2, 3}。
然後再從剩下的集合中取出一個元素,例如取出2,那麼還剩下{3}。
以此類推,把所有可能的情況取一遍,就是全排列了,如圖:
知道了這個過程,演算法也就寫出來了:
將數組看為一個集合,將集合分為兩部分:0~s和s~e,其中0~s表示已經選出來的元素,而s~e表示還沒有選擇的元素。
perm(set,s,e)
{
順序從s~e中選出一個元素與s交換(即選出一個元素)
調用perm(set,s + 1,e)
直到s>e,即剩餘集合已經為空了,輸出set
}
c語言代碼如下:
void perm(int list[], int s, int e, void (*cbk)(int list[]))
{
int i;
if(s > e)
{
(*cbk)(list);
}
else
{
for(i = s; i <= e; i++)
{
swap(list, s, i);
perm(list, s + 1, e, cbk);
swap(list, s, i);
}
}
}
其中:
void swap(int * o, int i, int j)
{
int tmp = o[i];
o[i] = o[j];
o[j] = tmp;
}
void cbk_print(int * subs)
{
printf("{");
for(int i = 0; i < LEN; i++)
{
printf("%d", subs[i]);
(i == LEN - 1) ? printf("") : printf(", ");
}
printf("}\n");
}
(2)組合:
組合指從n個不同元素中取出m個元素來合成的一個組,這個組內元素沒有順序。使用C(n, k)表示從n個元素中取出k個元素的取法數。
C(n, k) = n! / (k! * (n-k)!)
例如:從{1,2,3,4}中取出2個元素的組合為:
12;13;14;
23;24;
34
方法是:先從集合中取出一個元素,例如取出1,則剩下{2,3,4}
然後從剩下的集合中取出一個元素,例如取出2
這時12就構成了一個組,如圖。
從上面這個過程可以看出,每一次從集合中選出一個元素,然後對剩餘的集合(n-1)進行一次k-1組合。
comb(set,subset,n,k)
{
反向從集合中選出一個元素,將這個元素放入subset中。
調用comb(set,subset,n-1,k-1)
直到只需要選一個元素為止
}
C語言代碼如下:
void combine(int s[], int n, int k, void (*cbk)(int * subset, int k))
{
<