全排列集锦

/*
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;
}














  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值