使用泛型Java在数组/比较器上进行二进制搜索

时间:2012-10-11 12:50:18

标签: java arrays generics search binary

我正在努力为一组对象制作二进制搜索工作的比较器。本质上,我们的目标是搜索一个参差不齐的数组,以找到项目的第一个匹配项或最接近的匹配项,以提供插入点。该方法传入一个泛型(这是不可更改的 - 因为这是作业)但你不能创建泛型类型的数组...所以,我的比较器抛出一个错误:“方法binarySearch(Object [],Object)in类型数组不适用于参数(Object [],E,Comparator)“。也许我需要投射通用元素“item”?我不确定。代码:

private Location findFirst(E item) {
    Location current;
    int closestMatchArray1;
    int closestMatchArray2;

Object[] firstItemInArray2 = new Object[numArrayInUse];
Object firstItem;

Comparator<E> comparator = new CompareElement();

for (int i - 0; i < numArrayInUse; i++) {
    firstItem = topArray[i];
    firstItemInArray2[i] = firstItem;
}

closestMatchArray1 = Arrays.binarySearch(firstItemInArray2, item, comparator);

中学,但相关问题。在比较器中,我试图调用Comparable方法“compareTo”来获得一个负整数,给出一个项目在失败搜索时在数组中的位置的大致位置,但同样,我遇到了麻烦使用泛型,得到此错误:“方法compareTo(E)未定义为类型E”。代码:

public class CompareElement implements Comparator<E> {
  public int compare(E firstItem, E secondItem) {
     return firstItem.compareTo(secondItem);
  }
}

4 个答案:

答案 0 :(得分:1)

我认为您需要Comparator<Object>或者您需要一个E[]数组。对于后者,我建议查看这两篇文章:

鼓励以上阅读。


选项1:Array.newInstance()

假设item永远不为null

根据我在上述帖子中所读到的内容,如果您知道项目永远不会是null,您可以尝试这样的事情......

@SuppressWarnings("unchecked")
private Location findFirst(E item) {
    Location current;
    int closestMatchArray1;
    int closestMatchArray2;

    // Object[] firstItemInArray2 = new Object[numArrayInUse];
    // Object firstItem;

    E[] firstItemInArray2 
            = (E[]) Array.newInstance(item.getClass(), numArrayInUse); 
    E firstItem;

    Comparator<E> comparator = new CompareElement();

    for (int i = 0; i < numArrayInUse; i++) {
        firstItem = (E) topArray[i];
        firstItemInArray2[i] = firstItem;
    }

    closestMatchArray1 = Arrays.binarySearch(firstItemInArray2, item, comparator);

选项2:Array.newInstance()

需要Class参数

如果您无法保证该项永远不会null,并且您无法对null值进行任何特殊处理,则可以强制通过Class<?>参数在,如下......

@SuppressWarnings("unchecked")
private Location findFirst(E item, Class<E> clazz) {
    Location current;
    int closestMatchArray1;
    int closestMatchArray2;

    // Object[] firstItemInArray2 = new Object[numArrayInUse];
    // Object firstItem;

    E[] firstItemInArray2 
            = (E[]) Array.newInstance(clazz, numArrayInUse); 
    E firstItem;

    Comparator<E> comparator = new CompareElement();

    for (int i = 0; i < numArrayInUse; i++) {
        firstItem = (E) topArray[i];
        firstItemInArray2[i] = firstItem;
    }

    closestMatchArray1 = Arrays.binarySearch(firstItemInArray2, item, comparator);

选项3:对象比较器包装器

丑陋,但它有效

或者你可以创建一个Comparator<Object>来包装现有的Comparator<E>,如下所示(我认为这有点像黑客,但它对我来说一直都有效)......

    private Location findFirst(E item) {
    Location current;
    int closestMatchArray1;
    int closestMatchArray2;

    Object[] firstItemInArray2 = new Object[numArrayInUse];
    Object firstItem;

    // Comparator<E> comparator = new CompareElement();
    Comparator<Object> comparator = new Comparator<Object>() {
        private final Comparator<E> delegate = new CompareElement();

        @Override
        @SuppressWarnings("unchecked")
        public int compare(Object o1, Object o2) {
            return delegate.compare((E) o1, (E) o2);
        }
    };

    for (int i = 0; i < numArrayInUse; i++) {
        firstItem = topArray[i];
        firstItemInArray2[i] = firstItem;
    }

    closestMatchArray1 = Arrays.binarySearch(firstItemInArray2, item, comparator);

希望这有帮助!

答案 1 :(得分:0)

您没有声明<E>。您必须按如下方式定义CompareElement

public class CompareElement<E extends Comparable> implements Comparator<E> {
    public int compare(E firstItem, E secondItem) {
        return firstItem.compareTo(secondItem);
    }
}

然后声明如下:

Comparator<?> comparator = new CompareElement<?>();

?应该是您要比较的类型。

答案 2 :(得分:0)

您的E在哪里宣布?看起来像某个类型参数在一些我们看不到的封闭类中声明。您的CompareElement类似乎是一个比较器,它根据元素的自然顺序(即根据Comparable)来比较元素。如果是这样,那么E必须有一个绑定,以保证它能够与自身进行比较,<E extends Comparable<? super E>>。您可以更改声明E的边界,或者,如果您想像其他人建议的那样更改,将CompareElement与封闭类分开参数化,您可以这样做:

public class CompareElement<E extends Comparable<? super E>> implements Comparator<E> {
  public int compare(E firstItem, E secondItem) {
     return firstItem.compareTo(secondItem);
  }
}

您的第一个错误是因为您尝试使用的binarySearch版本(带有比较器的版本)对参数类型有限制。声明如下:static <T> int binarySearch(T[] a, T key, Comparator<? super T> c)。因此,如果您有Comparator<E>,则需要E[]作为第一个参数,而您需要Object[]。你必须想出一些方法来E[]

但实际上对你来说,你要做的就是根本不需要使用比较器。有一个版本的binarySearch方法没有比较器,它已经使用它们的自然顺序比较了元素。

答案 3 :(得分:-1)

您必须传递Class<E>才能实例化E数组。 (在运行时删除<E>,E只是对象。)

Class<E> klazz;

E[] firstItemInArray2 = (E[])
        java.lang.reflect.Arrays.newInstance(klazz, numArraysInUse);