1. 程式人生 > >c++ 排列和字典序全排列解析

c++ 排列和字典序全排列解析

    我們知道C++裡自帶的有全排列,對於在演算法或者acm之類的競賽可謂是非常的好用的一個函式。那麼在學習全排列和組合演算法之前我們先來看一下自帶的函式如何使用。

首先,對於全排列c++給出了兩個函式,next_permutation 和 prev_permutation 顧名思義,next_permutaion是指按字典序排列的下一個升序排列,而prev_permutation 則是指上一個。

std::next_permutation函式原型

template <class BidirectionalIterator>

bool next_permutation (BidirectionalIterator first, BidirectionalIterator last );

template <class BidirectionalIterator, class Compare>

bool next_permutation (BidirectionalIterator first,BidirectionalIterator last, Compare comp);

注:我們只需給出需要排序的陣列或者向量的開始和結尾的地址便可得到下一個排列。其中的要注意的是該函式是有返回值的,噹噹前排列存在以字典序順序更高的排列則返回true,如果不存在則返回false(表示此時已經是字典序)。

對陣列

next_permutation (a,a+5);

對向量:

next_permutation (v.begin() , v.end());

非字典序排列

這種方法比較簡單也比較好理解,但是缺點是輸出的時候不是字典序,這在很多的情況下並不適用。

思想:

對於一個數組為{1,2,3},要想得到全排列那麼必須滿足的是每一個元素都要放在第一個位置,即{1,*,*} {2,*,*}{3,*,*},那麼第一次遞迴我們就確定第一個位置的值。第二次可以的看成只有兩個元素的陣列,同樣以第一次遞迴的方法我們就確定了第二個位置的值,以此類推。

實現方法:

首先,我們需要一個變數m來記錄這是在計算第幾位的值,那麼每次從m遍歷到的n即為全排列剩下的值。這個演算法是採用深度優先的方法,即每次確定一個的值比如{1,2,3},第一次我們確定{1,*,*},第二次{1,2,*},第三次{1,2,3},第四次呢?

這裡就要用到交換,即先將2和3 交換,使得3在第二個位置,當第三個位置確定後,我們再將2和3調換回來,這樣就又恢復了原來的順序了。其實在一開始,確定每一位時都進行了交換隻不過自身與自身交換沒有區別而已。

#include <iostream>
using namespace std;
void swap(int &a ,int &b)
{
	int temp=a;
	a=b;
	b=temp;
}
void permutation(int arr[],int m,const int n)
{	
	if (m==n)
	{
		//輸出 
		for (int i =0;i<n;i++)cout<<arr[i]<<" ";
		cout<<endl;
	}
	 else
	 {
	 	for (int i =m;i<n;i++)
	 	{
	 		//先將當前位置元素分別與其他元素交換 
	 		swap(arr[i],arr[m]);
	 		//遞迴下一個位置 
	 		permutation(arr,m+1,n);
	 		//重複上面的交換,恢復原來的陣列順序 
	 		swap(arr[i],arr[m]);
	 	}
	 }
}
int main ()
{
	int  a[]={1,2,3};
	int b[3];
	bool flag[3];
	permutation (a,0,3);
	
	return 0;
} 

按升序輸出的全排列

下面的升序排列其實是按照上面的演算法改進來的。那麼首先要知道為什麼上面的演算法不是升序的。

上面的輸出後是

1 2 3

1 3 2

2 1 3

2 3 1

3 2 1

3 1 2

我們發現當以3為首元素的時候順序就不是字典序了,按照步驟執行一下便會發現,由於1和3交換後陣列的順序便變為3 2 1,那麼繼續執行就會出現先3 2 1 再 3 1 2 的現象。因此問題就是,當我們交換元素後,除了前面的交換的元素,後面的應該保持有序才能輸出的時候為字典序,即1和3交換後陣列的順序如果是3 1 2 則後面的輸出為字典序的。當然我們想到交換後對其排序或者依次往後移之類的操作,雖然能解決問題但是要花費大量的時間。

因此,我們可以開多一個輔助陣列和一個記錄該元素是否已經在輔助數組裡的標記陣列。這樣每次左往右遍歷整個陣列,噹噹前元素未標記(即不在輔助陣列的時候)將其存入輔助數組裡,並將標記置為真。當遞迴後再將該標記改為假。

#include <iostream>
using namespace std;

void swap(int &a ,int &b)
{
	int temp=a;
	a=b;
	b=temp;
}
void permutation(int arr[],int b[],bool f[],int m,const int n)
{
	if (m==n)
	{
		for (int i =0;i<n;i++)cout<<b[i]<<" ";
		cout<<endl;
	}
	 else
	 {
	 	for (int i =0;i<n;i++)
	 	{
	 		if (f[i])continue;
	 		f[i]=true;
	 		b[m]=arr[i];
	 		permutation(arr,b,f,m+1,n);
	 		f[i]=false;
	 	}
	 }
}
int main ()
{
	int  a[]={1,2,3};
	int b[3];
	bool flag[3];
	permutation (a,b,flag,0,3);	
	return 0;
} 


相關推薦

c++ 排列字典排列解析

    我們知道C++裡自帶的有全排列,對於在演算法或者acm之類的競賽可謂是非常的好用的一個函式。那麼在學習全排列和組合演算法之前我們先來看一下自帶的函式如何使用。首先,對於全排列c++給出了兩個函式,next_permutation 和 prev_permutation

