前些天写了《全排列算法(Java实现)》,当时没考虑元素的重复情况。现在考虑重复元素的情况,再写一次。不同的只是这段代码:
//如果i和前面begin~i-1都没重复,才可以swap
boolean doubleSign = false;
for(int j = begin;j<i;j++){
if(array[j] == array[i]){
doubleSign = true;
}
}
if(doubleSign){
continue;
}
完整如下:
public class QuanPailieChongfu {
/** 统计总数 */
static int total = 0;
/** allRank调用次数 */
static int call = 0;
public static void swap(int[] array, int a, int b) {
if (a == b) {
return;
}
array[a] = array[a] ^ array[b];
array[b] = array[a] ^ array[b];
array[a] = array[a] ^ array[b];
}
public static void print(int[] array) {
for (int element : array) {
System.out.print(element + " ");
}
System.out.println();
total++;
}
/**
* 数组第一个元素固定,<br>
* 其他后续的元素再allRank(array, begin + 1, length); <br>
* (当然,还需要轮流让每个元素放在第一位)
*
* @param array
* @param begin
* @param length
*/
public static void allRank(int[] array, int begin, int length) {
call++;
if (begin == length - 1) {
// 每个递归的最后,是打印输出
print(array);
} else {
for (int i = begin; i < length; i++) {
//如果i和前面begin~i-1都没重复,才可以swap
boolean doubleSign = false;
for(int j = begin;j<i;j++){
if(array[j] == array[i]){
doubleSign = true;
}
}
if(doubleSign){
continue;
}
// 使用for(int i = begin; i < length; i++)去轮流放在第一位
swap(array, begin, i);
// 无视第一位,将后续的元素继续递归
allRank(array, begin + 1, length);
// 如果不恢复现场,那么allRank就是一个会改变array的函数,那么
// 使用“for(int i = begin; i < length; i++)去轮流放在第一位的做法”
// 就会失效。
swap(array, i, begin);
}
}
}
public static void main(String[] args) {
int[] array = { 1, 1, 1, 4, 5 };
allRank(array, 0, 5);
System.out.println("不同顺序的总数(5!):" + total + "\n allRank()被调用的总数:" + call);
}
}
效果如下:
1 1 1 4 5
1 1 1 5 4
1 1 4 1 5
1 1 4 5 1
1 1 5 4 1
1 1 5 1 4
1 4 1 1 5
1 4 1 5 1
1 4 5 1 1
1 5 1 4 1
1 5 1 1 4
1 5 4 1 1
4 1 1 1 5
4 1 1 5 1
4 1 5 1 1
4 5 1 1 1
5 1 1 4 1
5 1 1 1 4
5 1 4 1 1
5 4 1 1 1
不同顺序的总数(5!/3!=120/6=20):20
allRank()被调用的总数:44