查找给定字符串的所有可能排列

时间:2010-08-01 10:35:28

标签: c algorithm

这只是为了找出一个看起来非常有趣的问题。我试着考虑一下,但在有效的时候找不到解决这个问题的方法。可能是我的概念还在积累......反正问题如下......

想要找出给定字符串的所有可能的排列.......另外,如果这个问题可能存在任何可能的变化,请分享。

我在net上发现了一个使用递归的解决方案..但是这并不令人满意,因为它看起来有点错误。

该计划如下: -

void permute(char s[], int d)
{
   int i;

   if(d == strlen(s))
      printf("%s",s);

   else
   {
      for(i=d;i<strlen(s);i++)
      {
         swap(s[d],s[i]);
         permute(s,d+1);
         swap(s[d],s[i]);
      }
   }
}

如果这个程序看起来不错(当我运行它时会出错),那么请提供一个小例子来理解这一点,因为我还在开发递归概念..

任何其他有效的算法(如果存在)也可以讨论....

请说,这不是HW ........

感谢.............

2 个答案:

答案 0 :(得分:4)

代码看起来是正确的,尽管你只有算法的核心,而不是一个完整的程序。您必须提供缺失的位:标题,main函数和swap宏(您可以通过将其称为swap来使swap(s, d, i)成为函数。

要理解该算法,在printf("permute(%s, %d)", s, d)函数的开头添加一些跟踪输出(比如permute)并使用3或4个字符的字符串运行程序将是有益的。

基本原则是每次递归调用permute都会连续将每个剩余元素放在d位置;位于d的元素通过将其放在上述剩余元素所在的位置(即交换元素)来保存。对于每个展示位置,递归调用permute以在位置d之后生成所有所需的子字符串。所以顶级调用(d = 0)到permute连续尝试位置0中的所有元素,第二级调用(d = 1)尝试位置1中的所有元素,除了已经位于0位置的那个等等。下一个最深的调用(d = n - 1)在最后一个位置有一个元素可以尝试,最深的调用({{ 1}} = d)打印生成的排列。

核心算法需要Θ(n·n!)运行时间,这是最好的,因为它是输出的大小。然而,这种实现效率较低,因为它在每次迭代时重新计算n,运行时间为Θ(n²·n!);预先计算长度的简单修复将产生Θ(n·n!)。实现需要Θ(n)内存,这是最好的,因为这是输入的大小。

答案 1 :(得分:1)

有关递归的解释,请参阅Gilles回答。

您的代码存在一些问题。首先,很难在C中实现所需的swap函数,因为C缺少引用调用的概念。您可以尝试使用宏来执行此操作,但是您必须使用 exclusive-or 技巧来交换值,或者使用临时变量。

然后,在每个递归级别重复使用strlen会破坏程序的复杂性。正如您所说,这是在每个递归级别的每次迭代中完成的。由于您的字符串甚至更改(因为swap s),编译器甚至无法注意到它总是相同的。所以他无法优化任何东西。如果您像这样实现它,那么在字符串中搜索终止'\0'将主导所有其他指令。