zoukankan      html  css  js  c++  java
  • C++ STL 全排列函数详解

    一、概念

      从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。如果这组数有n个,那么全排列数为n!个。

      比如a,b,c的全排列一共有3!= 6 种 分别是{a, b, c}、{a, c, b}、{b, a, c}、{b, c, a}、{c, a, b}、{c, b, a}。

    二、常用操作

      1.头文件

    #include <algorithm>

      2.使用方法

      这里先说两个概念:“下一个排列组合”和“上一个排列组合”,对序列 {a, b, c},每一个元素都比后面的小,按照字典序列,固定a之后,a比bc都小,c比b大,它的下一个序列即为{a, c, b},而{a, c, b}的上一个序列即为{a, b, c},同理可以推出所有的六个序列为:{a, b, c}、{a, c, b}、{b, a, c}、{b, c, a}、{c, a, b}、{c, b, a},其中{a, b, c}没有上一个元素,{c, b, a}没有下一个元素。

        1)next_permutation:求下一个排列组合 

    a.函数模板:next_permutation(arr, arr+size);
    b.参数说明:
      arr: 数组名
      size:数组元素个数
    c.函数功能: 返回值为bool类型,当当前序列不存在下一个排列时,函数返回false,否则返回true,排列好的数在数组中存储

    d.注意:在使用前需要对欲排列数组按升序排序,否则只能找出该序列之后的全排列数。
        比如,如果数组num初始化为2,3,1,那么输出就变为了:{2 3 1} {3 1 2} {3 2 1}

    2)prev_permutation:求上一个排列组合

    a.函数模板:prev_permutation(arr, arr+size);
    b.参数说明:
      arr: 数组名
      size:数组元素个数
    c.函数功能: 返回值为bool类型,当当前序列不存在上一个排列时,函数返回false,否则返回true
    d.注意:在使用前需要对欲排列数组按降序排序,否则只能找出该序列之后的全排列数。

    三、代码

    #include <iostream>
    #include <algorithm>
    using namespace std;
    int main ()
    {
        int arr[] = {3,2,1};
        cout<<"用prev_permutation对3 2 1的全排列"<<endl;
        do
        {
            cout << arr[0] << ' ' << arr[1] << ' ' << arr[2]<<'
    ';
        }
        while ( prev_permutation(arr,arr+3) );      ///获取上一个较大字典序排列,如果3改为2,只对前两个数全排列
    
        int arr1[] = {1,2,3};
        cout<<"用next_permutation对1 2 3的全排列"<<endl;
        do
        {
            cout << arr1[0] << ' ' << arr1[1] << ' ' << arr1[2] <<'
    ';
        }
        while ( next_permutation(arr1,arr1+3) );      ///获取下一个较大字典序排列,如果3改为2,只对前两个数全排列
        ///注意数组顺序,必要时要对数组先进行排序
    
        return 0;
    }

     四、全排列递归思路

    我们可以将这个排列问题画成图形表示,即排列枚举树,比如下图为{1,2,3}的排列枚举树,此树和我们这里介绍的算法完全一致;
     
     
    算法思路:
    (1)n个元素的全排列=(n-1个元素的全排列)+(另一个元素作为前缀);
    (2)出口:如果只有一个元素的全排列,则说明已经排完,则输出数组;
    (3)不断将每个元素放作第一个元素,然后将这个元素作为前缀,并将其余元素继续全排列,等到出口,出口出去后还需要还原数组;
    代码:
    public class hello {
        public static int arr[] = new int[]{1,2,3};
        public static void main(String[] args) {
            perm(arr,0,arr.length-1);
        }
        private static void swap(int i1, int i2) {
            int temp = arr[i2];
            arr[i2] = arr[i1];
            arr[i1] = temp;
        }
    
        /**
         * 对arr数组中的begin~end进行全排列
         * 
         * 比如:
         *     arr = {1,2,3}
         *  第一步:执行 perm({1,2,3},0,2),begin=0,end=2;
         *      j=0,因此执行perm({1,2,3},1,2),begin=1,end=2;
         *          j=1,swap(arr,0,0)-->arr={1,2,3},  perm({1,2,3},2,2),begin=2,end=2;
         *               因为begin==end,因此输出数组{1,2,3}
         *           swap(arr,1,1) --> arr={1,2,3};
         *           j=2,swap(arr,1,2)-->arr={1,3,2},  perm({1,3,2},2,2),begin=2,end=2;
         *               因为begin==end,因此输出数组{1,3,2}
         *           swap(arr,2,1) --> arr={1,2,3};
         *       j=1,swap(arr,0,1) --> arr={2,1,3},      perm({2,1,3},1,2),begin=1,end=2;
         *           j=1,swap(arr,1,1)-->arr={2,1,3}   perm({2,1,3},2,2),begin=2,end=2;
         *               因为begin==end,因此输出数组{2,1,3}
         *           swap(arr,1,1)--> arr={2,1,3};
         *           j=2,swap(arr,1,2)后 arr={2,3,1},并执行perm({2,3,1},2,2),begin=2,end=2;
         *               因为begin==end,因此输出数组{2,3,1}
         *           swap(arr,2,1) --> arr={2,1,3};
         *       swap(arr,1,0)  --> arr={1,2,3}
         *       j=2,swap(arr,2,0) --> arr={3,2,1},执行perm({3,2,1},1,2),begin=1,end=2;
         *           j=1,swap(arr,1,1) --> arr={3,2,1} , perm({3,2,1},2,2),begin=2,end=2;
         *               因为begin==end,因此输出数组{3,2,1}
         *           swap(arr,1,1) --> arr={3,2,1};
         *           j=2,swap(arr,2,1) --> arr={3,1,2},并执行perm({2,3,1},2,2),begin=2,end=2;
         *               因为begin==end,因此输出数组{3,1,2}
         *           swap(arr,2,1) --> arr={3,2,1};
         *       swap(arr,0,2) --> arr={1,2,3}
         *       
         */
        public static void perm(int arr[], int begin,int end) {
            if(end==begin){            //一到递归的出口就输出数组,此数组为全排列
                for(int i=0;i<=end;i++){
                    System.out.print(arr[i]+" ");
                }
                System.out.println();
                return;
            }
            else{
                for(int j=begin;j<=end;j++){    
                    swap(begin,j);        //for循环将begin~end中的每个数放到begin位置中去
                    perm(arr,begin+1,end);    //假设begin位置确定,那么对begin+1~end中的数继续递归
                    swap(begin,j);        //换过去后再还原
                }
            }
        }
    }
  • 相关阅读:
    Java学习二十九天
    Java学习二十八天
    47. Permutations II 全排列可重复版本
    46. Permutations 全排列,无重复
    subset ii 子集 有重复元素
    339. Nested List Weight Sum 339.嵌套列表权重总和
    251. Flatten 2D Vector 平铺二维矩阵
    217. Contains Duplicate数组重复元素
    209. Minimum Size Subarray Sum 结果大于等于目标的最小长度数组
    438. Find All Anagrams in a String 查找字符串中的所有Anagrams
  • 原文地址:https://www.cnblogs.com/aiguona/p/7304945.html
Copyright © 2011-2022 走看看