如何按排序顺序生成数组的所有排列?

Posted

技术标签:

【中文标题】如何按排序顺序生成数组的所有排列?【英文标题】:How to generate all permutations of an array in sorted order? 【发布时间】:2013-06-28 02:05:40 【问题描述】:

我有一个数组,用户可以插入一个字符串。

我有这个代码:

int main()
  char anagrama[13];
  cin >> anagrama;
  for(int j = 0; j < strlen(anagrama); j++)
    cout << anagrama[j];
    for(int k = 0; k < strlen(anagrama); k++)
      if(j != k)
        cout << anagrama[k];
    
    cout << endl;
  

问题是我需要按排序顺序对字符串的所有排列

例如,如果用户写:abc,则输出必须是:

abc
acb
bac
bca
cab
cba

我的代码没有显示所有排列,也没有排序

你能帮帮我吗?

我需要在没有实现功能的情况下进行实现。

我想用递归函数,但我不知道怎么做。

这是一个例子: http://www.disfrutalasmatematicas.com/combinatoria/combinaciones-permutaciones-calculadora.html 不重复和排序

【问题讨论】:

鉴于“没有实现功能”意味着功课,所以我不会给出完整的代码。是的,您可以使用递归。遍历字符串中的字符,每次都删除该字符,以便它可以在调用中将仍未使用的字符传递给自身。一个合理的函数签名是void f(std::vector&lt;std::string&gt;&amp; results, const std::string&amp; unused_chars, const std::string&amp; prefix_so_far = "")。如果f 发现unused_chars 为空,则可以将prefix_so_far 添加到results 组合与排列不同(您的示例)。在组合中,元素的顺序无关紧要,顺序在排列中很重要。 将所有组合推入向量,然后排序。 【参考方案1】:

在 C++ 中,您可以使用 std::next_permutation 逐一进行排列。在第一次调用std::next_permutation 之前,您需要按字母顺序对字符进行排序:

cin>>anagrama;
int len = strlen(anagrama);
sort(anagrama, anagrama+len);
do 
    cout << anagrama << endl;
 while (next_permutation(anagrama, anagrama+len));

这是demo on ideone。

如果您必须自己实现置换,您可以borrow the source code 或next_permutation,或者选择一种更简单的递归方式实现置换算法。

【讨论】:

不行,我需要实现置换,我不能使用函数 我打算递归地实现一个置换算法,但我有一些问题【参考方案2】:
#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

void permute(string select, string remain)
    if(remain == "")
        cout << select << endl;
        return;
    
    for(int i=0;remain[i];++i)
        string wk(remain);
        permute(select + remain[i], wk.erase(i, 1));
    


int main()
    string anagrama;
    cout << "input character set >";
    cin >> anagrama;
    sort(anagrama.begin(), anagrama.end());
    permute("", anagrama);


另一个版本

#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>

using namespace std;

void permute(string& list, int level, vector<string>& v)
    if(level == list.size())
        v.push_back(list);
        return;
    
    for(int i=level;list[i];++i)
        swap(list[level], list[i]);
        permute(list, level + 1, v);
        swap(list[level], list[i]);
    


int main()
    string anagrama;
    vector<string> v;
    cout << "input character set >";
    cin >> anagrama;
    permute(anagrama, 0, v);
    sort(v.begin(), v.end());
    copy(v.begin(), v.end(), ostream_iterator<string>(cout, "\n"));

【讨论】:

好的,但是什么是字符串(wk)。这个有什么作用? 我怎样才能对输出进行排序? @AlexanderOvalle wk(remain) 构造函数。保留复制到 wk。 但是我不明白,为什么每次循环都要声明wc? Why do I have to declare wc in each cycle? 删除选中的元素。【参考方案3】:

@alexander 该程序的输出完全符合您的要求:

HERE,是一个最简单的代码,用于生成给定数组的所有组合/排列,不包括一些特殊库(仅包括 iostream.hstring)并且不包括使用一些特殊的命名空间(仅使用 namespace std)。

void shuffle_string_algo( string ark )


//generating multi-dimentional array:

