The principle and use of STL algorithm next_permutation

Source:http://leonard1853.iteye.com/blog/1450085

1. Encountered next_permutation (permutation: the meaning of sequence)

I encountered a simple question on TC today (SRM531-Division Two-Level One), which is to find the smallest dictionary sequence of a given array that is not arranged in ascending order (Sequence of numbers A is lexicographically smaller than B if A contains a smaller number on the first position on which they differ).

The solution is very simple, that is, sort the array (ascending order), and then find the first interchangeable position from end to beginning (because there may be duplicate numbers).

Finally, look at other people's solutions. After sorting, use a function next_permutaion in STL to directly find the first sequence that is not in ascending order.

2. Implementation principle of next_permutation

I found this function in "STL Source Code Analysis", here is a brief description of the principle:

In STL, in addition to next_permutation, there is also a function prev_permutation, both of which are used to calculate permutations and combinations. The former is to find the next permutation and combination, and the latter is to find the previous permutation and combination. The so-called "next" and "previous", the book gives a simple example: for the sequence {a, b, c}, each element is smaller than the latter, according to the dictionary sequence, after fixing a, a is greater than bc Are all small, c is greater than b, its next sequence is {a, c, b}, and the previous sequence of {a, c, b} is {a, b, c}, the same can deduce all The six sequences are: {a, b, c}, {a, c, b}, {b, a, c}, {b, c, a}, {c, a, b}, {c, b , a}, where {a, b, c} has no previous element and {c, b, a} has no next element.

The function prototype of next_permutation is as follows:

template<class BidirectionalIterator>  
bool next_permutation(  
      BidirectionalIterator _First,   
      BidirectionalIterator _Last  
);  
template<class BidirectionalIterator, class BinaryPredicate>  
bool next_permutation(  
      BidirectionalIterator _First,   
      BidirectionalIterator _Last,  
      BinaryPredicate _Comp  
 );  

For the third parameter of the second overloaded function, the default comparison order is less than. If the next sequence is found, it returns true, otherwise it returns false.

The principle of function implementation is as follows:

In the current sequence, look for two adjacent elements from the tail to the front, the former is marked as i, the latter is marked as ii, and i < ii. Then look for another element j from the end . If i <*j is satisfied , the i-th element and the j-th element are swapped, and all the elements after the iith element (including ii) are sorted upside down, that is, to find The next sequence is up.

The code is implemented as follows:

template<class BidirectionalIterator>  
bool next_permutation(  
      BidirectionalIterator first,   
      BidirectionalIterator last  
)  
{
    
      
    if(first == last)  
        return false; //空序列  
  
    BidirectionalIterator i = first;  
    ++i;  
    if(i == last)  
        return false;  //一个元素,没有下一个序列了  
      
    i = last;  
    --i;  
  
    for(;;) {
    
      
        BidirectionalIterator ii = i;  
        --i;  
        if(*i < *ii) {
    
      
            BidirectionalIterator j = lase;  
            while(!(*i < *--j));  
  
            iter_swap(i, j);  
            reverse(ii, last);  
            return true;  
        }  
          
        if(i == first) {
    
      
            reverse(first, last);  //全逆向,即为最小字典序列,如cba变为abc  
            return false;  
        }  
    }  
  
}  

prev_permutation is similar to the realization of reverse lookup

3. Use next_permutation

Consider the question, what is the next sequence of the sequence {a, d, c, e, b}? Please use the previous analysis to derive the answer and verify it with the code.

Here I use arrays and vectors to represent sequences, and use next_permutation to get the next sequence (compilation environment: Dev-C++):

#include <cstdlib>  
#include <iostream>  
#include <algorithm>  
#include <vector>  
  
using namespace std;  
  
void TestArray()   
{
    
      
    char chs[] = {
    
    'a', 'd', 'c', 'e', 'b'};  
    int count = sizeof(chs)/sizeof(char);  
      
    next_permutation(chs+0, chs + count);  
      
    printf("TestArray:\n");  
    for(int i = 0; i < count; i++) {
    
      
            printf("%c\t", chs[i]);  
    }  
      
    printf("\n");  
}  
  
void TestVector()  
{
    
      
     char chs[] = {
    
    'a', 'd', 'c', 'e', 'b'};  
     int count = sizeof(chs)/sizeof(char);  
     vector<char> vChs(chs, chs + count);  
       
     next_permutation(vChs.begin(), vChs.end());  
       
     printf("TestVector:\n");  
     vector<char>::iterator itr;  
     for(itr = vChs.begin(); itr != vChs.end(); itr++) {
    
      
             printf("%c\t", *itr);  
     }  
     printf("\n");  
}  
  
int main(int argc, char *argv[])  
{
    
      
    TestArray();  
    printf("\n");  
    TestVector();  
      
    system("PAUSE");  
    return EXIT_SUCCESS;  
}  

4. Summary

It is very convenient to use next_permutation and prev_permutation to find permutations and combinations, but remember to include the header file #include.

Although the last permutation does not have the next permutation, using next_permutation will return false, but after using this method, the sequence will become the first of the dictionary sequence, for example, cba becomes abc. The same is true for prev_permutation.

Guess you like

Origin blog.csdn.net/weixin_43743711/article/details/115180065