字典序全排列算法

来源:互联网 发布:君学书院 知乎 编辑:程序博客网 时间:2024/06/10 14:53

字典序全排列算法

原文链接

问题描述

算法的作用是将给定的一串符号以字典排序的规则列出这串符号的全排列,例如给定符号串“abc”其全排列共有六个符号串按字典序排列顺序为:abc->acb->bac->bca->cab->cba再例如数字123的字典序全排列为:123->132->213->231->312->321 ;其中“A->B”表示B是根据字典序紧跟在A后面的一个序列。

算法描述

本算法能一次求出每一个序列后面紧跟的序列,从字典序最小的序列(例如“abc”或“123”)出发依次求出全排列所有序列

  • 在当前的符号串中从末尾开始找出第一个升序对,比如:162543中从尾部开始(4,3)是非升序对,(5,4)是非升序对,而(2,5)是升序对,所以从末尾开始第一个升序对为(2,5)
  • 那么升序对(2,5)中的 “2”称为替换数,“2”在序列中的位置(此处位置为3)称为替换点
  • 在替换点之后的数中找到大于替换数的最小数,在 162543中替换点后有三个数5,4,3他们都大于替换数2,找出最小的一个就是3,
  • 然后将找到的最小的数和替换数相交换得到序列:163542
  • 然后将替换点之后的所有符号翻转,即将3542翻转得到162453即为162543在字典序下后面紧跟的符号串。
#include <iostream>#include <string>#include <algorithm>using namespace std;string input;string top;/* 全排列,输入input需是字典序最小的符号串,如123,如果不是则需要预处理后再调用次函数*/void perm(){    while(input < top){//判断是否已经找到最后一个串,如果是则结束循环        int index = input.size() - 1 - 1; //从到数第二个数开始寻找第一个升序对        while(input[index] >= input[index + 1])index--;        //在替换点只有寻找大于替换数的最小数,从index+1开始        int min_max = index + 1;        for(int i = min_max ; i <= input.size() - 1; i++){            if(input[i] > input[index] && input[i] <= input[min_max]) min_max = i;        }        //将寻找的最小数与替换数交换        char tmp = input[index];        input[index] = input[min_max];        input[min_max] = tmp;         //将替换点之后的符号串逆序        string rev = input.substr(index + 1);        reverse(rev.begin(), rev.end());        input.replace(index + 1, rev.size(), rev);        //输出该串        cout << input << endl;    }}int main(){    cin >> input;    cout << input << endl;    top.assign(input.rbegin(), input.rend()); //将输入逆转得到字典序最大的串,用于判断循环结束    perm();    return 0;}
Input:abc
Ouput:abcacbbacbcacabcba