LeetCode31.下一個排列字典排列

實現獲取下一個排列的函式,演算法需要將給定數字序列重新排列成字典序中下一個更大的排列。 如果不存在下一個更大的排列,則將數字重新排列成最小的排列(即升序排列)。 必須原地修改,只允許使用額外常數空間。 以下是一些例子,輸入位於左側列,其相應輸出位於右側列。1,2,3 →&n

遞迴詳解(STL字典字典排列 )。

遞迴的定義就是函式本身呼叫自己,定義看起來很簡單,我感覺在具體問題中是很難實現的,首先這個思想也是很難懂的,具體的過程也是抽象的,對於ACM新手是很難搞懂的。 接下來,我就幾個例子來講一下我的見解。 在數學與電腦科學中,遞迴(Recursion)是指在函式的定義中使用函式自身的方法。實際上,

Lucky Numbers (easy)(模擬,字典排列

B. Lucky Numbers (easy) time limit per test 2 seconds memory limit per test 256 megabytes in

演算法學習——搜尋C++ STL 實現排列去重排列

全排列搜尋實現#include <iostream> #include <memory.h> using namespace std; int a[10001]; int b[1

STL之字典排列

#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm&

排列演算法(字典法、SJT Algorithm 、Heap's Algorithm)

一、字典序法 1) 從序列P的右端開始向左掃描,直至找到第一個比其右邊數字小的數字,即。 2) 從右邊找出所有比大的數中最小的數字,即。 3) 交換與。 4) 將右邊的序列翻轉,即可得到字典序的下一個排列。 5) 重複上面的步驟,直至得到字典序最大的排列,即左邊數字比右邊的

如何求先排列排列——hihocoder+洛谷例題【二叉樹遞歸搜索】

define second [] tor 記錄 例題 .com 內存限制 行為 【已知先序、中序求後序排列】: [#1049 : 後序遍歷](http://hihocoder.com/problemset/problem/1049) 時間限制:10000ms 單點時限:1

C語言版 輸出字串排列

問題:輸入一字串(要求不存在重複字元),打印出該字串中字元中字元的所有排列。  例如:輸入”abc”,輸出結果為abc, acb, bac, bca, cab和cba。 遇到這個問題,筆者搜了一下,網上有很多答案,但似乎沒有我想要的簡單一點的純C語言編寫的,所以自己動手寫了

字典排序排列--座標法

在前一篇文章中記錄了字典排序的全排列演算法,但是這有一個前提就是需要保證其中的元素是有序的,因此這篇文章記錄改進的字典有序全排列演算法,額外記錄其中元素的下標,保證下標有序。相當於對下標進行全排列,然後對於生成的座標序列取對應的元素值,構成一個元素序列。 P =    [9

排列字典問題Permrank題解

先附上n=4的時候的4*3!=24種情況 1 23 4     1 2 4 3     1 3 2 4    1 3 4 2     1 4 2 3     1 4 3 2 2 13 4     2 1 4 3     2 3 1 4    2 3 4 1     2 4

next_permutation的思想用法(排列函式)

#include<iostream> #include<algorithm> using namespace std; int main(){ int a[4]={1,2,3,4}; do{ cout<<a[0]<<"

排列字典問題

問題描述: n個元素{1,2,, n }有n!個不同的排列。將這n!個排列按字典序排列,並編號為0,1,…, n!-1。每個排列的編號為其字典序值。例如,當n=3時,6 個不同排列的字典序值如下:

C++用回溯方法做排列的代碼

sin als eof set return using ems result fin 學習閑暇時間,將內容過程經常用的一些內容記錄起來,下邊內容是關於C++用回溯方法做全排列的內容,應該能對各位有一些好處。 #include<cstring> #include

NOI2.2基本演算法之遞迴自呼叫函式 排列 分析----如何寫排列函式

一、題目描述 總時間限制: 1000ms 記憶體限制: 65536kB 描述給定一個由不同的小寫字母組成的字串,輸出這個字串的所有全排列。 我們假設對於小寫字母有'a' < 'b' < ... < 'y' < 'z',而且給定的字串中的字母已經按

第二章 遞迴與分治策略(排列字典問題)

一. 遞迴 1.概念 直接或間接地呼叫自身的演算法。用函式自身給出定義的函式稱為遞迴函式。 2.說明 (1)每個遞迴函式都必須有非遞迴定義的初始值,否則,遞迴函式就無法計算。 (2)遞迴式的主

演算法--排列,去重排列以及非遞迴實現

問題1: 給定字串1234無重複字元,求其所有排列 遞迴方式求解: def swap(num, i, j): tmp = num[i] num[i] = num[j] num[j] = tmp #num無重複數字 def fullSort(num, index)

P1691 有重複元素的排列問題 (模擬排列

題目描述 設R={r1,r2,……,rn}是要進行排列的n個元素。其中元素r1,r2,……,rn可能相同。使設計一個演算法,列出R的所有不同排列。 給定n以及待排列的n個元素。計算出這n個元素的所有不同排列。 輸入輸出格式 輸入格式: 第1行:元素個數n(1&l

C#】C#委託字典的結合使用

using System.Collections; using System.Collections.Generic; using UnityEngine; public class DelegateDic : MonoBehaviour { public de

C#委託字典的結合使用

目錄   例1: 例2: 例1: class Program { static void Main(string[] args) { Dictionary<char, Func<