📌  相关文章
📜  按排序(字典顺序)打印所有排列

📅  最后修改于: 2021-04-29 08:52:49             🧑  作者: Mango

给定一个字符串,按排序顺序输出它的所有排列。例如,如果输入字符串为“ ABC”,则输出应为“ ABC,ACB,BAC,BCA,CAB,CBA”。

在本文中我们已经讨论了打印所有排列的程序,但是在这里我们必须按升序打印排列。

以下是按词典顺序打印排列的步骤
1.以非降序对给定的字符串进行排序并打印。第一个排列始终是按非降序排序的字符串。
2.开始生成下一个更高的排列。进行操作,直到不可能再进行更高的排列。如果我们达到一个排列,其中所有字符都以非递增顺序排序,那么该排列就是最后的排列。

生成下一个更高排列的步骤:
1.取先前打印的排列,然后在其中找到最右边的字符,该字符小于下一个字符。让我们将此字符称为“第一个字符”。
2.现在找到“第一个字符”的上限。天花板是“第一个字符”右侧的最小字符,大于“第一个字符”。让我们将ceil字符称为“第二个字符”。
3.交换在以上两个步骤中找到的两个字符。
4.在“第一个字符”的原始索引之后对子字符串进行排序(以不降序排列)。

让我们考虑字符串“ ABCDEF”。假设先前打印的排列为“ DCFEBA”。排序后的下一个排列应为“ DEABCF”。让我们了解上述步骤以查找下一个排列。 “第一个字符”将是“ C”。 “第二个字符”将是“ E”。交换这两个之后,我们得到“ DEFCBA”。最后一步是在“第一个字符”的字符原始索引之后对子字符串进行排序。最后,我们得到“ DEABCF”。

以下是该算法的实现。

C++
// C++ Program to print all permutations
// of a string in sorted order.
#include 
using namespace std;
 
/* Following function is needed for library function qsort(). Refer
http://www.cplusplus.com/reference/clibrary/cstdlib/qsort/ */
int compare (const void *a, const void * b)
{ return ( *(char *)a - *(char *)b ); }
 
// A utility function two swap two characters a and b
void swap (char* a, char* b)
{
    char t = *a;
    *a = *b;
    *b = t;
}
 
// This function finds the index of the smallest character
// which is greater than 'first' and is present in str[l..h]
int findCeil (char str[], char first, int l, int h)
{
    // initialize index of ceiling element
    int ceilIndex = l;
 
    // Now iterate through rest of the elements and find
    // the smallest character greater than 'first'
    for (int i = l+1; i <= h; i++)
    if (str[i] > first && str[i] < str[ceilIndex])
            ceilIndex = i;
 
    return ceilIndex;
}
 
// Print all permutations of str in sorted order
void sortedPermutations ( char str[] )
{
    // Get size of string
    int size = strlen(str);
 
    // Sort the string in increasing order
    qsort( str, size, sizeof( str[0] ), compare );
 
    // Print permutations one by one
    bool isFinished = false;
    while ( ! isFinished )
    {
        // print this permutation
        cout << str << endl;
 
        // Find the rightmost character which is
        // smaller than its next character.
        // Let us call it 'first char'
        int i;
        for ( i = size - 2; i >= 0; --i )
        if (str[i] < str[i+1])
            break;
 
        // If there is no such character, all are
        // sorted in decreasing order, means we
        // just printed the last permutation and we are done.
        if ( i == -1 )
            isFinished = true;
        else
        {
            // Find the ceil of 'first char' in
            // right of first character.
            // Ceil of a character is the smallest
            // character greater than it
            int ceilIndex = findCeil( str, str[i], i + 1, size - 1 );
 
            // Swap first and second characters
            swap( &str[i], &str[ceilIndex] );
 
            // Sort the string on right of 'first char'
            qsort( str + i + 1, size - i - 1, sizeof(str[0]), compare );
        }
    }
}
 
// Driver program to test above function
int main()
{
    char str[] = "ABCD";
    sortedPermutations( str );
    return 0;
}
 
