• 全排列算法:递归和非递归实现


    参考资料:http://blog.csdn.net/e3399/article/details/7543861

    如果要求C(n,m),例如C(5,2)=5!/(2!*3!)=10,就参考http://www.cnblogs.com/qrlozte/p/3497035.html

    如果要求P(n,n),例如P(3,3)=3!=6,就使用本文章提到的全排列算法

    如果要求P(n,m),例如P(5,2)=5!/(5-2)!=20,就先求C(n,m),然后对每一个组合求P(m,m)即可,因为P(n,m)=C(n,m)*P(m,m)

    1.非递归实现 next_permutation

      1.1 基本思想

        注:此算法要求被排列的各个元素之间具有“Natural Order”,也就是说这些元素可以组成一个有序的序列,在JAVA中可以通过实现Comparable来完成

             1.对初始队列进行排序,找到所有排列中最小的一个排列Pmin。
             2.找到刚刚好比Pmin大比其它都小的排列P(min+1)。
             3.循环执行第二步,直到找到一个最大的排列,算法结束。

         例如排列ABCDE,这是所有排列中最小的一个排列,刚好比ABCDE大的排列是:ABCED。

      1.2 算法描述

        给定已知序列P = A1A2A3.....An
        对P按字典排序,得到P的一个最小排列Pmin = A1A2A3....An ,满足Ai > A(i-1) (1 < i <= n)
        从Pmin开始,找到刚好比Pmin大的一个排列P(min+1),再找到刚好比P(min+1)大的一个排列,如此重复。
        1.从后向前(即从An->A1),找到第一对为升序的相邻元素,即Ai < A(i+1)。
          若找不到这样的Ai,说明已经找到最后一个全排列,可以返回了。
        2.从后向前,找到第一个比Ai大的数Aj,交换Ai和Aj。
        3.将排列中A(i+1)A(i+2)....An这个序列的数逆序倒置,即An.....A(i+2)A(i+1)。因为由前面第1、2可以得知,A(i+1)>=A(i+2)>=.....>=An,这为一个升序序列,应将该序列逆序倒置,所得到的新排列才刚刚好比上个排列大。
        4.重复步骤1-3,直到返回。

      1.3 代码

    /* Print the all-permutation of the given int array. */
    void next_permutation(int a[], int length)
    {
        if (length < 2)
        {
            return;
        }
        
        while (true)
        {
            print_array(a, length); // print the permutation
    
            int i, j;
            for (i = length-2; i >= 0; --i)
            {
                if (a[i] < a[i + 1])
                    break;
                else if (i == 0)
                    return;
                else
                    ;
            }
            for (j = length-1; j > i; --j)
            {
                if (a[j] > a[i])
                    break;
                else
                    ;
            }
            swap(a, i, j);
            reverse(a, i + 1, length - 1);
        }
    }
    
    /* Reverse the elements between a[i] and a[j], inclusive. */
    void reverse(int a[], int i, int j)
    {
        for (; i<j; i++, j--)
        {
            swap(a, i, j);
        }
    }
    
    /* Swap two elements in an int array. */
    void swap(int *a, int i, int j)
    {
        a[j] ^= a[i];
        a[i] ^= a[j];
        a[j] ^= a[i];
    }
    
    /* Print an int array to the standard output stream. */
    void print_array(int a[], int length)
    {
        std::cout << "[";
        for (int i = 0; i < length-1; i++)
        {
            std::cout << a[i] << ", ";
        }
        std::cout << a[length-1] << "]" << std::endl;
    }

    2.递归实现

      参考http://blog.csdn.net/e3399/article/details/7543861

  • 相关阅读:
    两个页面相同js方法兼容
    两个页面js方法兼容
    jQuery Chosen 使用
    我写的一个抓取基金净值的工具
    自己做的一个固定大小对象内存池,效率大概为原始的new/delete的2倍
    用libevent实现的echo服务器及telnet客户端
    共享一个防止脚本重复启动的shell脚本
    神煞排盘软件
    一个在字符串中查找多个关键字的函数strstrs(三种不同算法实现及效率分析)
    写了一个时间处理的类,能将人类时间转换成距离公元零年一月一日秒数(时间戳),同时支持时间戳转换成日期时间
  • 原文地址:https://www.cnblogs.com/qrlozte/p/3497801.html
Copyright © 2020-2023  润新知