全排列是一種時間復雜度為O(n!)的算法前兩天給學生講課無意間想到這個問題回來總結了一下可以由種算法求解其中動態循環類似回溯算法實現起來比較繁瑣故總結了種以飨讀者所有算法均使用JavaScript編寫可直接運行
算法一交換(遞歸)
復制代碼 代碼如下:
<html xmlns="
<head>
<meta http
equiv="Content
Type" content="text/html; charset=utf
" />
<title>Full Permutation(Recursive Swap)
Mengliao Software</title>
</head>
<body>
<p>Full Permutation(Recursive Swap)<br />
Mengliao Software Studio
Bosun Network Co
Ltd
<br />
</p>
<script type="text/javascript">
/*
全排列(遞歸交換)算法
將第一個位置分別放置各個不同的元素
對剩余的位置進行全排列(遞歸)
遞歸出口為只對一個元素進行全排列
*/
function swap(arr
i
j) {
if(i!=j) {
var temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
var count=
;
function show(arr) {
document
write("P<sub>"+ ++count+"</sub>: "+arr+"<br />");
}
function perm(arr) {
(function fn(n) { //為第n個位置選擇元素
for(var i=n;i<arr
length;i++) {
swap(arr
i
n);
if(n+
<arr
length
) //判斷數組中剩余的待全排列的元素是否大於
個
fn(n+
); //從第n+
個下標進行全排列
else
show(arr); //顯示一組結果
swap(arr
i
n);
}
})(
);
}
perm(["e
"
"e
"
"e
"
"e
"]);
</script>
</body>
</html>
算法二鏈接(遞歸)
復制代碼 代碼如下:
<html xmlns="
<head>
<meta http
equiv="Content
Type" content="text/html; charset=utf
" />
<title>Full Permutation(Recursive Link)
Mengliao Software</title>
</head>
<body>
<p>Full Permutation(Recursive Link)<br />
Mengliao Software Studio
Bosun Network Co
Ltd
<br />
</p>
<script type="text/javascript">
/*
全排列(遞歸鏈接)算法
設定源數組為輸入數組
結果數組存放排列結果(初始化為空數組)
逐一將源數組的每個元素鏈接到結果數組中(生成新數組對象)
從原數組中刪除被鏈接的元素(生成新數組對象)
將新的源數組和結果數組作為參數遞歸調用步驟
直到源數組為空
則輸出一個排列
*/
var count=
;
function show(arr) {
document
write("P<sub>"+ ++count+"</sub>: "+arr+"<br />");
}
function perm(arr) {
(function fn(source
result) {
if (source
length ==
)
show(result);
else
for (var i =
; i < source
length; i++)
fn(source
slice(
i)
concat(source
slice(i +
))
result
concat(source[i]));
})(arr
[]);
}
perm(["e
"
"e
"
"e
"
"e
"]);
</script>
</body>
</html>
算法三回溯(遞歸)
復制代碼 代碼如下:
<html xmlns="
<head>
<meta http
equiv="Content
Type" content="text/html; charset=utf
" />
<title>Full Permutation(Recursive Backtrack)
Mengliao Software</title>
</head>
<body>
<p>Full Permutation(Recursive Backtrack)<br />
Mengliao Software Studio
Bosun Network Co
Ltd
<br />
</p>
<script type="text/javascript">
/*
全排列(遞歸回溯)算法
建立位置數組
即對位置進行排列
排列成功後轉換為元素的排列
建立遞歸函數
用來搜索第n個位置
第n個位置搜索方式與八皇後問題類似
*/
var count =
;
function show(arr) {
document
write("P<sub>" + ++count + "</sub>: " + arr + "<br />");
}
function seek(index
n) {
if (n >=
) //判斷是否已回溯到了第一個位置之前
即已經找到了所有位置排列
if (index[n] < index
length
) { //還有下一個位置可選
index[n]++; //選擇下一個位置
if ((function () { //該匿名函數判斷該位置是否已經被選擇過
for (var i =
; i < n; i++)
if (index[i] == index[n]) return true; //已選擇
return false; //未選擇
})())
return seek(index
n); //重新找位置
else
return true; //找到
}
else { //當前無位置可選
進行遞歸回溯
index[n] =
; //取消當前位置
if (seek(index
n
)) //繼續找上一個位置
return seek(index
n); //重新找當前位置
else
return false; //已無位置可選
}
else
return false;
}
function perm(arr) {
var index = new Array(arr
length);
for (var i =
; i < index
length; i++)
index[i] =
; //初始化所有位置為
以便++後為
for (i =
; i < index
length
; i++)
seek(index
i); //先搜索前n
個位置
while (seek(index
index
length
)) { //不斷搜索第n個位置
即找到所有位置排列
var temp = [];
for (i =
; i < index
length; i++) //將位置之轉換為元素
temp
push(arr[index[i]]);
show(temp);
}
}
perm(["e
"
"e
"
"e
"
"e
"]);
</script>
</body>
</html>
算法四回溯(非遞歸)
復制代碼 代碼如下:
<html xmlns="
<head>
<meta http
equiv="Content
Type" content="text/html; charset=utf
" />
<title>Full Permutation(Non
recursive Backtrack)
Mengliao Software</title>
</head>
<body>
<p>
Full Permutation(Non
recursive Backtrack)<br />
Mengliao Software Studio
Bosun Network Co
Ltd
<br />
</p>
<script type="text/javascript">
/*
全排列(非遞歸回溯)算法
建立位置數組
即對位置進行排列
排列成功後轉換為元素的排列
第n個位置搜索方式與八皇後問題類似
*/
var count =
;
function show(arr) {
document
write("P<sub>" + ++count + "</sub>: " + arr + "<br />");
}
function seek(index
n) {
var flag = false
m = n; //flag為找到位置排列的標志
m保存正在搜索哪個位置
do {
index[n]++;
if (index[n] == index
length) //已無位置可用
index[n
] =
; //重置當前位置
回退到上一個位置
else if (!(function () {
for (var i =
; i < n; i++)
if (index[i] == index[n]) return true;
return false;
})()) //該位置未被選擇
if (m == n) //當前位置搜索完成
flag = true;
else
n++;
} while (!flag && n >=
)
return flag;
}
function perm(arr) {
var index = new Array(arr
length);
for (var i =
; i < index
length; i++)
index[i] =
;
for (i =
; i < index
length
; i++)
seek(index
i);
while (seek(index
index
length
)) {
var temp = [];
for (i =
; i < index
length; i++)
temp
push(arr[index[i]]);
show(temp);
}
}
perm(["e
"
"e
"
"e
"
"e
"]);
</script>
</body>
</html>
算法五排序(非遞歸)
復制代碼 代碼如下:
<html xmlns="
<head>
<meta http
equiv="Content
Type" content="text/html; charset=utf
" />
<title>Full Permutation(Non
recursive Sort)
Mengliao Software</title>
</head>
<body>
<p>
Full Permutation(Non
recursive Sort)<br />
Mengliao Software Studio
Bosun Network Co
Ltd
<br />
</p>
<script type="text/javascript">
/*
全排列(非遞歸求順序)算法
建立位置數組
即對位置進行排列
排列成功後轉換為元素的排列
按如下算法求全排列
設P是
~n(位置編號)的一個全排列
p = p
p
pn = p
p
pj
pj
pj+
pk
pk
pk+
pn
(
)從排列的尾部開始
找出第一個比右邊位置編號小的索引j(j從首部開始計算)
即j = max{i | pi < pi+
}
(
)在pj的右邊的位置編號中
找出所有比pj大的位置編號中最小的位置編號的索引k
即 k = max{i | pi > pj}
pj右邊的位置編號是從右至左遞增的
因此k是所有大於pj的位置編號中索引最大的
(
)交換pj與pk
(
)再將pj+
pk
pk
pk+
pn翻轉得到排列p
= p
p
pj
pj
pn
pk+
pk
pk
pj+
(
)p
便是排列p的下一個排列
例如
是位置編號
~
的一個排列
求它下一個排列的步驟如下
(
)從右至左找出排列中第一個比右邊數字小的數字
(
)在該數字後的數字中找出比
大的數中最小的一個
(
)將
與
交換得到
(
)將原來
(當前
)後面的所有數字翻轉
即翻轉
得
(
)求得
的下一個排列為
*/
var count =
;
function show(arr) {
document
write("P<sub>" + ++count + "</sub>: " + arr + "<br />");
}
function swap(arr
i
j) {
var t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
function sort(index) {
for (var j = index
length
; j >=
&& index[j] > index[j +
]; j
)
; //本循環從位置數組的末尾開始
找到第一個左邊小於右邊的位置
即j
if (j <
) return false; //已完成全部排列
for (var k = index
length
; index[k] < index[j]; k
)
; //本循環從位置數組的末尾開始
找到比j位置大的位置中最小的
即k
swap(index
j
k);
for (j = j +
k = index
length
; j < k; j++
k
)
swap(index
j
k); //本循環翻轉j+
到末尾的所有位置
return true;
}
function perm(arr) {
var index = new Array(arr
length);
for (var i =
; i < index
length; i++)
index[i] = i;
do {
var temp = [];
for (i =
; i < index
length; i++)
temp
push(arr[index[i]]);
show(temp);
} while (sort(index));
}
perm(["e
"
"e
"
"e
"
"e
"]);
</script>
</body>
</html>
算法六求模(非遞歸)
復制代碼 代碼如下:
<html xmlns="
<head>
<meta http
equiv="Content
Type" content="text/html; charset=utf
" />
<title>Full Permutation(Non
recursive Modulo)
Mengliao Software</title>
</head>
<body>
<p>Full Permutation(Non
recursive Modulo)<br />
Mengliao Software Studio
Bosun Network Co
Ltd
<br />
</p>
<script type="text/javascript">
/*
全排列(非遞歸求模)算法
初始化存放全排列結果的數組result
與原數組的元素個數相等
計算n個元素全排列的總數
即n!
從>=
的任意整數開始循環n!次
每次累加
記為index
取第
個元素arr[
]
求
進制的表達最低位
即求index模
的值w
將第
個元素(arr[
])插入result的w位置
並將index迭代為index
取第
個元素arr[
]
求
進制的表達最低位
即求index模
的值w
將第
個元素(arr[
])插入result的w位置
並將index迭代為index
取第
個元素arr[
]
求
進制的表達最低位
即求index模
的值w
將第
個元素(arr[
])插入result的w位置
並將index迭代為index
……
直到取最後一個元素arr[arr
length
]
此時求得一個排列
當index循環完成
便求得所有排列
例
求
個元素["a"
"b"
"c"
"d"]的全排列
共循環
!=
次
可從任意>=
的整數index開始循環
每次累加
直到循環完index+
後結束
假設index=
(或
+
+
*
+
*
…)
因為共
個元素
故迭代
次
則得到的這一個排列的過程為
第
次迭代
/
商=
余數=
故第
個元素插入第
個位置(即下標為
)
得["a"]
第
次迭代
/
商=
余數=
故第
個元素插入第
個位置(即下標為
)
得["a"
"b"]
第
次迭代
/
商=
余數=
故第
個元素插入第
個位置(即下標為
)
得["c"
"a"
"b"]
第
次迭代
/
商=
余數=
故第
個元素插入第
個位置(即下標為
)
得["c"
"a"
"d"
"b"]
*/
var count =
;
function show(arr) {
document
write("P<sub>" + ++count + "</sub>: " + arr + "<br />");
}
function perm(arr) {
var result = new Array(arr
length);
var fac =
;
for (var i =
; i <= arr
length; i++)
fac *= i;
for (index =
; index < fac; index++) {
var t = index;
for (i =
; i <= arr
length; i++) {
var w = t % i;
for (j = i
; j > w; j
)
result[j] = result[j
];
result[w] = arr[i
];
t = Math
floor(t / i);
}
show(result);
}
}
perm(["e
"
"e
"
"e
"
"e
"]);
</script>
</body>
</html>
上面的六種算法有些是對位置進行排列例如回溯排序等因為這樣可以適應各種類型的元素而非要求待排列元素一定是數字或字母等
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19940.html