// This is code is contributed by rathbhupendra


C
// Program to print all permutations of a string in sorted order.
#include 
#include 
#include 
 
/* Following function is needed for library function qsort(). Refer
http://www.cplusplus.com/reference/clibrary/cstdlib/qsort/ */
int compare (const void *a, const void * b)
{ return ( *(char *)a - *(char *)b ); }
 
// A utility function two swap two characters a and b
void swap (char* a, char* b)
{
    char t = *a;
    *a = *b;
    *b = t;
}
 
// This function finds the index of the smallest character
// which is greater than 'first' and is present in str[l..h]
int findCeil (char str[], char first, int l, int h)
{
    // initialize index of ceiling element
    int ceilIndex = l;
 
    // Now iterate through rest of the elements and find
    // the smallest character greater than 'first'
    for (int i = l+1; i <= h; i++)
    if (str[i] > first && str[i] < str[ceilIndex])
            ceilIndex = i;
 
    return ceilIndex;
}
 
// Print all permutations of str in sorted order
void sortedPermutations ( char str[] )
{
    // Get size of string
    int size = strlen(str);
 
    // Sort the string in increasing order
    qsort( str, size, sizeof( str[0] ), compare );
 
    // Print permutations one by one
    bool isFinished = false;
    while ( ! isFinished )
    {
        // print this permutation
        printf ("%s \n", str);
 
        // Find the rightmost character which is smaller than its next
        // character. Let us call it 'first char'
        int i;
        for ( i = size - 2; i >= 0; --i )
        if (str[i] < str[i+1])
            break;
 
        // If there is no such character, all are sorted in decreasing order,
        // means we just printed the last permutation and we are done.
        if ( i == -1 )
            isFinished = true;
        else
        {
            // Find the ceil of 'first char' in right of first character.
            // Ceil of a character is the smallest character greater than it
            int ceilIndex = findCeil( str, str[i], i + 1, size - 1 );
 
            // Swap first and second characters
            swap( &str[i], &str[ceilIndex] );
 
            // Sort the string on right of 'first char'
            qsort( str + i + 1, size - i - 1, sizeof(str[0]), compare );
        }
    }
}
 
// Driver program to test above function
int main()
{
    char str[] = "ABCD";
    sortedPermutations( str );
    return 0;
}


C++
#include 
using namespace std;
 
// An optimized version that uses reverse instead of sort for
// finding the next permutation
 
// A utility function to reverse a string str[l..h]
void reverse(char str[], int l, int h)
{
    while (l < h)
    {
        swap(&str[l], &str[h]);
        l++;
        h--;
    }
}
 
// Print all permutations of str in sorted order
void sortedPermutations ( char str[] )
{
    // Get size of string
    int size = strlen(str);
 
    // Sort the string in increasing order
    qsort( str, size, sizeof( str[0] ), compare );
 
    // Print permutations one by one
    bool isFinished = false;
    while ( ! isFinished )
    {
        // print this permutation
        cout << str << endl;
 
        // Find the rightmost character which
        // is smaller than its next character.
        // Let us call it 'first char'
        int i;
        for ( i = size - 2; i >= 0; --i )
        if (str[i] < str[i+1])
            break;
 
        // If there is no such character, all
        // are sorted in decreasing order,
        // means we just printed the last
        // permutation and we are done.
        if ( i == -1 )
            isFinished = true;
        else
        {
            // Find the ceil of 'first char' in
            // right of first character.
            // Ceil of a character is the
            // smallest character greater than it
            int ceilIndex = findCeil( str, str[i], i + 1, size - 1 );
 
            // Swap first and second characters
            swap( &str[i], &str[ceilIndex] );
 
            // reverse the string on right of 'first char'
            reverse( str, i + 1, size - 1 );
        }
    }
}
 
// This code is contributed by rathbhupendra


C
// An optimized version that uses reverse instead of sort for
// finding the next permutation
 
