简体   繁体   English

调试HeapSort Java代码

[英]Debugging HeapSort Java Code

I have a test program to randomly generate data are randomly generated, and then pass them to the class constructor of class Sorter. 我有一个随机生成数据的测试程序是随机生成的,然后将它们传递给类Sorter的类构造函数。 Then Sorter will sort the data and pass it back through a method to the main function. 然后Sorter将对数据进行排序,并通过方法将其传递回main函数。 I have also implemented several other sorting method as the subclass of the Sorter class, and they work just fine. 我还实现了几个其他排序方法作为Sorter类的子类,它们工作得很好。 So I think there're no problems in my Sorter class. 所以我觉得我的Sorter课没有问题。 Below is the output of my test program when using heapsort. 以下是使用heapsort时我的测试程序的输出。

Data: 数据:

48 96 71 81 78 72 93 52 67 70 48 96 71 81 78 72 93 52 67 70

Sorted Data: 排序数据:

48 71 81 78 72 67 52 93 70 96 48 71 81 78 72 67 52 93 70 96

As you can see, data is not sorted after going through the following code. 如您所见,在完成以下代码后,数据不会被排序。 And below is the code. 以下是代码。

public class HeapSort extends Sorter{
    private int[] heap;
    private int size;

    public HeapSort(int[] data){
        super(data);
    }

    public void sort(){
        constructHeap();

        for(int i = size - 1; i >= 0; i--){
            numbers[i] = extractMax();
        }
    }

    public void constructHeap(){
        size = numbers.length;
        heap = new int[size];
        for(int j = 0; j < size; j++) heap[j] = numbers[j];

        for(int i = size/2 - 1; i >= 0; i--){
            fixHeap(i, heap[i]);
        }
    }

    public int extractMax(){
        int max = heap[0];
        fixHeap(0, heap[--size]);
        return max;
    }

    public void fixHeap(int pos, int key){
        if(left(pos) > size) heap[pos] = key; // if current position is leaf
        else{
            int largest = pos;
            int r = right(pos);
            int l = left(pos);
            if(r < size && heap[largest] < heap[r]) largest = r;
            if(l < size && heap[largest] < heap[l]) largest = l;

            if(largest == pos) heap[pos] = key;
            else{
                heap[pos] = heap[largest];
                fixHeap(largest, key);
            }
        }
    }

    public int left(int i){return 2*i+1;}

    public int right(int i){return 2*i+2;}
}

Edited: Below is the debugged code. 编辑:下面是调试代码。 Hopefully someone would find it useful. 希望有人会发现它很有用。

public class HeapSort extends Sorter{

  private int[] heap;
  private int size;

  public HeapSort(int[] data){
    super(data);
  }

  public void sort(){
    constructHeap();

    for(int i = size - 1; i >= 0; i--){
      numbers[i] = extractMax();
    }
  }

  public void constructHeap(){
    size = numbers.length;
    heap = new int[size];
    for(int j = 0; j < size; j++) heap[j] = numbers[j];

    for(int i = size/2 - 1; i >= 0; i--){
      fixHeap(i);
    }
  }

  public int extractMax(){
    int max = heap[0];
    heap[0] = heap[--size];
    fixHeap(0);
    return max;
  }

  public void fixHeap(int pos){
    if(left(pos) < size){               // if current position is not leaf
      int largest = pos;
      int r = right(pos);
      int l = left(pos);
      if(r < size && heap[largest] < heap[r]) largest = r;
      if(l < size && heap[largest] < heap[l]) largest = l;

      if(largest != pos){
        exchange(pos, largest);
        fixHeap(largest);
      }
    }
  }

  public int left(int i){return 2*i+1;}

  public int right(int i){return 2*i+2;}

  public void exchange(int a, int b){
    int temp = heap[a];
    heap[a] = heap[b];
    heap[b] = temp;
  }

}

I assume you have a debugger, and know how to use it. 我假设你有一个调试器,并知道如何使用它。

In my opinion, the best way to debug complex code is what I call "divide and conquer debugging". 在我看来,调试复杂代码的最佳方法是我称之为“分而治之的调试”。 Pseudocode: 伪代码:

void debug(Time beforeTheBug, Time afterTheBug) {
    do {
        Time pivot = between(beforeTheBug, afterTheBug);
        if (stateIsAsExceptedAt(pivot)) {
            afterTheBug = pivot;
        } else {
           beforetheBug = pivot;
        }
    } while (amountOfCodeExecutedBetween(beforeTheBug, afterTheBug) is not trivial);
}

In your case, my first check was the output. 在你的情况下,我的第一次检查是输出。 Indeed, it was not sorted, so the bug is in this class. 实际上,它没有排序,所以bug就在这个类中。

My next check was whether the heap invariant was satisfied after constructHeap. 我的下一个检查是在constructHeap之后是否满足堆不变量。 At that time, heap is [96, 48, 93, 81, 78, 72, 71, 52, 67, 70], so the heap invariant is not satisfied (48 is not greater than 78), and a bug occurs during construction of the heap. 那时, heap是[96,48,93,81,78,72,71,52,67,70],所以不满足堆不变量(48不大于78),并且在构造期间发生错误的堆。

Looking at constructHeap() reveals no useful break point, because the first loop is quite simpe, and very unlikely to be wrong, while the second loop (with its call to fixHeap) contains all the complexity. 看看constructHeap()显示没有有用的断点,因为第一个循环非常简单,并且不太可能出错,而第二个循环(调用fixHeap)包含所有复杂性。

The first iteration of the loop finds nothing to change, which is correct, as the subtree already satisfies the heap invariant. 循环的第一次迭代找不到任何改变,这是正确的,因为子树已经满足堆不变量。 Same for the second iteration. 第二次迭代也是如此。

The third iteration correctly identifies that the right child is greater than the root, and swaps the two. 第三次迭代正确识别出正确的子项大于根,并交换两者。

The forth iteration finds nothing to change, which is correct. 第四次迭代找不到任何改变,这是正确的。

So it is the very last iteration of the loop that contains the problem. 所以它是包含问题的循环的最后一次迭代。 Both children are greater than the parent. 两个孩子都比父母大。 fixHeap correctly moves the greater child into the root, and invokes itself recursively. fixHeap正确地将更大的子进入根目录,并以递归方式调用自身。 That invocation finds the heap invariant satisfied, and returns. 该调用发现堆不变满足并返回。 But the invariant is not satisfied after the return. 但回归后,不变量不满意。

So the problem is somewhere from detection of the heap invariant to the return. 所以问题是从检测堆不变量到返回的某个地方。 The detection checks: 检测检查:

        if (r < size && heap[largest] < heap[r])
            largest = r;
        if (l < size && heap[largest] < heap[l])
            largest = l;

where heap is [96, 96, 93, 81, 78, 72, 71, 52, 67, 70]. heap是[96,96,93,81,78,72,71,52,67,70]。 Yes, 96 is greater than 81 and 78. But actually, shouldn't heap[pos] == key ? 是的,96大于81和78.但实际上,不应该heap[pos] == key Ah, that's what the next statement does... 啊,这就是下一个声明所做的......

Put differently, we were checking the heap invariant before completing the previous update, and then finishing that update, which broke the invariant in this case ... 换句话说,我们在完成上一次更新之前检查堆不变量,然后完成更新,在这种情况下打破了不变量......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM