Permunation-全排列

描述

给定一个集合求全排列

分析

  1. 递归

递归过程如图
这里写图片描述
求【a,b,c】的全排列
即求{ a-[b.c]; b-[a,c]; c-[a,b] } 的全排列,依次类推

void permunation(int start,int end)
{

    ifend==start)//当start == end 时一次递归结束
        return;
    for(int i=start; i<end; i++)
    {
        swap(arr[start],arr[i]);//依次交换 首元素
        permunation(start+1,end);//递归求子序列的全排列
        swap(arr[start],arr[i]);//递归结束后 恢复数列 方便下一次递归
    }
}

2、非递归实现

字典序:将集合A中的元素的排列,与某种顺序建立一一映射的关系,按照这种顺序,将集合的所有排列全部输出。这种顺序需要保证,既可以输出全部的排列,又不能重复输出某种排列,或者循环输出一部分排列。字典序就是用此种思想输出全排列的一种方式。这里以A{1,2,3,4}来说明用字典序输出全排列的方法。按照四位数的大小从小到大输出

这里给出算法。

1、对集合A排序
2、a[1,n] 中从你n~1查找元素 a[k] 满足a[k]>a[k-1]的元素,如果不存在k说明没有下一个排序。
3、找到a[k+1,n]之间比a[k]大的最小的元素 a[i]交换 swap(a[i],a[k]);
4、a[k+1,n]为从大到小排列 逆序a[k+1,n]求得下一个排列。

使用字典序输出集合的全排列需要注意,因为字典序涉及两个排列之间的比较,对于元素集合不方便比较的情况,可以将它们在数组中的索引作为元素,按照字典序生成索引的全排列,然后按照索引输出对应集合元素的排列,对于集合A{a,b,c,d},可以对其索引1234进行全排列生成。这么做还有一个好处,就是对于字典序全排列生成算法,需要从字典序最小的排列开始才能够生成集合的所有排列,如果原始集合A中的元素不是有序的情况,字典序法将无法得到所有的排列结果,需要对原集合排序之后再执行生成算法,生成索引的全排列,避免了对原始集合的排序操作。

字典序算法还有一个优点,就是不受重复元素的影响。例如1224,交换中间的两个2,实际上得到的还是同一个排列,而字典序则是严格按照排列元素的大小关系来生成的。

void reverseArr(arr,start,end)//翻转 [start,end]
{
    for(int i=start; i<end; i++)
        for(int j=end; j!=j; j--)
            std::swap(arr[i],arr[j])
}
void reverseArr_2(arr,star,end)//[start,end]
{
    for(int i=0; i*2<end-start,i++)
        swap(arr[start+i],start[end-i]);
}
void generatePermunation(int *arr,int len)
{
    std::sort(arr,arr+len);
    while(true)
    {
        int k=-1;
        for(int i=len-1; i!=0; i--)
        {
            if(a[i]>a[i-1])
                k = i-1;
        }
        if(k<0)
            return ;
        for(int j=len-1;j!=0; j--)
        {
            if(a[j]>a[k])
            {
                swap(a[j],a[k]);
                reverse(a[k+1],a[len-1]);
                //输出arr
            }
        }
    }
}

参考

https://www.cnblogs.com/nowornever-L/p/6008954.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值