// A utility function to reverse a string str[l..h]
void reverse(char str[], int l, int h)
{
   while (l < h)
   {
       swap(&str[l], &str[h]);
       l++;
       h--;
   }
}
 
// Print all permutations of str in sorted order
void sortedPermutations ( char str[] )
{
    // Get size of string
    int size = strlen(str);
 
    // Sort the string in increasing order
    qsort( str, size, sizeof( str[0] ), compare );
 
    // Print permutations one by one
    bool isFinished = false;
    while ( ! isFinished )
    {
        // print this permutation
        printf ("%s \n", str);
 
        // Find the rightmost character which is smaller than its next
        // character. Let us call it 'first char'
        int i;
        for ( i = size - 2; i >= 0; --i )
           if (str[i] < str[i+1])
              break;
 
        // If there is no such character, all are sorted in decreasing order,
        // means we just printed the last permutation and we are done.
        if ( i == -1 )
            isFinished = true;
        else
        {
            // Find the ceil of 'first char' in right of first character.
            // Ceil of a character is the smallest character greater than it
            int ceilIndex = findCeil( str, str[i], i + 1, size - 1 );
 
            // Swap first and second characters
            swap( &str[i], &str[ceilIndex] );
 
            // reverse the string on right of 'first char'
            reverse( str, i + 1, size - 1 );
        }
    }
}


Python3
# An optimized version that uses reverse
# instead of sort for finding the next
# permutation
 
# A utility function to reverse a
# string str[l..h]
def reverse(str, l, h):
     
    while (l < h) :
        str[l], str[h] = str[h], str[l]
        l += 1
        h -= 1
         
    return str
     
def findCeil(str, c, k, n):
     
    ans = -1
    val = c
     
    for i in range(k, n + 1):
        if str[i] > c and str[i] < val:
            val = str[i]
            ans = i
             
    return ans
             
# Print all permutations of str in sorted order
def sortedPermutations(str):
     
    # Get size of string
    size = len(str)
 
    # Sort the string in increasing order
    str = ''.join(sorted(str))
 
    # Print permutations one by one
    isFinished = False
     
    while (not isFinished):
         
        # Print this permutation
        print(str)
 
        # Find the rightmost character which
        # is smaller than its next character.
        # Let us call it 'first char' 
        for i in range(size - 2, -1, -1):
            if (str[i] < str[i + 1]):
                break
 
        # If there is no such character, all
        # are sorted in decreasing order,
        # means we just printed the last
        # permutation and we are done.
        if (i == -1):
            isFinished = True
        else:
             
            # Find the ceil of 'first char' in
            # right of first character.
            # Ceil of a character is the
            # smallest character greater than it
            ceilIndex = findCeil(str, str[i], i + 1,
                                           size - 1)
 
            # Swap first and second characters
            str[i], str[ceilIndex] =  str[ceilIndex], str[i]
 
            # Reverse the string on right of 'first char'
            str = reverse(str, i + 1, size - 1)
             
# This code is contributed by rohan07


输出:

ABCD
ABDC
....
....
DCAB
DCBA

上面程序的时间复杂度上限为O(n ^ 2 xn!)。我们可以优化上述算法的第4步,以找到下一个排列。可以对子数组进行反转,而不是对“第一个字符”之后的子数组进行排序,因为交换后得到的子数组始终以非递增的顺序进行排序。此优化使时间复杂度变为O(nxn!)。请参阅以下优化代码。

C++

#include 
using namespace std;
 
// An optimized version that uses reverse instead of sort for
// finding the next permutation
 
// A utility function to reverse a string str[l..h]
void reverse(char str[], int l, int h)
{
    while (l < h)
    {
        swap(&str[l], &str[h]);
        l++;
        h--;
    }
}
 
