Johnson-Trotter算法的分析和java实现
2017-10-06 16:33
330 查看
Steinhaus-Johnson-Trotter算法是一种基于最小变换的全排列生成算法,对于排列a[1...n],该算法通过将a[i],与a[i-1](或a[i+1])进行交换,生成下一个排列,直到所有排列生成完毕为止,这样,当前排列与其后继排列只是两个相邻位置的元素发生了调换。当然,为了防止重复生成某一个排列,算法并非随意调换某两个元素之间的位置,其生成全排列的具体规则如下。
首先,以字典序最小的排列起始,并且为该排列的每个元素赋予一个移动方向,初始所有元素的移动方向都向左。
在排列中查找这样的元素,该元素按照其对应的移动方向移动,可以移动到一个合法位置,且移动方向的元素小于该元素,在所有满足条件的元素中,找到其中的最大者。
将该元素与其移动方向所对应的元素交换位置。
对于排列中,所有元素值大于该元素的元素,反转其移动方向。
这里有几个概念需要说明一下,所谓合法位置,是指该元素按照其移动方向移动,不会移动到排列数组之外,例如对于<4,<1,<2,<3,此时对于元素4,如果继续向左移动,就会超过数组范围,所以4的下一个移动位置是非法位置。而且,所有元素,都只能向比自己小的元素的方向移动,如上面例子中的元素2,3,而元素1是不能够移动到元素4的位置的。每次移动,都要对可以移动的所有元素中的最大者进行操作,上例中元素1,4不能移动,2,3都存在合法的移动方案,此时需要移动3,而不能移动2。合法移动之后,需要将所有大于移动元素的元素的移动方向反转,上例中的元素3移动后的结果是4>,1<,<3,<2,可以看到,元素4的移动方向改变了。再如此例子<2,<1,3>,4>,对于其中的元素2,4,其对应的下一个移动位置都是非法位置,而对于元素1,3,其下一个移动位置的元素,都比他们要大,对于该排列就找不到一个可以的移动方案,这说明该算法已经达到终态,全排列生成结束。下面是该算法的代码
package cn.sunline.test;
public class FullPermutation3 {
public static void swap(int[] intarr, int i, int j)
{
int temp;
temp = intarr[i];
intarr[i] = intarr[j];
intarr[j] = temp;
}
public static int SJTNext( int[] index, int[] move)
{
int i, j, t;
int array_size = index.length;
//找到最大合法移动的元素索引
for(i = array_size - 1, j = array_size; i >= 0; --i)
{
if(i + move[i] < array_size && i + move[i] >= 0 && index[i] > index[i + move[i]])
{
if(j == array_size)
{
j = i;
continue;
}
if(index[i] > index[j])
{
j = i;
}
}
}
//未发现合法的移动策略
if(j == array_size)
{
return 1;
}
t = index[j];//要交换位置的元素
i = j + move[j];//发生交换的位置
swap(index, i, j);
swap(move, i, j);
//将所有比t大的元素的移动方向反转
for(i = 0; i < array_size; ++i)
{
if(index[i] > t)
{
move[i] = -move[i];
}
}
return 0;
}
public static void arrayPrint(char[] array,int[] index){
int array_size = array.length;
for(int x:index){
System.out.print(array[x]);
}
System.out.println();
}
/*
* 基于最小变换的Steinhaus–Johnson–Trotter算法
*/
static void FullArray(char[] array)
{
int array_size = array.length;
int[] index = new int[array_size];
int[] move = new int[array_size];
for( int i = 0; i < array_size; ++i)
{
index[i] = i;
move[i] = -1;
}
arrayPrint(array, index);
while(SJTNext(index, move) == 0)
{
arrayPrint(array, index);
}
}
public static void main(String[] args) {
char[] charx = {'a','b','c','c'};
FullArray(charx);
}
}
首先,以字典序最小的排列起始,并且为该排列的每个元素赋予一个移动方向,初始所有元素的移动方向都向左。
在排列中查找这样的元素,该元素按照其对应的移动方向移动,可以移动到一个合法位置,且移动方向的元素小于该元素,在所有满足条件的元素中,找到其中的最大者。
将该元素与其移动方向所对应的元素交换位置。
对于排列中,所有元素值大于该元素的元素,反转其移动方向。
这里有几个概念需要说明一下,所谓合法位置,是指该元素按照其移动方向移动,不会移动到排列数组之外,例如对于<4,<1,<2,<3,此时对于元素4,如果继续向左移动,就会超过数组范围,所以4的下一个移动位置是非法位置。而且,所有元素,都只能向比自己小的元素的方向移动,如上面例子中的元素2,3,而元素1是不能够移动到元素4的位置的。每次移动,都要对可以移动的所有元素中的最大者进行操作,上例中元素1,4不能移动,2,3都存在合法的移动方案,此时需要移动3,而不能移动2。合法移动之后,需要将所有大于移动元素的元素的移动方向反转,上例中的元素3移动后的结果是4>,1<,<3,<2,可以看到,元素4的移动方向改变了。再如此例子<2,<1,3>,4>,对于其中的元素2,4,其对应的下一个移动位置都是非法位置,而对于元素1,3,其下一个移动位置的元素,都比他们要大,对于该排列就找不到一个可以的移动方案,这说明该算法已经达到终态,全排列生成结束。下面是该算法的代码
package cn.sunline.test;
public class FullPermutation3 {
public static void swap(int[] intarr, int i, int j)
{
int temp;
temp = intarr[i];
intarr[i] = intarr[j];
intarr[j] = temp;
}
public static int SJTNext( int[] index, int[] move)
{
int i, j, t;
int array_size = index.length;
//找到最大合法移动的元素索引
for(i = array_size - 1, j = array_size; i >= 0; --i)
{
if(i + move[i] < array_size && i + move[i] >= 0 && index[i] > index[i + move[i]])
{
if(j == array_size)
{
j = i;
continue;
}
if(index[i] > index[j])
{
j = i;
}
}
}
//未发现合法的移动策略
if(j == array_size)
{
return 1;
}
t = index[j];//要交换位置的元素
i = j + move[j];//发生交换的位置
swap(index, i, j);
swap(move, i, j);
//将所有比t大的元素的移动方向反转
for(i = 0; i < array_size; ++i)
{
if(index[i] > t)
{
move[i] = -move[i];
}
}
return 0;
}
public static void arrayPrint(char[] array,int[] index){
int array_size = array.length;
for(int x:index){
System.out.print(array[x]);
}
System.out.println();
}
/*
* 基于最小变换的Steinhaus–Johnson–Trotter算法
*/
static void FullArray(char[] array)
{
int array_size = array.length;
int[] index = new int[array_size];
int[] move = new int[array_size];
for( int i = 0; i < array_size; ++i)
{
index[i] = i;
move[i] = -1;
}
arrayPrint(array, index);
while(SJTNext(index, move) == 0)
{
arrayPrint(array, index);
}
}
public static void main(String[] args) {
char[] charx = {'a','b','c','c'};
FullArray(charx);
}
}
相关文章推荐
- JAVA实现的Johnson-trotter算法(高效的全排列算法)
- JAVA 实现各种排序算法和复杂度分析1
- 千千静听 窗口自动粘合,java 代码实现 源码分析
- JAVA 实现各种排序算法和复杂度分析
- 常用排序算法分析与实现(Java版)
- Java加密算法的实现实例细节分析讲解
- JAVA 实现各种排序算法和复杂度分析1
- java 中的 wait 和 notify 实现的源码分析
- 数据结构Stack(堆)JAVA实现——数据结构算法分析(英文原版)
- 电子商务的安全分析、设计及JAVA实现
- 排序算法分析(JAVA实现)
- 算法设计、分析与实现 从入门到精通 C、C++和Java 这本书的堆实现85页C++语言实现有问题
- HttpUrlConnection底层实现和关于java host绑定ip即时生效的设置及分析
- Java实现聊天软件之一,Java山寨“糗糗”分析
- 电子商务的安全分析、设计及JAVA实现
- 冒泡排序、选择排序、插入排序、快速排序算法的时间性能分析(java实现)
- 利用JAVA的动态属性之反射原理实现一个简单AOP容器 - AOP的实现原理分析
- 分析JAVA、C#、C++的“覆盖”和“隐藏”与多态的实现
- 通过分析 JDK 源代码研究 TreeMap 红黑树算法实现 refer from http://www.ibm.com/developerworks/cn/java/j-lo-tree/index.html?ca=drs-
- JXTA Platform JAVA参考实现源代码分析系列文章(2)