欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[土味]Java遍历无序全排列组合

程序员文章站 2022-06-07 19:51:32
...

Java遍历无序全排列组合

在做迷宫生成,拆墙时需要用到无序的全排列,网上找到一段代码,也没有注释,看不懂,自己研究了下,把分析过程贴出来.

原文链接
java排列组合 实现全排列,支持有序和无序

先上代码

/**
     * 方法一:无序
     *
     * @param data
     * @param <E>
     * @return
     */
    public static <E> List<List<E>> arrangeSelect1(List<E> data) {

        int size = data.size();
        // 一共 2^size-1 个无序全排列组合
        int count = (int) (Math.pow(2, size) - 1);

        List<List<E>> arrangeAllSet = new ArrayList<>();

        for (int i = 1; i <= count; i++) {

            List<E> arrangeSet = new ArrayList<>();

            for (int j = 0; j < size; j++) {
                if ((i << (31 - j)) >> 31 == -1) {
                    arrangeSet.add(data.get(j));
                }
            }
            arrangeAllSet.add(arrangeSet);
        }
        return arrangeAllSet;
    }

	@Test
    public void test() {
        List<Integer> data = new ArrayList<Integer>();
        for(int i=0; i<3; i++) {
            data.add(i);
        }

        List<List<Integer>> arrangeList1 = arrangeSelect1(data);
        System.out.println(arrangeList1);

    }

他这边主要用到了左移和右移,特点如下
<< 左移,丢弃最高位(符号位同样丢弃),0补最低位
>> 右移 符号位不变,左边补上符号位

下面上分析过程
int a = 1;
0x00000001 (1的16进制)
0000 0000 0000 0000 0000 0000 0000 0001 (1的二进制)

执行 1 << 31
1000 0000 0000 0000 0000 0000 0000 0000

执行 1 << 31 >> 1
1100 0000 0000 0000 0000 0000 0000 0000

执行 1 << 31 >> 2
1110 0000 0000 0000 0000 0000 0000 0000

执行 1 << 31 >> 31 = -1
1111 1111 1111 1111 1111 1111 1111 1111

执行 1 << 10
0000 0000 0000 0000 0000 0100 0000 0000

执行 1 << 10 >> 31 = 0
0000 0000 0000 0000 0000 0000 0000 0000

结论: 对于1来说,只有一种情况可以让表达式 1 << (31 - j)) >> 31 == -1 成立,就是 j=0
对于2,3,4,5…来说,也可以用同样的方法得到 j 的取值,结果如下:

i 表达式 j 取值
1 << 31 >> 31 = -1 j=0
2 << 30 >> 31 = -1 j=1
3 << 31 >> 31 = -1 j=0
3 << 30 >> 31 = -1 j=1
4 << 29 >> 31 = -1 j=2
5 << 31 >> 31 = -1 j=0
5 << 29 >> 31 = -1 j=2
6 << 30 >> 31 = -1 j=1
6 << 29 >> 31 = -1 j=2
7 << 31 >> 31 = -1 j=0
7 << 30 >> 31 = -1 j=1
7 << 29 >> 31 = -1 j=2
8 << 28 >> 31 = -1 j=3
  • 横向看,可以看到数字3对应的 j 有两种情况,7有3种,其实可以看成3 = 1 + 2, 3的表达式是有1和2的表达式组合起来的,同样7 = 1 + 2 + 4,所以7的表达式就是1,2,4的表达式组合起来的.

  • 纵向看 j取值列,可以发现,
    第一行是1个元素{0}的全排列{0},
    第1-4行是两个元素{0, 1}的全排列{[0],[1],[0,1]},
    第1-12行是3个元素{0, 1, 2}的全排列{[0], [1], [0, 1], [2], [0, 2], [1, 2], [0, 1, 2]}

  • 所以通过 i 和 j 的两重循环,就可以将所有的无序排列组合全部打印出来.

参考资料
java排列组合 实现全排列,支持有序和无序

相关标签: 土味 算法