C++ STL之next_permutation小证明与Java实现
最近在用Java写程序时,会经常涉及到生成排列之类,在C++ STL里面有next_permutation
这个函数,可在Java里的确没有这个函数的实现,于是自己对next_permutation
稍微理顺了一下。
next_permutation实现思路:
在当前序列中,从尾端向前寻找两个相邻元素,前一个记为*i,后一个记为*j,并且满足*i < *j。然后再从尾端寻找另一个元素*t,如果满足*i < *t,即将第i个元素与第t个元素对调,并将第j个元素之后(包括j)的所有元素颠倒排序,即求出下一个序列了。
自己的小证明如下:
例如: 1 3 4 5 2
这个序列首先从尾部找到两相邻元素i, j, i=2,j=3, 同时t=j, 即i, j之后都为逆序,所以显然就是i与j交换才能得到下一个序列。例如:1 5 7 6 4 3 2
这个序列,对应的i=2, j=3, 但从尾部向前寻找元素t时, t!=j, 即*t > *i && *t < *j,所以这样子*t肯定是在位置j之后大于*i的元素中的最小值,所以*i与*t交换、j之后的元素逆序排列是能够得到下一个序列的。
一个排列一个具有N个元素的代码:
package lanqiao;
import java.util.ArrayList;
public class PREV_2 {
static int[] array = new int[10];
static void reverse(int begin, int end) {
int mid = (begin+end) / 2;
int cnt = 0;
for(; ;) {
if(cnt > mid-begin) break;
int t = array[begin+cnt]; array[begin+cnt] = array[end-cnt]; array[end-cnt] = t;
cnt++;
}
}
static boolean next_per(int begin, int end) {
if(begin == end) return false; //为空
if(begin+1 == end) return false; //只有一个元素
int i = end;
for(; ;) {
int j = i; --i;
if(array[i] < array[j]) { //前<后 相邻
int t = end;
while(array[i] >= array[t]) {
--t;
}
//System.out.println(array[i] +"~"+ array[t]);
int temp = array[i]; array[i] = array[t]; array[t] = temp;
reverse(j, end);
return true;
}
if(i == begin) { //前一元素已经指向首元素,反转整个区间,无下一元素 dcba的下一个排列是abcd
reverse(begin, end);
return false;
}
}
}
public static void main(String[] args) {
array[1] = 1; array[2] = 2; array[3] = 3; array[4] = 4; array[5] = 5; array[6] = 6;
array[7] = 7; array[8] = 8; array[9] = 9;
while(next_per(1, 9)) {
for(int i = 1;i <= 9;i++) {
System.out.print(array[i]+" ");
}
System.out.println();
}
}
}
p.s本文是我第一次采用MarkDown撰写