【问题标题】:Field variable produces different result than local variable with recursion字段变量产生与具有递归的局部变量不同的结果
【发布时间】:2013-02-17 13:50:16
【问题描述】:

我遇到了这个非常奇怪的问题,我不知道为什么。

public class QuickSort
{
  private int pivLocation;
  private void quickSort(Integer[] input, int low, int high)
  {
    if(low < high)
    {
      this.pivLocation = partition(input, low, high);
      quickSort(input, low, pivLocation-1);
      quickSort(input, pivLocation+1, high);
      Inversions.comparisons += high - low;
    }
  }
}

private int partition(Integer[] input, int low, int high)
{

        int arrLength = high - low;

        if(arrLength%2 == 0){

            int pivot = input[low];
        }
        else
        {
            int pivot = 1;
        }
    int i = low+1;
    for(int j=low+1; j<= high; j++ )
    {

        if(input[j]< pivot)
        {

            swap(input, j, i);
            i++;
        }
    }
    swap(input, low, i-1);

    return i-1;


}

与编写完全相同的代码相比,这给出了不同的比较计数,但我没有使用字段变量,而是将 pivLocation 转换为局部变量。

int pivLocation = partition(input, low, high);

我不明白为什么。

【问题讨论】:

    标签: java variables global-variables


    【解决方案1】:

    使用类变量时,请考虑以下事项:

    pivLocation = partition(input,low,high);
    // pivLocation changes in this function (specifically to a lower value)
    quickSort(input, low, pivLocation-1);
    // pivLocation is now lower than expected
    quickSort(input, pivLocation+1, high);
    

    因此,第二个quickSort 使用可能包含已排序元素的索引来调用。因此,比较的次数将高于所需的次数。

    当你使用一个局部变量时,每个递归调用都有它自己的pivLocation 变量,所以你没有这个问题。

    【讨论】:

    • 然而,奇怪的是排序正确完成。只有比较是错误的。如果 pivLocation 不正确,排序也应该失败。不应该吗?
    • @idipous 从第一次递归调用,pivLocation 只能得到一个较小的值(简单分析一下就知道了)。这意味着您将为包含一些已排序数据的索引调用quickSort。因此排序应该是成功的。交换两个递归调用应该会导致排序失败。
    • 嗯,即使我交换递归调用,它也不会失败。它仍然正确排序。唯一错误的是比较。我理解它的方式是,正如您正确所说的 pivLocation 在第一个递归调用中发生了变化,但是因为当我调用第二个递归函数时它被 -1 更改了,所以我加了 1 并且由于我实现分区的方式它不会不同。
    • @idipous 我不明白为什么在交换调用时它会正确排序(至少不是从提供的代码中)。你是什​​么意思比较是错误的?
    • 我添加了分区代码。通过比较,我的意思是 Inversions.comparisons,它是快速排序完成的比较次数。当我使用局部变量而不是类字段时,我会得到预期的数字,否则会得到错误的数字。
    【解决方案2】:

    因为递归。每次调用方法时都会初始化局部变量。

    当你有:

    int var;
    void mymethod() {
       mymethod();
    }
    

    var 只初始化一次。

    void mymethod() {
       int var;
       mymethod();
    }
    

    var 在每次调用mymethod() 时都会被初始化(设置为零),因为变量范围在方法内是有限的。

    【讨论】:

      猜你喜欢
      • 2020-12-06
      • 1970-01-01
      • 2012-04-25
      • 2016-08-12
      • 2017-02-17
      • 1970-01-01
      • 1970-01-01
      • 2013-07-14
      • 1970-01-01
      相关资源
      最近更新 更多