0

我正在尝试做一个斐波那契堆,但我不明白为什么我在 consolidate 方法中出现“indexofboundsException”错误,我就像geek_for_geeks一样实现它,虽然它是用 C 语言编写的,但我是用 java 做的,它应该可以工作:(。

正如我所说,我正在尝试执行以消除斐波那契堆的最小值,插入成功,显示也成功,但是合并后,数组中出现错误:

float temp2 = (float) ((Math.log(nro_nodos)) / (Math.log(2)));
    int temp3 = (int)temp2;
    Nodo[] arr = new Nodo[temp3];
    for (int i = 0; i <= temp3; i++) 
        arr[i] = null;

IndexodboundsException 对我说,到目前为止,我已经按照 geekforgeeks 页面所说的那样实现了它,但也许它在 java 中找到了不同的事情要做,在 C 中它说:

int temp1; 
float temp2 = (log(no_of_nodes)) / (log(2)); 
int temp3 = temp2; 
struct node* arr[temp3]; 
for (int i = 0; i <= temp3; i++) 
    arr[i] = NULL; 

我的班级 Nodo 是:

package Fibonacci_Heap;

公共类 Nodo {

Nodo<T> parent;
Nodo<T> child;
Nodo<T> left;
Nodo<T> right;
T dato;
int degree = 0;
public Nodo(T dato){
    this.dato = dato;
}

和我的类 FH(斐波那契堆):

包 Fibonacci_Heap;公共类 FH {

int nro_nodos = 0;
Nodo<T> min = null;


void Fibonnaci_link(Nodo<T> ptr2, Nodo<T> ptr1) 
{ 
    (ptr2.left).right = ptr2.right; 
    ptr2.right.left = ptr2.left; 
    if (ptr1.right == ptr1) 
        min = ptr1; 
    ptr2.left = ptr2; 
    ptr2.right = ptr2; 
    ptr2.parent = ptr1; 
    if (ptr1.child == null) 
        ptr1.child = ptr2; 
    ptr2.right = ptr1.child; 
    ptr2.left = ptr1.child.left; 
    ((ptr1.child).left).right = ptr2; 
    (ptr1.child).left = ptr2; 
    if (ptr2.dato.compareTo(ptr1.child.dato) < 0) 
        ptr1.child = ptr2; 
    ptr1.degree++; 
} 



public void consolidar(){
    int temp1;
    float temp2 = (float) ((Math.log(nro_nodos)) / (Math.log(2)));
    int temp3 = (int)temp2;
    Nodo[] arr = new Nodo[temp3];
    for (int i = 0; i <= temp3; i++) 
        arr[i] = null;
    Nodo ptr1 = min;
    Nodo ptr2;
    Nodo ptr3;
    Nodo ptr4 = ptr1;
    do{
        ptr4 = ptr4.right; 
        temp1 = ptr1.degree; 
        while(arr[temp1] != null){
            ptr2 = arr[temp1];
            if(((Comparable) ptr1.dato).compareTo(ptr2.dato) > 0){
                ptr3 = ptr1; 
                ptr1 = ptr2; 
                ptr2 = ptr3;
            }
            if(ptr2 == min){
                min = ptr1;
            }
            Fibonnaci_link(ptr2, ptr1);
            if (ptr1.right == ptr1) 
                min = ptr1; 
            arr[temp1] = null; 
            temp1++;
        }
        arr[temp1] = ptr1; 
        ptr1 = ptr1.right;
        
    }while(ptr1 != min);
    min = null;
    for (int j = 0; j <= temp3; j++) { 
        if (arr[j] != null) { 
            arr[j].left = arr[j]; 
            arr[j].right = arr[j]; 
            if (min != null) { 
                (min.left).right = arr[j]; 
                arr[j].right = min; 
                arr[j].left = min.left; 
                min.left = arr[j]; 
                if (((Comparable) arr[j].dato).compareTo(min.dato) < 0 ) 
                    min = arr[j]; 
            } 
            else { 
                min = arr[j]; 
            } 
            if (min == null) 
                min = arr[j]; 
            else if (((Comparable) arr[j].dato).compareTo(min.dato) < 0) 
                min = arr[j]; 
        } 
    } 
}
void eliminar_min() 
{ 
    if (min == null) 
        throw new RuntimeException("el arbol esta vacio"); 
    else { 
        Nodo temp = min; 
        Nodo pntr; 
        pntr = temp; 
        Nodo x = null; 
        if (temp.child != null) { 
  
            x = temp.child; 
            do { 
                pntr = x.right; 
                (min.left).right = x; 
                x.right = min; 
                x.left = min.left; 
                min.left = x; 
                if (((Comparable) x.dato).compareTo(min.dato) < 0) 
                    min = x; 
                x.parent = null; 
                x = pntr; 
            } while (pntr != temp.child); 
        } 
        (temp.left).right = temp.right; 
        (temp.right).left = temp.left; 
        min = temp.right; 
        if (temp == temp.right && temp.child == null) 
            min = null; 
        else { 
            min = temp.right; 
            consolidar(); 
        } 
        nro_nodos--; 
    } 
} 
void display() 
{ 
    Nodo ptr = min; 
    if (ptr == null) 
        System.out.print("esta vacio");
    else { 
        System.out.println("los nodos raiz son: ");
        do { 
            System.out.print(ptr.dato); 
            ptr = ptr.right; 
            if (ptr != min) { 
                System.out.print("-->"); 
            } 
        } while (ptr != min && ptr.right != null); 
        System.out.println();
        System.out.print("El nuemro de nodos es "+nro_nodos+" nodos");
    } 
} 
public static void main(String[] args) {
    // TODO Auto-generated method stub
    FH<Integer> heap = new FH();
    heap.insercion(5);
    heap.insercion(2);
    heap.insercion(8);
    heap.display();
    heap.eliminar_min();
}

}

在此处输入图像描述

异常堆栈跟踪如下所示:

los nodos raiz son: 2-->5-->8 El nuemro de nodos es 3 nodosException in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1 at Fibonacci_Heap.FH.consolidar(FH.java:56) at Fibonacci_Heap.FH.eliminar_min(FH.java:138) at Fibonacci_Heap.FH.main(FH.java:173) 
4

1 回答 1

1

您在 Java 中重复的原始 C 代码中存在错误。具体来说,看看你改编的 Java 代码:

Nodo[] arr = new Nodo[temp3];
for (int i = 0; i <= temp3; i++) 
    arr[i] = null;

这将创建一个大小为 的数组temp3,其索引范围temp3 - 1分别为 0 到 。但是在下一个循环中,您将迭代到并包括 index temp3,它从数组的末尾走开。

鉴于您在上面共享的 C 代码,看起来 C 代码中也存在同样的错误。Java 和 C 之间的区别在于,与这些写入触发异常的 Java 相比, C 中的错误写入会导致未定义的行为并且可能会静默失败。

根据我对斐波那契堆的理解,我认为您应该分配一个大小在temp3 + 1此处的数组。这将解决您的索引问题。

这里的另一个问题:由于舍入错误,Math.log(nro_nodos) / Math.log(2)转换为整数,实际上可能不会给您 log 2 n。考虑使用Math.round此处来避免这种情况。

此外,一个无耻的自我插入:多年前,我编写了一个斐波那契堆的 Java 版本,它在执行合并步骤时使用了稍微不同的策略。此外,有关合并如何工作的更多背景信息,请查看惰性二项式堆上的这些幻灯片,它提供了合并步骤的另一个视图。

希望这可以帮助!

于 2020-06-28T02:43:38.840 回答