全排列的非递归解法
情景
在类似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