Algorithm,permutation,next_permutation,算法,下一个排列

#include <iostream>
bool next_permutation(int *arr, int n)
{
    if (n == 1 || n == 0) return false;
    int i;
    for (i = n - 2; i >= 0; --i)
    {
        if (arr[i] < arr[i + 1]) break;
    }
    if (i == -1) return false;
    else
    {
        int j;
        for (j = n -1; ; --j)
        {
            if (arr[j] > arr[i]) break;
        }
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    int low = i + 1;
    int high = n - 1;
    for( ; low < high; ++low, --high)
    {
        int tmp = arr[low];
        arr[low] = arr[high];
        arr[high] = tmp;
    }
    return true;
}

int main()
{
    int arr[] = {1, 2, 3, 4, 5};
    while (1)
    {
        for (unsigned i = 0; i < sizeof(arr)/sizeof(*arr); ++i)
            std::cout << arr[i] << " ";
        std::cout << std::endl;
        if (!next_permutation(arr, sizeof(arr)/sizeof(*arr)))
                break;
    }
    return 0;
}

这个算法本质上是贪心的,由上一个字典序生成下一个字典序

贪心找后面可以变动的序列:

1. 从后到前,找第一正序对 使: arr[i] < arr[i + 1] > arr[i + 2] > arr[i + 3] > ...

 意味着只需要更改[i, n -1]的序列,可实现现有序列字典序的最小增长

 我们看到[i + 1, n - 1]序列已经达到最大值,这个序列中至少存在一个值 大于 arr[i] 

 注意 [0 , i - 1] 的数不能动,因为变动那些不可能是字典序的最小增长, 所以只能从后面选一个数arr[j],替换i位置,贪心选择最小的数

 在[i + 1, n - 1]中从后向前找到第一个大于 arr[i]的 arr[j], 令 arr[i] 与 arr[j] 交换. 

   交换后,i 位置数已经正确,[i + 1, n - 1],是排列的最大序, 对其逆序即可

:如

0  1  2  3  4  5  

4      1     3  <  7  > 6  > 5   > 2  index   i = 2  j  = 5

交换

4   1   5      7  > 6  > 3  > 2

逆序

4       1    5      2      3     6     7


原文地址:https://www.cnblogs.com/threef/p/3200507.html