【问题标题】:How can I find all permutations of a string without using recursion?如何在不使用递归的情况下找到字符串的所有排列?
【发布时间】:2011-09-05 11:31:04
【问题描述】:

谁能帮我解决这个问题:这是一个查找任意长度字符串的所有排列的程序。需要相同的非递归形式。 (首选C语言实现)

using namespace std;

string swtch(string topermute, int x, int y)
{
  string newstring = topermute;
  newstring[x] = newstring[y];
  newstring[y] = topermute[x]; //avoids temp variable
  return newstring;
}

void permute(string topermute, int place)
{
  if(place == topermute.length() - 1)
  {
    cout<<topermute<<endl;
  }
  for(int nextchar = place; nextchar < topermute.length(); nextchar++)
  {
    permute(swtch(topermute, place, nextchar),place+1);
  }
}

int main(int argc, char* argv[])
{    
  if(argc!=2)    
  {
    cout<<"Proper input is 'permute string'";
    return 1;
  }
  permute(argv[1], 0);
  return 0;    
}

【问题讨论】:

  • 这不是一个“C”语言解决方案——你使用的是内置的字符串类型、cout、运算符重载......如果它是由 Stroustrup 自己编写的,那就再好不过了 C++ .
  • 你是对的。 [c] 标签被移除以保存一个编辑。
  • 我在暗示我想要这个 C++ 代码的 C 实现

标签: c++ algorithm recursion iteration


【解决方案1】:
#include <iostream>
#include <string>

using namespace std;

void permuteString(string& str, int i)
{
    for (int j = 0; j < i; j++) {
        swap(str[j], str[j+1]);
        cout << str << endl;
    }
}

int factorial(int n)
{
    if (n != 1) return n*factorial(n-1);
}

int main()
{
    string str;

    cout << "Enter string: ";
    cin >> str;

    cout << str.length() << endl;

    int fact = factorial(str.length());

    int a = fact/((str.length()-1));

    for (int i = 0; i < a; i++) {
        permuteString(str, (str.length()-1));
    }   
}

【讨论】:

  • 你应该更好地解释你的答案。不解释就发布代码是不行的。 OP 应该理解答案的含义。
【解决方案2】:

另一种方法是分配一个包含 n! 的数组! char 数组并以与手动相同的方式填充它们。

如果字符串是“abcd”,则将所有“a”字符放在第一个 n-1 的位置 0 中!数组,位置 1 用于下一个 n-1!数组等。然后将所有“b”字符放在第一个 n-2 的位置 1!数组等,前 n-3 个位置 2 中的所有“c”字符!数组等,以及前 n-4 个位置 3 中的所有“d”字符!数组等,在填充数组时,在每种情况下使用模数运算从位置 3 移动到位置 0。

不需要交换,您很早就知道是否有足够的内存来存储结果。

