遞迴:從陣列中取n個數有多少種組合。
還是在學習遞迴。
看別人的部落格自己學習了之後,來寫一下自己的理解吧。
首先這道題目是說,有一個數組,例如arr={1,2,3,4,5,6},給定一個n<=arr_len,例如給定4,問:從陣列中取4個數一共有多少種組合方式?
這個在數學上是排列組合問題。用腦子想的話,可以很快就有思路。
例如:
先定下取1,2,3,然後在4,5,6中取一個。假如我取了4。
下一步就是先定下取1,2,3然後在5,6中取一個。
……不做贅述了。
可是在計算機上實現就有點棘手。因為計算機不懂你在想什麼,你就要想辦法告訴它該怎麼做。
就繼續說上面給出的arr這個陣列。思路是這樣:
自定義一個函式void combine(…),需要傳遞給它的引數有:
- 原始陣列:int *arr
- 另一個存放下標的陣列:int *result
- 取多少個數:int n
- 陣列result中的索引:int index
- 遍歷的起始位置:int start
- 原始陣列的長度:int arr_len
然後剖析一下這個函式的過程。
這個函式就是在arr中直接找到有多少種組合方式,但不是輸出組合方式(也可以改成這樣),而是直接輸出組合的情況。
輸出結果是這樣的:
先上函式的程式碼塊:
void combine (int *arr,int start,int *result,int index,int n,int arr_len)
{
int ct = 0 ;
for(ct = start;ct < arr_len-index+1;ct++){
result[index-1] = ct;
if(index-1==0){
int j;
for(j = n-1;j>=0;j--)
printf("%d\t",arr[result[j]]);
printf("\n");
}
else
combine(arr,ct+1,result,index-1,n,arr_len);
}
}
理解:
1. 在函式中新定義一個ct;表示count,用來迴圈遍歷。
2. 外層for迴圈的作用是遍歷,內層的for是用來輸出不同的組合情況。
3. 可以看到在內層的for裡,先是定義了一個j,然後看在printf語句裡是arr[result[j]],因此可以知道在result中存放的只是對應的arr的下標,當輸出時,還是在arr中根據不同的組合輸出相應的數。
4. 回到外層for的下一行,result[index-1]=ct,這裡就是將arr中的對應的下標儲存到result陣列中,它告訴result陣列,在arr中分別取第幾…和第幾個數。例如,當ct分別等於0,1,2,3時,result中就儲存了這四個數,然後在內層的for中就輸出arr的第一,二,三,四個數 。
5. 那麼我們要做的就是恰當的改變ct的值。可能第一次,我是在0,1,2,3,4,5中取不同情況的下標ct,例如第一次取了0,1,2,3這四個下標,那麼下一次我就會去0,1,2,4。一直到0開頭的情況取完,然後就取1開頭的情況,1開頭的情況又有1,2,3,4等等。還有2,3開頭的情況。但最多隻有3開頭,因為本例的情況是在陣列中取4個數,從3這個下標一直順序取到最後一個時,已經正好把所有數取完。同樣的,如果是在陣列中取3個數求不同的組合,那麼就最多有4的下標開頭。
6. 這樣就不會重複。
7. 改變ct的值就是讓ct的範圍合適恰當的推進。從0開頭的情況在(ct = start;ct < arr_len-index-1;ct++)的迴圈裡,那麼推進下一位就是從1開始的情況,此時ct的取值範圍應該是(ct = start+1;ct<=arr_len-(index-1)+1;ct++)。這裡就體現了遞迴。因此在遞迴中的函式傳遞需要改變兩個值。一個是ct+1,另一個是index-1,其他不變。
完整的程式碼如下:
#include<stdio.h>
void combine (int *arr,int start,int *result,int index,int n,int arr_len)
{
int ct = 0;
for(ct = start;ct < arr_len-index+1;ct++){
result[index-1] = ct;
if(index-1==0){
int j;
for(j = n-1;j>=0;j--)
printf("%d\t",arr[result[j]]);
printf("\n");
}
else
combine(arr,ct+1,result,index-1,n,arr_len);
}
}
int main()
{
int arr[6]={1,2,3,4,5,6};
int result[4]={};
int arr_len = sizeof(arr)/sizeof(int);
int n = 4,index = 4;
int ct = 0;
combine(arr,ct,result,index,n,arr_len);
}