// Print all permutations of str in sorted order
void sortedPermutations ( char str[] )
{
    // Get size of string
    int size = strlen(str);
 
    // Sort the string in increasing order
    qsort( str, size, sizeof( str[0] ), compare );
 
    // Print permutations one by one
    bool isFinished = false;
    while ( ! isFinished )
    {
        // print this permutation
        cout << str << endl;
 
        // Find the rightmost character which
        // is smaller than its next character.
        // Let us call it 'first char'
        int i;
        for ( i = size - 2; i >= 0; --i )
        if (str[i] < str[i+1])
            break;
 
        // If there is no such character, all
        // are sorted in decreasing order,
        // means we just printed the last
        // permutation and we are done.
        if ( i == -1 )
            isFinished = true;
        else
        {
            // Find the ceil of 'first char' in
            // right of first character.
            // Ceil of a character is the
            // smallest character greater than it
            int ceilIndex = findCeil( str, str[i], i + 1, size - 1 );
 
            // Swap first and second characters
            swap( &str[i], &str[ceilIndex] );
 
            // reverse the string on right of 'first char'
            reverse( str, i + 1, size - 1 );
        }
    }
}
 
// This code is contributed by rathbhupendra

C

// An optimized version that uses reverse instead of sort for
// finding the next permutation
 
// A utility function to reverse a string str[l..h]
void reverse(char str[], int l, int h)
{
   while (l < h)
   {
       swap(&str[l], &str[h]);
       l++;
       h--;
   }
}
 
// Print all permutations of str in sorted order
void sortedPermutations ( char str[] )
{
    // Get size of string
    int size = strlen(str);
 
    // Sort the string in increasing order
    qsort( str, size, sizeof( str[0] ), compare );
 
    // Print permutations one by one
    bool isFinished = false;
    while ( ! isFinished )
    {
        // print this permutation
        printf ("%s \n", str);
 
        // Find the rightmost character which is smaller than its next
        // character. Let us call it 'first char'
        int i;
        for ( i = size - 2; i >= 0; --i )
           if (str[i] < str[i+1])
              break;
 
        // If there is no such character, all are sorted in decreasing order,
        // means we just printed the last permutation and we are done.
        if ( i == -1 )
            isFinished = true;
        else
        {
            // Find the ceil of 'first char' in right of first character.
            // Ceil of a character is the smallest character greater than it
            int ceilIndex = findCeil( str, str[i], i + 1, size - 1 );
 
            // Swap first and second characters
            swap( &str[i], &str[ceilIndex] );
 
            // reverse the string on right of 'first char'
            reverse( str, i + 1, size - 1 );
        }
    }
}

Python3

# An optimized version that uses reverse
# instead of sort for finding the next
# permutation
 
# A utility function to reverse a
# string str[l..h]
def reverse(str, l, h):
     
    while (l < h) :
        str[l], str[h] = str[h], str[l]
        l += 1
        h -= 1
         
    return str
     
def findCeil(str, c, k, n):
     
    ans = -1
    val = c
     
    for i in range(k, n + 1):
        if str[i] > c and str[i] < val:
            val = str[i]
            ans = i
             
    return ans
             
# Print all permutations of str in sorted order
def sortedPermutations(str):
     
    # Get size of string
    size = len(str)
 
    # Sort the string in increasing order
    str = ''.join(sorted(str))
 
    # Print permutations one by one
    isFinished = False
     
    while (not isFinished):
         
        # Print this permutation
        print(str)
 
        # Find the rightmost character which
        # is smaller than its next character.
        # Let us call it 'first char' 
        for i in range(size - 2, -1, -1):
            if (str[i] < str[i + 1]):
                break
 
        # If there is no such character, all
        # are sorted in decreasing order,
        # means we just printed the last
        # permutation and we are done.
        if (i == -1):
            isFinished = True
        else:
             
            # Find the ceil of 'first char' in
            # right of first character.
            # Ceil of a character is the
            # smallest character greater than it
            ceilIndex = findCeil(str, str[i], i + 1,
                                           size - 1)
 
            # Swap first and second characters
            str[i], str[ceilIndex] =  str[ceilIndex], str[i]
 
            # Reverse the string on right of 'first char'
            str = reverse(str, i + 1, size - 1)
             
# This code is contributed by rohan07