全排列算法的递归与非递归实现
全排列算法的递归与非递归实现.出于语言特性问题,运行效率较低.
<
script language
=
"
JavaScript
"
>
<!--
// 全排列递归算法
// code by meixx(梅雪香)
/**/ /*
递归的算法采用分而治之的思想
考虑序列 P1P2P3Pn 可以分解为 P1 + C(P2P3Pn),依此类推.
*/
function combination(arr) {
var len = arr.length;
if (len == 2 ) {
var a = arr[ 0 ], b = arr[ 1 ];
return [a + b,b + a];
}
else if (len == 1 ) return arr;
else {
var strRtn = "" ;
for ( var i = 0 ;i < len;i ++ ) {
strRtn += merge(arr[i],combination(arr.slice( 0 ,i).concat(arr.slice(i + 1 ,len)))).join( " , " ) + " , " ;
}
return strRtn.replace( / \,$ / , "" ).split( " , " );
}
}
function merge(head,arr) {
for ( var i = 0 ;i < arr.length;i ++ )
arr[i] = head + arr[i];
return arr;
}
/**/ /*
var ar = combination("54321".split(""));
for(var i=0;i<ar.length;i++)
document.write(ar[i].join(""),"<br>");
*/
// -->
</ script >
< script language = " JavaScript " >
<!--
// 全排列非递归算法
// code by meixx(梅雪香)
/**/ /*
非递归全排列算法的基本思想是:
1.找到所有排列中最小的一个排列P.
2.找到刚刚好比P大比其它都小的排列Q,
3.循环执行第二步,直到找到一个最大的排列,算法结束.
下面用数学的方法描述:
给定已知序列 P = A1A2A3An ( Ai!=Aj , (1<=i<=n , 1<=j<=n, i != j ) )
找到P的一个最小排列Pmin = P1P2P3Pn 有 Pi > P(i-1) (1 < i <= n)
从Pmin开始,总是目前得到的最大的排列为输入,得到下一个排列.
方法为:
1.从低位到高位(从后向前),找出“不符合趋势”的数字。即找到一个Pi,使Pi < P(i+1)。
若找不到这样的pi,说明我们已经找到最后一个全排列,可以返回了。
2.在 P(i+1)P(i+2)Pn 中,找到一个Pj,便得 Pj"刚刚好大于"Pi.
("刚刚好大于"的意思是:在 P(i+1)P(i+2)Pn 中所有大于Pi的元素构成的集合中最小的元素.)
3.交换 Pi , Pj 的位置.注意:此处不改变i和j的值,改变的是Pi和Pj.
4.交换后, P1P2P3Pn 并不是准确的后一个排列。因为根据第1步的查找,我们有P(i+1) > P(i+2) > . > Pn
即使进行了Pi和Pj的交换,这仍然是这一部分最大的一个排列。将此排列逆序倒置(变成最小的排列)即为所求的下一个排列.
5.重复步骤1-4,直到步骤1中找不到“不符合趋势”的数字.
*/
// 参数arr:待进行全排列的数组(没有重复的元素)
function Combin(arr) {
var arResult = [];
var ar = arr.sort();
arResult.push(ar);
for (;;) {
ar = FindNext(arResult[ 0 ],ar);
if ( ! ar) return arResult;
arResult.push(ar);
}
}
function FindNext(arFirst,arLast) {
for ( var i = arLast.length - 1 ;i > 0 ;i -- ) {
if (arLast[i - 1 ] < arLast[i]) { // 找到了"不符合趋势"的数字
var ar = arLast.slice();
var strTail = ar.slice(i).join( "" );
var tmpStr = arFirst.join( "" );
var strSearch = tmpStr.substr( tmpStr.indexOf(ar[i - 1 ]) + 1 );
// 确定ar[i-1]要交换的字符及该字符的位置
for ( var j = 0 ,k = strSearch.length;j < k;j ++ ) {
var ch = strSearch.charAt(j);
var idx = strTail.indexOf(ch);
if ( idx >= 0 ) break ;
}
ar[i + idx] = ar[i - 1 ];
ar[i - 1 ] = ch;
return ar.slice( 0 ,i).concat(ar.slice(i).reverse());
}
}
return null ; // 找不到"不符合趋势"的数字,说明所有的排列已经找到
}
/**/ /*
var ar = Combin("f4e3r21".split(""));
for(var i=0;i<ar.length;i++)
document.write(ar[i].join(""),"<br>");
*/
// -->
</ script >
<!--
// 全排列递归算法
// code by meixx(梅雪香)
/**/ /*
递归的算法采用分而治之的思想
考虑序列 P1P2P3Pn 可以分解为 P1 + C(P2P3Pn),依此类推.
*/
function combination(arr) {
var len = arr.length;
if (len == 2 ) {
var a = arr[ 0 ], b = arr[ 1 ];
return [a + b,b + a];
}
else if (len == 1 ) return arr;
else {
var strRtn = "" ;
for ( var i = 0 ;i < len;i ++ ) {
strRtn += merge(arr[i],combination(arr.slice( 0 ,i).concat(arr.slice(i + 1 ,len)))).join( " , " ) + " , " ;
}
return strRtn.replace( / \,$ / , "" ).split( " , " );
}
}
function merge(head,arr) {
for ( var i = 0 ;i < arr.length;i ++ )
arr[i] = head + arr[i];
return arr;
}
/**/ /*
var ar = combination("54321".split(""));
for(var i=0;i<ar.length;i++)
document.write(ar[i].join(""),"<br>");
*/
// -->
</ script >
< script language = " JavaScript " >
<!--
// 全排列非递归算法
// code by meixx(梅雪香)
/**/ /*
非递归全排列算法的基本思想是:
1.找到所有排列中最小的一个排列P.
2.找到刚刚好比P大比其它都小的排列Q,
3.循环执行第二步,直到找到一个最大的排列,算法结束.
下面用数学的方法描述:
给定已知序列 P = A1A2A3An ( Ai!=Aj , (1<=i<=n , 1<=j<=n, i != j ) )
找到P的一个最小排列Pmin = P1P2P3Pn 有 Pi > P(i-1) (1 < i <= n)
从Pmin开始,总是目前得到的最大的排列为输入,得到下一个排列.
方法为:
1.从低位到高位(从后向前),找出“不符合趋势”的数字。即找到一个Pi,使Pi < P(i+1)。
若找不到这样的pi,说明我们已经找到最后一个全排列,可以返回了。
2.在 P(i+1)P(i+2)Pn 中,找到一个Pj,便得 Pj"刚刚好大于"Pi.
("刚刚好大于"的意思是:在 P(i+1)P(i+2)Pn 中所有大于Pi的元素构成的集合中最小的元素.)
3.交换 Pi , Pj 的位置.注意:此处不改变i和j的值,改变的是Pi和Pj.
4.交换后, P1P2P3Pn 并不是准确的后一个排列。因为根据第1步的查找,我们有P(i+1) > P(i+2) > . > Pn
即使进行了Pi和Pj的交换,这仍然是这一部分最大的一个排列。将此排列逆序倒置(变成最小的排列)即为所求的下一个排列.
5.重复步骤1-4,直到步骤1中找不到“不符合趋势”的数字.
*/
// 参数arr:待进行全排列的数组(没有重复的元素)
function Combin(arr) {
var arResult = [];
var ar = arr.sort();
arResult.push(ar);
for (;;) {
ar = FindNext(arResult[ 0 ],ar);
if ( ! ar) return arResult;
arResult.push(ar);
}
}
function FindNext(arFirst,arLast) {
for ( var i = arLast.length - 1 ;i > 0 ;i -- ) {
if (arLast[i - 1 ] < arLast[i]) { // 找到了"不符合趋势"的数字
var ar = arLast.slice();
var strTail = ar.slice(i).join( "" );
var tmpStr = arFirst.join( "" );
var strSearch = tmpStr.substr( tmpStr.indexOf(ar[i - 1 ]) + 1 );
// 确定ar[i-1]要交换的字符及该字符的位置
for ( var j = 0 ,k = strSearch.length;j < k;j ++ ) {
var ch = strSearch.charAt(j);
var idx = strTail.indexOf(ch);
if ( idx >= 0 ) break ;
}
ar[i + idx] = ar[i - 1 ];
ar[i - 1 ] = ch;
return ar.slice( 0 ,i).concat(ar.slice(i).reverse());
}
}
return null ; // 找不到"不符合趋势"的数字,说明所有的排列已经找到
}
/**/ /*
var ar = Combin("f4e3r21".split(""));
for(var i=0;i<ar.length;i++)
document.write(ar[i].join(""),"<br>");
*/
// -->
</ script >