/*
1、递归全排列
2、几种排列组合的算法
3、堆全排列
*/
//////////////////////////////////////////////////////////////////////////////
//递归全排列
#include <stdio.h>
int n = 0;
void swap(int *a, int *b)
{
int m;
m = *a;
*a = *b;
*b = m;
}
void perm(int list[], int k, int m)
{
int i;
if(k > m)
{
for(i = 0; i <= m; i++)
printf("%d ", list[i]);
printf("\n");
n++;
}
else
{
for(i = k; i <= m; i++)
{
swap(&list[k], &list[i]);
perm(list, k + 1, m);
swap(&list[k], &list[i]);
}
}
}
int main()
{
int list[] = {1, 2, 3, 4, 5};
perm(list, 0, 4);
printf("total:%d\n", n);
return 0;
}
//////////////////////////////////////////////////////////////////////////
//几种全排列算法
/*
* 几种排列组合的算法
*/
#include<stdio.h>
int a[20];
int n;
//打印数组
void showArray(int *a)
{
int i;
for(i=1;i<=n;i++)
printf("%d",a[i]);
printf("\n");
}
//翻转法
void overturn()
{
int i,temp,temp1,temp2,j;
int b[20];
for(i=1;i<=n;i++)
*(b+n-i+1)=*(a+i);
showArray(b);
for(i=1;i<=n;i++){
//判断第一个数是否为1
if(i==1 && b[i]!=i){
temp=b[i];
for(j=1;j<n;j++)
b[j]=b[j+1];
b[j]=temp;
showArray(b);
i=0;
continue;
}
//判断第二个数是否为1
if(i==2 && b[i]!=i){
temp1=b[i];
temp2=b[i-1];
for(j=1;j+2<=n;j++)
b[j]=b[j+2];
b[j]=temp1;
b[j+1]=temp2;
showArray(b);
i=0;
continue;
}
//判断第三个数是否为1
if(i==3 && b[i]!=i){
temp=b[i];
temp1=b[i-1];
temp2=b[i-2];
for(j=1;j+3<=n;j++)
b[j]=b[j+3];
b[j++]=temp;
b[j++]=temp1;
b[j]=temp2;
showArray(b);
i=0;
continue;
}
}
}
//换位法
void changeSite()
{
int i,temp,temp1;
int b[20],max=0;
int dir[20]={-1,-1,-1,-1,-1,-1};
for(i=1;i<=n;i++)
*(b+i)=*(a+i);
showArray(b);
while(1){
max=0;
b[max]=0;
//寻找最大的活结点
for(i=1;i<=n;i++){
if(i+dir[i]>0 && i+dir[i]<=n && b[i]>b[i+dir[i]])
max=b[i]>b[max]?i:max;
}
if(max==0)
break;
//交换位置和方向
temp=b[max];
b[max]=b[max+dir[max]];
b[max+dir[max]]=temp;
temp1=dir[max+dir[max]];
dir[max+dir[max]]=dir[max];
dir[max]=temp1;
//改变比活结点大的数的方向
for(i=1;i<=n;i++)
if(b[i]>temp)
dir[i]=-dir[i];
showArray(b);
}
}
//序数法(排出的序列为有序的)
//str:待排序的字符序列 n:首字符下标 len:字符串长度
void ordinal(char * str,int n,int len)
{
int i;
char temp;
if(n==len)
puts(str);
for(i=n;i<len;i++){
temp=str[i];
str[i]=str[n];
str[n]=temp;
ordinal(str,n+1,len);
temp=str[i];
str[i]=str[n];
str[n]=temp;
}
}
void main()
{
int i;
char str[20];
for(i=1;i<=4;i++)
a[i]=i;
a[0]=n=4;
printf("对1234这四个数进行全排列\n");
printf("翻转法:\n");
overturn();
printf("换位法:\n");
changeSite();
printf("序数法:\n");
for(i=0;i<n;i++)
str[i]=a[i+1]+'0';
str[i]=0;
ordinal(str,0,n);
}
//////////////////////////////////////////////////////////////////
//字典序法生成全排列
#include <iostream>
#include <string>
using namespace std;
/*
字典序法生成全排列
*/
string input;
void perm();
int main(){
input="abcde";//a--z,z最大,input初始值为序列中第一个串(否则先sort一下)
perm();
return 0;
}
void perm(){
cout<<input<<endl;
while(1){
int index=-1;
for(int i=input.size()-2;i>=0;i--) // 从最右开始,找到第一个比右边小的数字,赋值给index
{
if(input[i]<input[i+1]){
index=i;
break;
}
}
if(index==-1)break; // 所有排列遍历完,break while
char M='z'; // M为监视哨兼临时变量(for swap)
int C; // C为所找到数字的序号
for(i=index+1;i<=input.size()-1;i++){ // 再从最右开始,找到input[index]右边比input[index]大的数字
if(input[i]<=input[index])continue;
if(input[i]<=M){
C=i;
M=input[i];
}
}
input[C]=input[index];
input[index]=M; // 交换input[index]和input[C]
int len=input.size()-1-index;
for(i=1;i<=len/2;i++){ // 将index后面的部分倒置,比如7421,倒置为1247,只需要对称交换即可
char t=input[index+i];
input[index+i]=input[input.size()-i];
input[input.size()-i]=t;
}
cout<<input<<endl;
}
}
////////////////////////////////////////////////////////////////////
#include <iostream>
using namespace std;
int total = 0;
//交换函数
void swapArray(int &a,int &b)
{
int temp;
temp = a;
a = b;
b = temp;
}
//递归函数
void fullPermutation(int * fullArray,int start,int end,int number){
//这里,既可以是">=",也可以是">",,应该也可以是"=="
if(start>=end){
for(int i=0;i<number;i++){
cout<<fullArray[i];
}
cout<<endl;
total++;
}
else{
for(int i=start;i<=end;i++){
swapArray(fullArray[start],fullArray[i]);//交换
fullPermutation(fullArray,start+1,end,number);
swapArray(fullArray[start],fullArray[i]);//注意恢复原样
}
}
}
int main()
{
int number;//全排列的长度
cout<<"Number:"<<endl;
cin>>number;
int * fullArray = new int[number];//动态生成全排列的数组
//初始化
for (int i=0;i<number;i++)
{
fullArray[i] = i+1;
}
fullPermutation(fullArray,0,number-1,number);
cout<<"Total = "<<total;
return 0;
}
//////////////////////////////////////////////////////////////////////////////
//堆全排列
#include <stdio.h>
#define MAX 100
void process(char *c,int n)
{
int i = 0;
while (i < n)
{
printf("%c",c[i]);
i++;
}
printf("\n");
}
void perm(char *list,int n)
{
int k;
char tmp;
int i = n;
int count[MAX];
count[i - 1] = 1;
while (i > 2)
{
i--;
count[i - 1] = 1;
}
process(list,n);
do {
if(count[i - 1] < i)
{
if(i % 2 != 0)
k = 1;
else
k = count[i - 1];
tmp = list[k - 1];
list[k - 1] = list[i - 1];
list[i - 1] = tmp;
count[i - 1] += 1;
i = 2;
process(list,n);
}
else
{
count[i - 1] = 1;
i += 1;
}
}while (i <= n);
}
int main(void)
{
char c[] = {'a','b','c'};
perm(c,3);
return 0;
}
/////////////////////////////////////////////////////////////////////
//邻位对换法全排列
#include <iostream>
using namespace std;
void Print(int a[], int n)
{
int i;
for (i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
printf("\n");
return;
}
/*
函数名称:Move
函数功能:寻找最大可移数,可移数m,将m与其箭头所指的邻数互换位置,
并将所得新排列中所有比m大的数p的方向调整
输入变量:int a[]:存储了1,2,3,...,n共n个自然数的数组
bool p[]:存储了n个元素的指向的数组:向左为false,向右为true
int n:数组a[]的长度
输出变量:排列中存在最大可移数,则做了相关操作后返回真,否则直接返回假
*/
bool Move(int a[], bool p[], int n)
{
int max = 1;
int pos = -1;
for (int i=0; i<n; i++)
{
if (a[i] < max)
continue;
if ((p[i] && i < n-1 && a[i] > a[i+1]) || //指向右侧
(!p[i] && i > 0 && a[i] > a[i-1])) //指向左侧
{
max = a[i];
pos = i;
}
}
if (pos == -1) //都不能移动
return false;
//与其箭头所指的邻数互换位置
if (p[pos]) //指向右侧
{
int temp = a[pos]; a[pos] = a[pos+1]; a[pos+1] = temp;
bool flag = p[pos]; p[pos] = p[pos+1]; p[pos+1] = flag;
}
else //指向左侧
{
int temp = a[pos]; a[pos] = a[pos-1]; a[pos-1] = temp;
bool flag = p[pos]; p[pos] = p[pos-1]; p[pos-1] = flag;
}
//将所得排列中所有比max大的数p的方向调整
for (i=0; i<n; i++)
{
if (a[i] > max)
p[i] = !p[i];
}
return true;
}
/*
函数名称:Permutation
函数功能:排列邻位对换法:输出n个数的所有全排列
输入变量:int n:1,2,3,...,n共n个自然数
输出变量:无
*/
void Permutation(int n)
{
int *a = new int[n]; //用来存储n个自然数
bool *p = new bool[n]; //用来存储n个元素的指向:向左为false,向右为true
for (int i=0; i<n; i++) //存储全排列的元素值,并计算全排列的数量
{
a[i] = i + 1;
p[i] = false; //开始均指向左侧
}
do
{
Print(a, n); //输出第一个全排列
if (n == a[n-1])//若n在最右侧,将其逐次与左侧的元素交换,得到n - 1个新的排列
{
for (int i=n-1; i>0; i--)
{
int temp = a[i]; a[i] = a[i-1]; a[i-1] = temp;
bool flag = p[i]; p[i] = p[i-1]; p[i-1] = flag;
Print(a, n);
}
}
else //若n在最左侧,将其逐次与右侧的元素交换,得到n - 1个新的排列
{
for (int i=1; i<n; i++)
{
int temp = a[i]; a[i] = a[i-1]; a[i-1] = temp;
bool flag = p[i]; p[i] = p[i-1]; p[i-1] = flag;
Print(a, n);
}
}
} while (Move(a, p, n));
delete []a;
delete []p;
}
int main(void)
{
Permutation(3);
return 0;
}
////////////////////////////////////////////////////////////////////////////////
全排列集锦
最新推荐文章于 2025-08-09 18:46:25 发布