遞歸和循環兩種方式實現未知維度集合的笛卡爾積

什麼是笛卡爾積?

在數學中,兩個集合XY笛卡兒積(Cartesian product),又稱直積,表示爲X × Y,第一個對象是X的成員而第二個對象是Y的所有可能有序對的其中一個成員

假設集合A={a,b},集合B={0,1,2},則兩個集合的笛卡爾積爲{(a,0),(a,1),(a,2),(b,0),(b,1), (b,2)}。


如何用程序算法實現笛卡爾積?

如果編程前已知集合的數量,通過程序的多次循環即可得出笛卡爾積。但是如果編程前不知道集合的數量,如何得到笛卡爾積哪?比如集合表示List < List<String>> list;這個list在編程前list的數量是未知的。下面的代碼使用遞歸和循環兩種方法實現未知維度集合的笛卡爾積:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 循環和遞歸兩種方式實現未知維度集合的笛卡爾積
 * Created on 2015-05-22
 * @author luweijie
 */
public class Descartes {

    /**
     * 遞歸實現dimValue中的笛卡爾積,結果放在result中
     * @param dimValue 原始數據
     * @param result 結果數據
     * @param layer dimValue的層數
     * @param curList 每次笛卡爾積的結果
     */
    private static void recursive (List<List<String>> dimValue, List<List<String>> result, int layer, List<String> curList) {
        if (layer < dimValue.size() - 1) {
            if (dimValue.get(layer).size() == 0) {
                recursive(dimValue, result, layer + 1, curList);
            } else {
                for (int i = 0; i < dimValue.get(layer).size(); i++) {
                    List<String> list = new ArrayList<String>(curList);
                    list.add(dimValue.get(layer).get(i));
                    recursive(dimValue, result, layer + 1, list);
                }
            }
        } else if (layer == dimValue.size() - 1) {
            if (dimValue.get(layer).size() == 0) {
                result.add(curList);
            } else {
                for (int i = 0; i < dimValue.get(layer).size(); i++) {
                    List<String> list = new ArrayList<String>(curList);
                    list.add(dimValue.get(layer).get(i));
                    result.add(list);
                }
            }
        }
    }

    /**
     * 循環實現dimValue中的笛卡爾積,結果放在result中
     * @param dimValue 原始數據
     * @param result 結果數據
     */
    private static void circulate (List<List<String>> dimValue, List<List<String>> result) {
        int total = 1;
        for (List<String> list : dimValue) {
            total *= list.size();
        }
        String[] myResult = new String[total];

        int itemLoopNum = 1;
        int loopPerItem = 1;
        int now = 1;
        for (List<String> list : dimValue) {
            now *= list.size();

            int index = 0;
            int currentSize = list.size();

            itemLoopNum = total / now;
            loopPerItem = total / (itemLoopNum * currentSize);
            int myIndex = 0;

            for (String string : list) {
                for (int i = 0; i < loopPerItem; i++) {
                    if (myIndex == list.size()) {
                        myIndex = 0;
                    }

                    for (int j = 0; j < itemLoopNum; j++) {
                        myResult[index] = (myResult[index] == null? "" : myResult[index] + ",") + list.get(myIndex);
                        index++;
                    }
                    myIndex++;
                }

            }
        }

        List<String> stringResult = Arrays.asList(myResult);
        for (String string : stringResult) {
            String[] stringArray = string.split(",");
            result.add(Arrays.asList(stringArray));
        }
    }

    /**
     * 程序入口
     * @param args
     */
    public static void main (String[] args) {
        List<String> list1 = new ArrayList<String>();
        list1.add("1");
        list1.add("2");

        List<String> list2 = new ArrayList<String>();
        list2.add("a");
        list2.add("b");

        List<String> list3 = new ArrayList<String>();
        list3.add("3");
        list3.add("4");
        list3.add("5");

        List<String> list4 = new ArrayList<String>();
        list4.add("c");
        list4.add("d");
        list4.add("e");

        List<List<String>> dimValue = new ArrayList<List<String>>();
        dimValue.add(list1);
        dimValue.add(list2);
        dimValue.add(list3);
        dimValue.add(list4);

        List<List<String>> recursiveResult = new ArrayList<List<String>>();
        // 遞歸實現笛卡爾積
        recursive(dimValue, recursiveResult, 0, new ArrayList<String>());

        System.out.println("遞歸實現笛卡爾乘積: 共 " + recursiveResult.size() + " 個結果");
        for (List<String> list : recursiveResult) {
            for (String string : list) {
                System.out.print(string + " ");
            }
            System.out.println();
        }

        List<List<String>> circulateResult = new ArrayList<List<String>>();
        circulate(dimValue, circulateResult);
        System.out.println("循環實現笛卡爾乘積: 共 " + circulateResult.size() + " 個結果");
        for (List<String> list : circulateResult) {
            for (String string : list) {
                System.out.print(string + " ");
            }
            System.out.println();
        }
    }
}


輸出結果是
遞歸實現笛卡爾乘積: 共 36 個結果
1 a 3 c 
1 a 3 d 
1 a 3 e 
1 a 4 c 
1 a 4 d 
1 a 4 e 
1 a 5 c 
1 a 5 d 
1 a 5 e 
1 b 3 c 
1 b 3 d 
1 b 3 e 
1 b 4 c 
1 b 4 d 
1 b 4 e 
1 b 5 c 
1 b 5 d 
1 b 5 e 
2 a 3 c 
2 a 3 d 
2 a 3 e 
2 a 4 c 
2 a 4 d 
2 a 4 e 
2 a 5 c 
2 a 5 d 
2 a 5 e 
2 b 3 c 
2 b 3 d 
2 b 3 e 
2 b 4 c 
2 b 4 d 
2 b 4 e 
2 b 5 c 
2 b 5 d 
2 b 5 e 
循環實現笛卡爾乘積: 共 36 個結果
1 a 3 c 
1 a 3 d 
1 a 3 e 
1 a 4 c 
1 a 4 d 
1 a 4 e 
1 a 5 c 
1 a 5 d 
1 a 5 e 
1 b 3 c 
1 b 3 d 
1 b 3 e 
1 b 4 c 
1 b 4 d 
1 b 4 e 
1 b 5 c 
1 b 5 d 
1 b 5 e 
2 a 3 c 
2 a 3 d 
2 a 3 e 
2 a 4 c 
2 a 4 d 
2 a 4 e 
2 a 5 c 
2 a 5 d 
2 a 5 e 
2 b 3 c 
2 b 3 d 
2 b 3 e 
2 b 4 c 
2 b 4 d 
2 b 4 e 
2 b 5 c 
2 b 5 d 
2 b 5 e 



發佈了71 篇原創文章 · 獲贊 59 · 訪問量 60萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章