全排列

原文出自:http://blog.csdn.net/morewindows/article/details/7370155/#cpp

全排列,如给定一个字符串: “123” 那么它的全排列形式为:123、132、213、231、321、312。

从全排列的结果看,213 和 321分别是123中的第一个字符1与第二个和第三个字符交换得到的结果。

而132、231、312则分别是123、213、321的后两个字符交换得到的。

由此可见一个完整的全排列则是从字符串的第一个字符开始分别与其后边的字符交换得到的。

/*************************************************************************
    > File Name: permutation.c
    > Created Time: 2014年06月17日 星期二 23时22分34秒
 ************************************************************************/

//全排列
#include<stdio.h>
#include<string.h>
int count = 1;
//借助指针交换两个数据
void swap(char *a, char *b)
{
    char tem = *b;
    *b = *a;
    *a = tem;
}
//全排列递归实现
void permutation(char *str,int k,int n)
{
    if(k == n-1)
    {
        printf("第%d个全排列:%s
",count++,str);
        return;
    }
    int i;
    for(i = k; i < n; i++)
    {
        swap(str+k,str+i);
        permutation(str,k+1,n);
        swap(str+i,str+k);
    }
}

int main()
{
    char str[100];
    printf("请输入一个字符串:
");
    scanf("%s",str);
    int len = strlen(str);
    permutation(str,0,len);
    return 0;
}

以上得到的结果不能处理出现重复数字的全排列,如果一个字符串中出现重复字符如 122,

那么他的全排列形式为 122、212、221.

依然根据上边得出的结论,从第一个字符开始与后边的字符交换,那么如果遇到重复的字符就不交换。

/*************************************************************************
    > File Name: permutation.c
    > Created Time: 2014年06月17日 星期二 23时22分34秒
 ************************************************************************/

//全排列
#include<stdio.h>
#include<string.h>
int count = 1;
//借助指针交换两个数据
void swap(char *a, char *b)
{
    char tem = *b;
    *b = *a;
    *a = tem;
}

//检查是否交换
bool checkSwap(char *str,int s,int e)
{
    for(int i = s; i < e; i++)
    {
        if(*(str+i) == *(str+e))return false;
    }
    return true;
}

//全排列递归实现
void permutation(char *str,int k,int n)
{
    if(k == n-1)
    {
        printf("第%d个全排列:%s
",count++,str);
        return;
    }
    int i;
    for(i = k; i < n; i++)
    {
        if(checkSwap(str,k,i)){
            swap(str+k,str+i);
            permutation(str,k+1,n);
            swap(str+i,str+k);
        }
    }
}

int main()
{
    char str[100];
    printf("请输入一个字符串:
");
    scanf("%s",str);
    int len = strlen(str);
    //printf("%d",len);
    permutation(str,0,len);
    return 0;
}

 非递归的实现算法想法:一个字符串的所有排列方法都是界于其全排列的最大值和最小值之间。例如 abcd的全排列可定界于 [abcd,dcba]之间。  

1、首先要把字符串排序,从小到大的顺序排列。

2、在字符串上,按照从尾部开始反向扫描,当遇到第一组自增的相邻字符时把这一组相邻字符的前者作为标记点,从尾部重新扫描找到比标记点大的最小字符(这个字符必定存在至少是相邻字符的第二个);交换标记点和这个字符。

3、然后将标记点之后的字符串倒置。

4、重复1---3步骤,直到找不到递增数组为止。

/*************************************************************************
    > File Name: permutation.c
    > Created Time: 2014年06月17日 星期二 23时22分34秒
 ************************************************************************/

//全排列
#include<stdio.h>
#include<string.h>
int count = 1;

//借助指针交换两个数据
void swap(char *a, char *b)
{
    char tem = *b;
    *b = *a;
    *a = tem;
}

//排序,这里随便写了一个选择排序,正好复习下
void sort(char *str)
{
    int len = strlen(str);
    for(int i = 0; i < len; i ++)
    {
        for(int j = i; j < len; j++)
        {
            if(*(str+i) > *(str+j))
            {
                char tem = *(str+j);
                *(str+j) = *(str+i);
                *(str+i) = tem;
            }
        }
    }
}
//字符a b区间的字符串转置
void reverse(char *a,char *b)
{
    while(a < b)swap(a++,b--);
}

//全排列循环实现
bool next_permutation(char *str)
{
    int len = strlen(str);//字符串长度
    int index = len-1;
    while(index != -1)
    {
        if(*(str+index-1) < *(str+index))
        {
            for(int i = len-1; i >= index; i--)
            {
                if(*(str+i) > *(str+index-1))
                {
                    swap(str+i,str+index-1);
                    reverse(str+index,str+len-1);
                    return true;
                }
            }
        }
        index--;
    }
    return false;
}

int main()
{
    char str[100];
    printf("请输入一个字符串:
");
    scanf("%s",str);
    sort(str);
    do{
        printf("第%d个全排列:%s
",count++,str);
    }while(next_permutation(str));
    return 0;
}
原文地址:https://www.cnblogs.com/newpanderking/p/3793768.html