全排列的非递归解法

全排列的非递归解法

情景

在类似16-QAM的星座图的模型中,想要找到一个最优的映射方式,由于没有想到什么合适的规则,于是想到穷举法。可是穷举法要把16!种排列方式全部列出,内存肯定不够用,matlab的perms函数也只支持长度为10的全排列,因此需要一个非递归穷举全排列的方法。
部分内容转载自:https://www.cnblogs.com/bakari/archive/2012/08/02/2620826.html

算法简述

要考虑全排列的非递归实现,先来考虑如何计算字符串的下一个排列。如"1234"的下一个排列就是"1243"。只要对字符串反复求出下一个排列,全排列的也就迎刃而解了。

如何计算字符串的下一个排列了?来考虑"926520"这个字符串,我们从后向前找第一双相邻的递增数字,“20”、"52"都是非递增的,“26 “即满足要求,称前一个数字2为替换数,替换数的下标称为替换点,再从后面找一个比替换数大的最小数(这个数必然存在),0、2都不行,5可以,将5和2交换得到"956220”,然后再将替换点后的字符串"6220"颠倒即得到"950226”(这是因为替换点后的数已经是最大数,颠倒之后可得到最小数。)。

如果达到这个数的最大,比如1234-à4321,这个时候就结束整个循环。

如果输入是一个非最小数,如1324,则将它转换为最小数,如1234,再进行排序。

C代码

//转载自https://www.cnblogs.com/bakari/archive/2012/08/02/2620826.html
//未经本博尝试运行
Prem( char *s )   //全排列函数
{
    char *pEnd = s + strlen(s) - 1;
    char *p = pEnd;  //p代表替换点
    //q代表替换点的下一个数 ,pMax 代表替换点后比替换点大的最小数
    char *q = new char,*pMax = new char;  //注意初始化!!!
    while (p !=  s)          //p == s 就结束循环
    {
        q = p;
        p--;
        if (*p < *q)
        {
            pMax = FindMaxForOne(p,pEnd);  //找与替换点交换的点
            Swap(p,pMax);         //交换
            Reverse(q,pEnd);       //将替换点后所有数进行反转
            Print(s);              //输出
            p = pEnd;             //将替换点置最后一个点,开始下一轮循环
        }
        if (s == p) break;           //结束条件
    }
}


char* FindMaxForOne(char *p,char *q)
{
    char *p1 = p;
    char *p2 = q;
    while (*p2 <= *p1) p2--;
    return p2;
}

matlab代码

function next_perm = NextPerm(X)
% given a vector, find the next permutation.
% input:
%   X is a vector.
% output:
%   next_perm is a vector, is the next permutation of X. the rule of find
%   next can be found in https://www.cnblogs.com/bakari/archive/2012/08/02/2620826.html
% Example:
% X = [1,2,3,4];
% next_perm = [1,2,4,3];
% Version 1, created at 2019/03/31;

L = length(X);
next_perm = X;

if L <= 1
    next_perm = X;
    return ;
end

for replace_index_A = L - 1:-1:1
    if X(replace_index_A) < X(replace_index_A + 1);
        break;
    end
end

if replace_index_A == 1 && X(1) > X(2)
   next_perm = 0;
   return
end

for replace_index_B = L:-1:2
    if X(replace_index_A) < X(replace_index_B)
        % swap A and B.
        next_perm(replace_index_A) = X(replace_index_B);
        next_perm(replace_index_B) = X(replace_index_A);
        next_perm(replace_index_A + 1:L) = fliplr(next_perm(replace_index_A + 1:L));
        break;
    end
end
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值