【讨论】:

    【解决方案3】:

    这解决了没有递归的问题。唯一的问题是,如果字符串中有重复的字符,它会产生重复的输出。

    #include<iostream.h>
    #include<conio.h>
    #include<stdio.h>
    #include<string.h>
    int factorial(int n)
    {
        int fact=1;
        for(int i=2;i<=n;i++)
            fact*=i;
        return fact;
    }
    char *str;
    void swap(int i,int j)
    {
        char temp=str[i];
        str[i]=str[j];
        str[j]=temp;
    }
    void main()
    {
        clrscr();
        int len,fact,count=1;
        cout<<"Enter the string:";
        gets(str);
        len=strlen(str);
        fact=factorial(len);
        for(int i=0;i<fact;i++)
        {
            int j=i%(len-1);
            swap(j,j+1);
            cout<<"\n"<<count++<<". ";
            for(int k=0;k<len;k++)
                cout<<str[k];
        }
        getch();
    }
    

    【讨论】:

    • 这是解决问题的一种有趣方法,但不幸的是,对于超过 12 个字符的字符串,它会失败,因为阶乘(len)会溢出。如果您愿意尝试,纠正此问题应该不会太难? (提示:分配一个与字符串长度相同的整数数组。)
    • 不是一个完整的问题解决方案,从 n!/2 到 n!这些值从 1 重复到 n!/2
    【解决方案4】:

    您是否尝试过使用 STL?有一种称为 next_permutation 的算法,它给定一个范围,将在每次后续调用中返回 true,直到遇到所有排列。不仅适用于字符串,还适用于任何“序列”类型。

    http://www.sgi.com/tech/stl/next_permutation.html

    【讨论】:

    • 我想你指的是这个:marknelson.us/2002/03/01/next-permutation
    • 是的,这是一个很好的页面,解释了它是如何使用的,只是为了让你知道算法中还有一个 std::prev_permutation 函数。
    【解决方案5】:

    基于堆栈的非递归等效代码:

    #include <iostream>
    #include <string>
    
    struct State
    {
        State (std::string topermute_, int place_, int nextchar_, State* next_ = 0)
            : topermute (topermute_)
            , place (place_)
            , nextchar (nextchar_)
            , next (next_)
        {
        }
    
        std::string topermute;
        int place;
        int nextchar;
    
        State* next;
    };
    
    std::string swtch (std::string topermute, int x, int y)
    {
        std::string newstring = topermute;
        newstring[x] = newstring[y];
        newstring[y] = topermute[x]; //avoids temp variable
    
        return newstring;
    }
    
    void permute (std::string topermute, int place = 0)
    {
        // Linked list stack.
        State* top = new State (topermute, place, place);
    
        while (top != 0)
        {
            State* pop = top;
            top = pop->next;
    
            if (pop->place == pop->topermute.length () - 1)
            {
                std::cout << pop->topermute << std::endl;
            }
    
            for (int i = pop->place; i < pop->topermute.length (); ++i)
            {
                top = new State (swtch (pop->topermute, pop->place, i), pop->place + 1, i, top);
            }
    
            delete pop;
        }
    }
    
    int main (int argc, char* argv[])
    {
        if (argc!=2)    
        {
            std::cout<<"Proper input is 'permute string'";
            return 1;
        }
        else
        {
            permute (argv[1]);
        }
    
        return 0;
    }
    

    我试图让它像 C 一样,并避免使用 c++ STL 容器和成员函数(不过为了简单起见,使用了构造函数)。

    请注意,排列是按与原始顺序相反的顺序生成的。

    我应该补充一点,以这种方式使用堆栈只是模拟递归。

    【讨论】:

      【解决方案6】:

      第一个建议 - 不要按值传递 std:string 参数。使用 const 引用

      string swtch(const string& topermute, int x, int y)
      void permute(const string & topermute, int place)
      

      它将为您节省大量不必要的复制。

      至于 C++ 解决方案,您在 algorithm 标头中有函数 std::next_permutationstd::prev_permutation。所以你可以写:

      int main(int argc, char* argv[])
      {    
        if(argc!=2)    
        {
          cout<<"Proper input is 'permute string'" << endl;
          return 1;
        }
        std::string copy = argv[1];
        // program argument and lexically greater permutations
        do
        {
          std::cout << copy << endl;
        } 
        while (std::next_permutation(copy.begin(), copy.end());
      
        // lexically smaller permutations of argument
        std::string copy = argv[1];
        while (std::prev_permutation(copy.begin(), copy.end())
        {
          std::cout << copy << endl;
        }
        return 0;    
      }
      

      至于 C 解决方案,您必须将变量类型从 std::string 更改为 char *(呃,您必须正确管理内存)。我认为类似的方法 - 编写函数

      int next_permutation(char * begin, char * end);
      int prev_permutation(char * begin, char * end);
      

      与 STL 函数具有相同的语义 - 可以。您可以找到std::next_permutation 的源代码,并附上说明here。我希望你能设法编写一个适用于 char * 的类似代码(顺便说一句,std::next_permutation 可以毫无问题地使用 char *,但你想要 C 解决方案)因为我懒得自己做:-)

      【讨论】:

        猜你喜欢
        • 2019-10-20
        • 2017-06-20
        • 2021-01-07
        • 2017-01-18
        • 2011-11-22
        • 2016-04-06
        • 2011-10-20
        • 1970-01-01
        相关资源
        最近更新 更多