char** alpha = new char*[ark.length()];
for (int i = 0; i < ark.length(); i++)
    alpha[i] = new char[ark.length()];

//populating given string combinations over multi-dimentional array
for (int i = 0; i < ark.length(); i++)
    for (int j = 0; j < ark.length(); j++)
        for (int n = 0; n < ark.length(); n++)
            if( (j+n) <= 2 * (ark.length() -1) )
                if( i == j-n)
                    alpha[i][j] = ark[n];
                else if( (i-n)== j)
                    alpha[i][j] = ark[ ark.length() - n];

if(ark.length()>=2)

    for(int i=0; i<ark.length() ; i++)
    
        char* shuffle_this_also = new char(ark.length());
        int j=0;
        //storing first digit in golobal array ma
        ma[v] = alpha[i][j];

        //getting the remaning string
        for (; j < ark.length(); j++)
            if( (j+1)<ark.length())
                shuffle_this_also[j] = alpha[i][j+1];
            else
                break;
        shuffle_this_also[j]='\0';

        //converting to string
        string send_this(shuffle_this_also);

        //checking if further combinations exist or not
        if(send_this.length()>=2)
        
            //review the logic to get the working idea of v++ and v--
            v++;
            shuffle_string_algo( send_this);
            v--;
        
        else
        
            //if, further combinations are not possiable print these combinations 
            ma[v] = alpha[i][0];
            ma[++v] = alpha[i][1];
            ma[++v] = '\0';
            v=v-2;

            string disply(ma);
            cout<<++permutaioning<<":\t"<<disply<<endl;
        
    


主要

int main()

string a;
int ch;
do

    system("CLS");
    cout<<"PERMUNATING BY ARK's ALGORITH"<<endl;
    cout<<"Enter string: ";
    fflush(stdin);
    getline(cin, a);

    ma = new char[a.length()];

    shuffle_string_algo(a);

    cout<<"Do you want another Permutation?? (1/0): ";
    cin>>ch;
 while (ch!=0);

return 0;

希望!它可以帮助你!如果您对理解逻辑有疑问,请在下方评论,我会编辑。

【讨论】:

【参考方案4】:
/*Think of this as a tree. The depth of the tree is same as the length of string.
In this code, I am starting from root node " " with level -1. It has as many children as the characters in string. From there onwards, I am pushing all the string characters in stack.
Algo is like this:

1. Put root node in stack.
2. Loop till stack is empty
2.a If backtracking
2.a.1 loop from last of the string character to present depth or level and reconfigure datastruture.
2.b Enter the present char from stack into output char

2.c If this is leaf node, print output and continue with backtracking on.
2.d Else find all the neighbors or children of this node and put it them on stack. */



        class StringEnumerator
        
        char* m_string;
        int   m_length;
        int   m_nextItr;
        public:
        StringEnumerator(char* str, int length): m_string(new char[length + 1]), m_length(length)  , m_Complete(m_length, false)
        
        memcpy(m_string, str, length);
        m_string[length] = 0;
        
    StringEnumerator(const char* str, int length): m_string(new char[length + 1]), m_length(length)  , m_Complete(m_length, false)
    
        memcpy(m_string, str, length);
        m_string[length] = 0;
    
    ~StringEnumerator()
    
        delete []m_string;
    

    void Enumerate();
   ;


        const int MAX_STR_LEN = 1024;
        const int BEGIN_CHAR = 0;

        struct StackElem
          
      char Elem;
      int Level;
      StackElem(): Level(0), Elem(0)
      StackElem(char elem, int level): Elem(elem), Level(level)

        ;

        struct CharNode
        
      int Max;
      int Curr;
      int Itr;
      CharNode(int max = 0): Max(max), Curr(0), Itr(0)
      bool IsAvailable()return (Max > Curr);
      void Increase()
      
        if(Curr < Max)
            Curr++;
      
      void Decrease()
      
        if(Curr > 0)
            Curr--;
       
       void PrepareItr()
      
        Itr = Curr;
       
