全排列算法——Java實現

什麼是全排列

從n個不一樣元素中任取m(m≤n)個元素,按照必定的順序排列起來,叫作從n個不一樣元素中取出m個元素的一個排列。當m=n時全部的排列狀況叫全排列。java

時間複雜度

n個數(字符、對象)的全排列一共有n!種,因此全排列算法至少時間O(n!)的。若是要對全排列進行輸出,那麼輸出的時間要O(n∗n!),由於每個排列都有n個數據。因此實際上,全排列算法對大型的數據是沒法處理的,而通常狀況下也不會要求咱們去遍歷一個大型數據的全排列。算法

算法的實現思想

首先,明確一點,本算法使用遞歸實現的,因此要求對遞歸有所瞭解。數組

當咱們要求一組字母的全排列,形如:函數

【A,B,C,D】this

你會怎麼作呢?我會這樣作:spa

第一步:將【A,B,C,D】將中的任意一個元素取出;.net

第二步:從剩下的三個元素中再任意取出一個元素;code

第三步:從剩下的兩個元素中再任意取出一個元素;對象

第四步:取出最後一個元素;blog

這樣就能夠獲得一個【A,B,C,D】排列了!效仿上面的四個步驟,只是不取重複的元素。就能夠獲得【A,B,C,D】因此的排列了嗎?

以此類推,【A】,【A,B】,【A,B,C】,【A,B,C,D,E】,【A,B,C,D,E,...】的全排列也能夠一一列出。

到目前爲止,細心的你應該能夠發現,【A】,【A,B】,【A,B,C】,【A,B,C,D】,【A,B,C,D,E】,【A,B,C,D,E,...】求全排列的方法都是同樣的,只是在元素有所差別。因此在寫算法時,咱們只要寫一個函數來求不一樣的全排列。

實現代碼

public class Main {

	public static void main(String[] args) {
		DataContainer data = new DataContainer(new Character[]{'a', 'b', 'c', 'd'});
		Stack<Object[]> res = new Stack<>();
		permu(data, res, new Stack<Object>());
		
		//打印
		for(Object[] objs: res){
			for(Object o: objs){
				System.out.print(o);
			}
			System.out.println();
		}
	}
	
	/**
	 * 求全排列的函數
	 * @param data 被排列的數組
	 * @param res 裝載一個排列
	 * @param objs 裝載全部排列
	 */
	static void permu(DataContainer data, Stack<Object[]> res, Stack<Object> objs) {
		if (data.effectSize == 0) {
			res.push(objs.toArray());
		}

		for (int i = 0; i < data.actualSize; i++) {
			if(data.state(i) == true){
				objs.add(data.getElement(i));
				permu(data, res, objs);
				
				//回溯
				data.recovery(i);
				objs.pop();
			}
		}
	}
}
/**
 * 
 * @author liutaigang
 *
 */
class DataContainer {
	Inner[] inners;
	int effectSize;// 有效元素的個數
	int actualSize;// 實際元素的個數

	DataContainer(Object[] data) {
		int len = data.length;
		this.actualSize = len;
		this.effectSize = len;
		inners = new Inner[len];
		for (int i = 0; i < len; i++) {
			inners[i] = new Inner(data[i], true);
		}
	}
	
	/**
	 * @param index 索引
	 * @return 返回inners中指定的有效值,若無效就返回null
	 */
	Object getElement(int index){
		if(inners[index].state == true){
			inners[index].state = false;//取過就無效了
			effectSize--;
			return inners[index].element;
		}
		return null;
	}
	
	boolean state(int index){
		return inners[index].state;
	}
	
	/**
	 * 將指定的元素恢復爲有效狀態
	 * @param index 索引
	 */
	void recovery(int index){
		if(inners[index].state == false){
			effectSize++; 
			inners[index].state = true;
		}
	}
	
	/**
	 * 內部類
	 * @author liutaigang
	 *	
	 */
	class Inner {
		Object element;// 元素
		boolean state;// 狀態:有效——true,無效——false

		Inner(Object element, boolean state) {
			this.element = element;
			this.state = state;
		}
	}
}

小小的拓展

固然,上述只是全排列的一種實現方法,甚至有些繁雜。僅僅是想爲你們提供一種思路。還有一些關於全排列的blog,很值得參考:

http://blog.csdn.net/summerxiachen/article/details/60579623

end

相關文章
相關標籤/搜索