字符串全排列

  1. 问题描述:输入一个字符串,输出该字符串所有可能的排列方式(全排列);

  2. 问题解析:

    字符串全排列问题算是一种找规律的问题,若果我们能找到生成第一个字符排列的方法,那么参考这个方法就可以依次生成其余的字符串排列,不过得强调一点,找到的这个方法必须得满足正确性、互异性和完整性,否则就不能称得上是全排列了。

    按照每个人的不同思维习惯,字符串全排列的生成方法应该是多样的,有的人喜欢从后往前生成新的排列,有的人偏爱于依次将单个字符插入不同位置来生成新的序列,博主将用下面这个例子阐述一下自己的思路。

    全排列讲解图片

    如上图所示,我们以 {a,b,c,d} 为例:

    • 从第一列开始,我们将“a”与自身和其它字符依次交换位置(绿色为交换位置的两个字符),生成第二列中的四个新的子串;

    • 到了第二列中,我们将第一位固定不动(橘黄色为固定不动的字符位),将剩下的三个字符视为新的字符串,新的字符串重复由第一列到第二列的操作。如“b”分别与“自身”、“c”、“d”进行位置交换,生成第三列;

    • 到了第三列,固定不动的位数加一,即前两位不动,剩下的两个字符视为新的字符串,重复之前的字符交换操作,生成第四列;

    • 到了第四列,固定不动的位数加一,前三位不再参与字符交换,剩下的一位字符再进行交换将毫无意义,排列结束;

    • 至此,{a,b,c,d} 生成全部的字符排列。

  3. 程序设计:

    有了好的思路,得想办法转化为可运行的程序化过程,如下:

    • 上述排序算法中,随着单个字符与其它字符的依次交换,会存在一些固定不动的点,这些点是不参与下一轮字符交换的,那么我们只需要将可操作的片段传入下一步;

    • 假设待排序字符串为“Str[n]”,初始可操作片段为整个字符串,我们将(0,n-1)传入下一步,并将第一个操作字符设置为指定交换字符;

    • 设传入的代码片段为(m,n-1),若指定交换字符为“n-1”,则将“m-1,n-1”传给自己,并将“m”设为指定交换字符(在这里,如果“m-1”小于“0”,则跳到最后一步);若指定交换字符不为“n-1”,将“m”与指定的交换字符进行位置交换,将新生成的代码片段传入下一步;

    • 设传入的代码片段为(m,n-1),若该可操作片段长度为“1”,即“m”与“n-1”同字符,输出“Str[n]”,并把(m-1,n-1)传回上一步,将“m-1”设为指定交换字符;若可操作片段长度大于“1”,则把(m+1,n-1)传回上一步,将“m+1”设为指定交换字符;

    • 至此,已生成字符串“Str[n]”的全部排列。

    这里,博主用的是一个回溯的思想,其实根据例题描述,那些交换字符生成的新的字符串在下一步中完全独立,因此可以考虑分治的设计思路,效率会更高。

  4. 代码展示:

#include <iostream>
using namespace std;

void CharSort(char *str, int start, int end)
{
    char data;
    int i;

    if (start == end)
    {
        for (i = 0; i < end; i++)
            cout << str[i];
        cout << endl;
    }
    else
    {
        for (i = start; i < end; i++)
        {
            data = str[start];
            str[start] = str[i];
            str[i] = data;

            CharSort(str, start + 1, end);

            data = str[start];
            str[start] = str[i];
            str[i] = data;
        }
    }
}

int main()
{
    char str[10];
    cin >> str;

    CharSort(str, 0, strlen(str));

    return 0;
}

5.运行结果

以abcd为例的运行结果展示

(注:第一行“abcd”为开始时的输入部分,从第二行开始为程序输出部分)

  • 8
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值