1. 程式人生 > >遞迴:從陣列中取n個數有多少種組合。

遞迴:從陣列中取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(…),需要傳遞給它的引數有:

  1. 原始陣列:int *arr
  2. 另一個存放下標的陣列:int *result
  3. 取多少個數:int n
  4. 陣列result中的索引:int index
  5. 遍歷的起始位置:int start
  6. 原始陣列的長度: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);
}