Что не так с моим кодом сортировки кучи в Java?

Я пытаюсь создать и отсортировать кучу, используя этот массив в Java. Я продолжаю получать исключение индекса массива за пределами границ в моей функции maxHeap. Код кажется мне понятным, поэтому я не уверен, откуда берется ошибка.

Кто-нибудь знает, что я делаю неправильно?

 public static void main(String[] args) {
    int[] array = { 5, 16, 10, 7, 43, 12, 75, 33, 47, 3, 2489, 591, 6639, 557, 84, 9054, 17, 8841, 99, 701, 21, 78, 9, 36, 839};
    heapSort(array3);
    System.out.println("Heap Sort:");
    printArray(array3);
}

public static void createHeap(int []A){
    int n = A.length-1;
    for(int i=n/2;i>=0;i--){
        maxheap(A,i);
    }
}

public static void maxheap(int[] A, int i){ 
    int n = A.length;
    int largest;
    int left=2*i;
    int right=2*i+1;
    if(left <= n && A[left] > A[i]){
        largest=left;
    }
    else{
        largest=i;
    }

    if(right <= n && A[right] > A[largest]){
        largest=right;
    }
    if(largest!=i){
        int temp=A[i];
        A[i]=A[largest];
        A[largest]=temp;
        maxheap(A, largest);
    }
}

public static void heapSort(int []A){
    createHeap(A);
    int n= A.length;
    for(int i=n;i>0;i--){
        int temp=A[0];
        A[0]=A[i];
        A[i]=temp;
        n=n-1;
        maxheap(A, 0);
    }
}


public static void printArray(int[] sortedArray) {

   for (int i = 0; i < sortedArray.length; i++) {
       System.out.print(sortedArray[i] + ", ");
   }
   System.out.println("");
}

person Sarah    schedule 03.04.2014    source источник
comment
Из какой строки исходит ошибка?   -  person Grammin    schedule 03.04.2014
comment
Пожалуйста, включите полную трассировку стека!   -  person The Guy with The Hat    schedule 03.04.2014
comment
Посмотрите на <= n и i=n.   -  person Bernhard Barker    schedule 03.04.2014
comment
Мое предположение было бы здесь, если (право ‹= n && A[право] › A[наибольшее]), если право = n, то A[право] выходит за пределы.   -  person pbible    schedule 03.04.2014


Ответы (2)


Вы объявляете int n три раза, первый раз как:

int n = A.length - 1;

in createHeap()

второй раз:

int n = A.length;

в maxHeap() и в третий раз:

int n = A.length;

in heapSort();

В maxHeap() right установлено на 25 и поэтому A[right] (A[25]) выходит за пределы

Вы можете исключить int n = A.length как из heapSort(), так и из maxHeap().

person WonderWorld    schedule 03.04.2014

Массивы в Java имеют нулевой индекс. Вы устанавливаете верхнюю границу цикла (n) равной A.length, а затем выполняете сравнение меньше или равно с ним, поэтому он всегда будет проверять наличие слишком большого количества элементов.

