使用可移动元素法(活动元素法)生成1~n的全排列(Java实现)

使用可移动元素法(活动元素法)生成1~n的全排列(Java实现)

全排列的概念

给定一个整数n,我们将1-n这n个数字进行任意序列的排列,如果使用穷举法,显然时间复杂度是O(n!),很不经济,在《组合数学》(Richard A.Brualdi)数中介绍了一种可移动元素法生成n个数的全排列的方法。这篇文章使用Java语言实现这种算法。

算法思想

首先使用数组存放初始序列,并为序列中的每个元素规定一个方向(左或者右),初始状态所有元素方向相同(本算法中初始化为左方向),我们定义可移动元素:如果一个元素k的箭头指向一个与其相邻但比它要小的元素,我们称这个k为可移动元素。算法步骤如下:

  • 1.初始化数组与其方向。
  • 2.当存在可移动元素时,执行如下循环:
    • 2.1找出最大的可移动元素m。
    • 2.2交换m和与其箭头所指的方向的相邻的元素。
    • 2.3改变当前数组中所有大于m的元素的箭头方向。
    • 2.4输出当前数组序列,为一个排列。
  • 3.退出循环,我们就得到了全排列。

代码

import java.util.Scanner;
public class N_Combination {
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		int n=sc.nextInt();
		Combination(n);
	}
	//生成n排列
	public static void Combination(int n) {
		int[] a=new int[n];//数组a存放1-n数字用来进行排列
		int[] b=new int[n];//数组b元素存放方向,约定0代表左方向,1代表右方向
		for(int i=0;i<n;i++) {
			a[i]=i+1;//初始化数组
			b[i]=0;//方向初始化全部向左
		}
		printArray(a);//先输出初始数组
		int max=Active(a, b);//找到当前序列中最大的活动元素
		int maxValue=max==-1?-1:a[max];
		while(max!=-1) {
			if(b[max]==0) {//活动元素向左,与左边元素交换
				swap(a,max,0);
				swap(b,max,0);
			}else if(b[max]==1) {//活动元素向右,与右边元素交换
				swap(a,max,1);
				swap(b,max,1);
			}
			
			for(int i=0;i<a.length;i++) {
				if(a[i]>maxValue) {
					//b[i]=(b[i]==1?0:1);//把所有值比maxValue大的数调换方向
					if(b[i]==0) {
						b[i]=1;
					}else {
						b[i]=0;
					}
				}
			}
			printArray(a);//输出当前排列
			max=Active(a, b);
			maxValue=max==-1?-1:a[max];
		}
	}
	public static int Active(int[] a,int[] b) {//返回最大活动元素下标,如果没有活动元素,返回-1
		int maxAc=-1;//存放当前最大活动元素
		int maxPointer=-1;//存放当前最大活动元素下标
		for(int i=0;i<a.length;i++) {
			if(b[i]==0&&i>=1) {
				if(a[i]>a[i-1]&&a[i]>maxAc) {
					maxAc=a[i];
					maxPointer=i;
				}
			}
			if(b[i]==1&&i<=a.length-2) {
				if(a[i]>a[i+1]&&a[i]>maxAc) {
					maxAc=a[i];
					maxPointer=i;
				}
			}
		}
		return maxPointer;
	}
	public static void printArray(int a[]) {//将数组输出
		StringBuffer sb=new StringBuffer();
		for(int i=0;i<a.length;i++) {
			sb.append(a[i]);
		}
		System.out.println(sb);
	}
	public static void swap(int a[],int pointer,int direction) {
		if(direction==0) {//和左边元素交换
			int temp=a[pointer];
			a[pointer]=a[pointer-1];
			a[pointer-1]=temp;
		}
		if(direction==1) {//和右边元素交换
			int temp=a[pointer];
			a[pointer]=a[pointer+1];
			a[pointer+1]=temp;
		}
	}
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值