全排列算法學習

遞歸方式實現全排列:圖片資源來自於網絡(遞歸順序類似樹的後序遍歷)
在這裏插入圖片描述
代碼實現

	/*****************
	 * 將字符串的組成元素進行全排列 後輸出
	 * @param str 輸入的字符串
	 * @return 所有的全排序序列
	 */
    public ArrayList<String> Permutation(String str) {
    	//輸出的結果集
    	ArrayList<String> result=new ArrayList<>();
    	//非空判斷
    	if(str==null||str.length()==0)
    	{
    		return result;
    	}
    	//調用遞歸全排序算法
    	allRangeRecu(str.toCharArray(), 0, str.length()-1, result);
    	//字典序排序
		 Collections.sort(result);
		 //返回結果集
		 return result;
    }
    /*************
     * 對數組中的元素進行全排序 排序序列保存在ArrayList中
     * @param array 進行全排序的元素序列
     * @param start 序列開始位置
     * @param end 序列結束位置
     */
    private void allRangeRecu(char[] array,int start,int end,ArrayList<String> result)
    {
    	if(start==end)//如果只剩下一個元素 則固定此序列
    	{
    		String curOrder=String.valueOf(array);//保存當前的序列
    		if(!result.contains(curOrder))//去重 只有當前的字符串不存在結果集中時才添加
    		{
    			result.add(curOrder);
    		}
    	}
    	else 
    	{
    		for(int i=start;i<=end;i++)
        	{
        		char temp=array[i];
        		array[i]=array[start];
        		array[start]=temp;
        		
        		allRangeRecu(array, start+1, end, result);
        		
        		temp=array[i];
        		array[i]=array[start];
        		array[start]=temp;
        	}
		}
    }

非遞歸方式實現全排序
非遞歸求解的過程就是一個找序列的下一序列的過程
這對初始的序列有要求,需要滿足是按照升序或者降序排列的。
方法的基本流程爲:

  • 首先,將所有的元素進行排序(假設初始按照升序排列)。
  • 然後,當所有的元素沒有完全變成另一種排序方式時,執行循環。
  • 從數組尾節點位置向前尋找,找到相鄰兩個位置中前一位置元素小於後一元素的位置,記錄前一位置爲leftIndex。如果沒找到,則說明序列已經變成降序,查找序列完成。
  • 從leftIndex+1開始,向後尋找最後一個大於array[leftIndex]的值,記錄此位置爲rightIndex。
  • 交換兩個位置的元素
  • 將原數組從leftIndex+1位置開始,轉置後面的數組。
  • 將轉置後的結果添加到結果集中。重新開始循環。
    算法過程如圖:
    在這裏插入圖片描述
    最後爲什麼要進行轉置?
    爲了保證下一個排序是恰好比當前排列大的一個序列。每次兩個元素交換後,都會將一個較大的元素移到前面(leftIndex位置)去,而從leftIndex+1的位置向後是一個遞減的序列,因爲移動到前面去一個大的值,高位變大,低位要調整爲最小的(升序排列),才能保證當前的序列恰好比之前的序列大。
    代碼實現如下
/***********************
 * 使用非遞歸方式對字符串進行字典序排序
 * @param array 需要進行排序的數組
 * @param start 數組開始位置
 * @param end  數組結束位置
 * @param result 排序的結果集
 */
    public void allRange(char[] array,int start,int end,ArrayList<String> result)
    {
    	//將數組排序爲有序的
    	Arrays.sort(array);
    	result.add(String.valueOf(array));
    	//循環查找所有元素的下一元素
    	//這是一個從123到321的過程
    	while(true)
    	{
    		int leftIndex=end;//從尾部向前找第一個array[i-1]<array[i]的位置
    		while(leftIndex>=1&&array[leftIndex-1]>=array[leftIndex])
    		{
    			//從右邊數第一個小右側元素的下標加1
    			leftIndex--;
    		}
    		//序列已經變成降序排列時 退出循環
    		if(leftIndex==0)
    		{
    			break;
    		}
    		leftIndex--;
    		int rightIndex=leftIndex+1;//查找右側交換元素
    		//從查找到的左側元素的下一位開始 
    		//找到最後一位大於array[leftIndex]的位置
    		while(rightIndex<=end&&array[rightIndex]>array[leftIndex])
    		{
    			rightIndex++;
    		}
    		rightIndex--;
    		//交換兩位置的元素
    		char temp=array[leftIndex];
    		array[leftIndex]=array[rightIndex];
    		array[rightIndex]=temp;
    		//轉置出前綴之外的數組
    		reverseArray(array, leftIndex+1, end);
    		//結果添加到數組中
    		result.add(String.valueOf(array));
    	}
    }
    /****************
     * 轉置數組內指定區域內的元素
     * @param array 需要進行轉置的數組
     * @param start 需要進行轉置數組的開始位置
     * @param end 結束位置
     */
    private void reverseArray(char[] array,int start,int end)
    {
    	if(start>=end)
    	{
    		return;
    	}
    	while(start<end)
    	{
    		char temp=array[start];
    		array[start]=array[end];
    		array[end]=temp;
    		start++;
    		end--;
    	}
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章