;




        void StringEnumerator::Enumerate()


    stack<StackElem> CStack;
    int count = 0;
    CStack.push(StackElem(BEGIN_CHAR,-1));
    char answerStr[MAX_STR_LEN];
    memset(answerStr, 0, MAX_STR_LEN);

    bool forwardPath = true;

    typedef std::map<char, CharNode> CharMap;

    typedef CharMap::iterator CharItr;
    typedef std::pair<char, CharNode> CharPair;

    CharMap mCharMap;
    CharItr itr;

    //Prepare Char Map
    for(int i = 0; i < m_length; i++)
    
        itr = mCharMap.find(m_string[i]);
        if(itr != mCharMap.end())
        
            itr->second.Max++;
        
        else
        
            mCharMap.insert(CharPair(m_string[i], CharNode(1)));
        
    


    while(CStack.size() > 0)
    
        StackElem elem = CStack.top();
        CStack.pop();

        if(elem.Level != -1)     // No root node
        
            int currl = m_length - 1;
            if(!forwardPath)
            
                while(currl >= elem.Level)
                
                    itr = mCharMap.find(answerStr[currl]);
                    if((itr != mCharMap.end()))
                    
                        itr->second.Decrease();
                    
                    currl--;
                

                forwardPath = true;
            

            answerStr[elem.Level] = elem.Elem;

            itr = mCharMap.find(elem.Elem);
            if((itr != mCharMap.end()))
            
                itr->second.Increase();
            
        

        //If leaf node
        if(elem.Level == (m_length - 1))
        
            count++;
            cout<<count<<endl;
            cout<<answerStr<<endl;
            forwardPath = false;
            continue;
        

        itr = mCharMap.begin();

        while(itr != mCharMap.end())
        
            itr->second.PrepareItr();
            itr++;
        


        //Find neighbors of this elem 
        for(int i = 0; i < m_length; i++)
        
            itr = mCharMap.find(m_string[i]);
            if(/*(itr != mCharMap.end()) &&*/ (itr->second.Itr < itr->second.Max))
            
                CStack.push(StackElem(m_string[i], elem.Level + 1));
                itr->second.Itr++;
            
        


    



【讨论】:

【参考方案5】:

我写了一个没有已经实现的功能,甚至是任何模板和容器。其实是先用C写的,后来转成C++了。

通俗易懂但效率低下,其输出就是你想要的,排序的。

#include <iostream>
#define N 4
using namespace std;

char ch[] = "abcd";

int func(int n) 
    int i,j;
    char temp;
    if(n==0) 
        for(j=N-1;j>=0;j--)
            cout<<ch[j];
        cout<<endl;
        return 0;
    
    for(i=0;i<n;i++)
        temp = ch[i];
        for(j=i+1;j<n;j++)
            ch[j-1] = ch[j];
        ch[n-1] = temp;
        //shift
        func(n-1);
        for(j=n-1;j>i;j--)
            ch[j] = ch[j-1];
        ch[i] = temp;
        //and shift back agian
    
    return 1;


int main(void)

    func(N);
    return 0;

【讨论】:

与标准库函数相比不太容易理解..【参考方案6】:

如果您有字符串的 std::vector,那么您可以按如下方式“置换”向量项。

C++14 代码

#include <iostream>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <boost/algorithm/string/join.hpp>
using namespace std;

int main() 
    // your code goes here
    std::vector<std::string> s;
    s.push_back("abc");
    s.push_back("def");
    s.push_back("ghi");

    std::sort(s.begin(), s.end());
    do
    
      std::cout << boost::algorithm::join(s,"_") << std::endl ;
     while(std::next_permutation(s.begin(), s.end())); 
    return 0;

输出

abc_def_ghi

abc_ghi_def

def_abc_ghi

def_ghi_abc

ghi_abc_def

ghi_def_abc

【讨论】:

以上是关于如何按排序顺序生成数组的所有排列?的主要内容,如果未能解决你的问题,请参考以下文章

UITableview 的名称部分按排序顺序排列

用单词和数字按字母顺序排列字符串

如何对EXCEL列进行指定顺序排列?

我如何测试使用硒在下拉菜单中按字母顺序对项目进行排序

php如何显示,排列指定文件夹中所有文件夹名

首先按字母顺序对对象数组进行排序,然后按数字排序