如何证明递归算法的正确性?

时间:2013-03-12 12:23:30

标签: recursion correctness induction

private static void swap(char[] str, int i, int j){
  char tmp = str[i];
  str[i] = str[j];
  str[j] = tmp;
}

public static void permute(String str){
  permute(str.toCharArray(), 0, str.length());
}

private static void permute(char[] str, int low, int high){
  if(low == high){
    System.out.println(str);
  } else {
    for(int i = low; i < high; i++){
      swap(str, low, i);
      permute(str, low+1, high);
      swap(str, low, i);
    }
  }
}

我为字符串置换实现了一个递归方法。但我有一个问题:如何通过使用归纳来证明此代码的正确性?我真的不知道。

1 个答案:

答案 0 :(得分:0)

首先,您必须具体说明正确性的含义(即您要检查代码的规范;另请参阅https://stackoverflow.com/a/16630693/476803)。让我们假设正确性在这里意味着

  

permute的每个输出都是给定字符串的排列。

然后我们可以选择执行归纳的自然数。对于递归函数permute,我们可以选择lowhigh之间或其中某些组合。

在阅读实现时,很明显输出字符串的前缀是其元素不会改变的。此外,该前缀的长度在递归期间增加,因此剩余的后缀(其长度为high - low)减小。因此,让我们在high - low上进行归纳(假设low <= high,这是合情合理的,因为最初我们使用0表示低high的某些字符串的长度,以及递归在low == high)后立即停止。也就是说,我们展示

  

事实: permute(str, low, high)的每个输出都是high - low的最后str个字符的排列。

  • 基本案例:假设high - low = 0。然后该陈述是真实的,因为它必须保留最后0个字符(即,没有)。

  • 步骤案例:假设high - low = n + 1。此外,作为归纳假设(IH),我们可以假设该陈述适用于n。从high - low = n + 1开始,我们high - (low + 1) = n(因为high必须严格大于low才能保留high - low = n + 1。因此,通过IH,permute(str, low+1, high)的每个输出都是high - (low + 1)的最后str个字符的排列。

    现在我们必须要证明某些事情。即通过在permute(str, low+1, high)生成的输出中交换lowstr个字符,low个字符high之后的任何字符(最多low),我们会在high0之间生成字符排列。这一步(我在这里省略,因为我只是想证明你原则上如何使用归纳法)得出结论证明。

最后,通过lowstr.lengthhigh permute实例化上述事实,我们得到了非{}递归str是{{1}}的排列。

注意:以上证明仅显示每个输出 一个排列。但是,知道实际所有排列都会打印出来也可能会很有趣。