if(left <= n && A[left] > A[i]){

Должно быть

if(left < n && A[left] > A[i]){

А также

if(right <= n && A[right] > A[largest]){

Должно быть

if(right < n && A[right] > A[largest]){

Вы также выполняете хитрую операцию по инициализации right. createHeap() устанавливает i равным n/2 (что само по себе потенциально является ошибкой). Затем вы передаете это значение maxHeap в виде параметра i. Затем вы делаете это:

int right = 2*i+1;

Что здесь происходит, когда i равно 2?

Чтобы i было 2, A.length должно быть 5 или 6 (поскольку createHeap устанавливает n в A.length - 1, поэтому (5 - 1) / 2 = 4 равно (6 - 1) / 2). Когда это просачивается к maxheap, 2 * i + 1 приводит вас к 5, что выходит за пределы A (это может быть длина, но если это так, то 4 является самым высоким индексом, а не 5).

Итак, это ситуация, когда A.length = 5:

if(right <= n && A[right] > A[largest]) {
   ^ 5      ^ 5    ^ ArrayIndexOutOfBoundsException thrown here.

right <= n оценивается как true, потому что 5 действительно равно 5, поэтому A[right] оценивается и быстро терпит неудачу с вашим исключением. Простая проверка меньше чем для right < n предотвратит это, так как 5 не меньше 5, поэтому первое условие оценивается как false, тем самым гарантируя, что A[right] вообще не будет оцениваться.

Короче говоря, это не работает для массива нечетной длины.

Помните: свойство .length массива сообщает вам, сколько элементов этот массив может содержать, а не индекс последнего элемента.

person JonK    schedule 03.04.2014
comment
ваше объяснение не будет причиной исключения индекса за пределы в этом случае. Он выбрасывается в A[0] = A[i];. Из-за оператора &&, если left или i выходят за границы, он будет вычисляться как ложный и переходить к оператору else. - person WonderWorld; 04.04.2014
comment
Нет. Если бы A[left] был за пределами, он не оценивался бы как false, он выдавал бы ArrayIndexOutOfBoundsException. i не может быть за пределами, насколько я могу судить, так как createHeap() устанавливает его как n/2 перед передачей. right потенциально может быть за пределами из-за операции 2 * i + 1. Этот код никогда не достигнет A[0] = A[i] в heapSort, он умрет раньше, чем это произойдет. Если бы вы действительно запустили этот код, вы бы это заметили. - person JonK; 04.04.2014
comment
Попытайся. Я отладил это. Только когда условие будет (A[right] > A[largest] && right <= n), будет выдано исключение ArrayIndexOutOfBoundsException. Но не наоборот. Поскольку left и right могут иметь значения больше, чем A.lenght - person WonderWorld; 04.04.2014
comment
Я делал попытку. Я также отладил его, и код в этой строке дает сбой, потому что A[right] выходит за пределы, как я уже говорил. - person JonK; 04.04.2014
comment
Если я отлажу его и удалю int n = A.length в функции heapSort(), код запустится. Изменение, как вы говорите, не имеет значения. В какой-то момент условие даже равно 38 <= 24 && A[38] > A[19], и это не вызывает исключения. - person WonderWorld; 04.04.2014
comment
Итак, вы используете неправильный код. Вы изменили его по сравнению с тем, что опубликовал ОП, поэтому совершенно не имеет значения, что ваш не терпит неудачу таким же образом. Запустите код OP, вы увидите, где именно он терпит неудачу. - person JonK; 04.04.2014
comment
Как ты можешь говорить такое? Я скопировал и вставил код. И поскольку ОП принял мой ответ, я не знаю, почему вы продолжаете говорить, что я делаю это неправильно. - person WonderWorld; 04.04.2014
comment
Вы также заявили, что удалили int n = A.length, поэтому вы больше не используете опубликованный код. - person JonK; 04.04.2014
comment
Эта строка вызывает ошибку ArrayIndexOutOfBoundsException. Если я перейду на int n = A.length в функции maxheap(), она вызовет исключение, как вы говорите. - person WonderWorld; 04.04.2014
comment
Я вообще не критиковал ваш ответ - он действительно работает. Моя проблема заключалась в том, что ваш первоначальный комментарий предполагал, что доступ к индексу за пределами границ в условном выражении if будет оцениваться как false вместо создания исключения. Я думаю, мы оба можем согласиться с тем, что есть ряд проблем с исходным кодом, мы просто решили разные проблемы в наших ответах. - person JonK; 04.04.2014
comment
Вы правы в этом. Теперь я понимаю, почему это не так. Даже если второе условие должно вызвать исключение, оно не будет вызвано первым условием. Если первое условие истинно, то второе условие вернет либо истину, либо ложь, и не может вызвать исключение, поскольку n не может быть больше 24. Если первое условие ложно, то второе условие не будет оцениваться. , даже если это вызовет исключение. - person WonderWorld; 04.04.2014
comment
Моя ошибка, я закомментировал int n в maxHeap() и пропустил третье объявление n. Шагая по коду, он приводит к сбою там, где вы сказали, что он разбился. Но все же изменение <= на < не решение, это не то, что неправильно, left может быть меньше или равно 24. :) - person WonderWorld; 04.04.2014