简体   繁体   English

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

[英]Binary search on arrays/comparator using generics Java

I'm struggling to make a comparator for binary search work on an array of objects. 我在努力为对象数组的二进制搜索工作提供一个比较器。 Essentially the goal is to search a ragged array to find the first match of an item OR the closest match to provide an insert point. 本质上,目标是搜索一个参差不齐的数组以找到某项的第一个匹配项,或者找到最接近的匹配项以提供插入点。 The method passes in an generic (this is unchangeable - as this is homework) but you can't create arrays of generic types... so, my comparator is throwing an error: "The method binarySearch(Object[], Object) in type Arrays is not applicable for the arguments (Object[], E, Comparator)". 该方法传入一个泛型(这是不可更改的-因为这是家庭作业),但是您无法创建泛型类型的数组...因此,我的比较器抛出了一个错误:“方法binarySearch(Object [],Object)类型Arrays不适用于参数(Object [],E,Comparator)”。 Perhaps I need to cast the generic element "item"? 也许我需要转换通用元素“ item”? I'm not sure. 我不确定。 Code: 码:

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);

Secondary, but related question. 次要但相关的问题。 In the comparator, I am attempting to invoke the Comparable method "compareTo" to obtain a negative integer that gives an approximate location for where an item would be if it were in the array on a failed search, but again, I'm having trouble with generics, getting this error: "The method compareTo(E) is undefined for the type E". 在比较器中,我尝试调用Comparable方法“ compareTo”以获取一个负整数,该负整数给出一个项目在失败搜索中位于数组中时的大概位置,但是同样,我遇到了麻烦使用泛型时,出现此错误:“类型E的方法compareTo(E)未定义”。 Code: 码:

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

I think you either need a Comparator<Object> or you need an array of E[] . 我认为您要么需要Comparator<Object>要么需要E[]的数组。 For the latter, I would suggest checking out these two articles: 对于后者,我建议您查看以下两篇文章:

Above reading is encouraged. 鼓励以上阅读。


Option 1: Array.newInstance() 选项1:Array.newInstance()

assumes item is never null 假设item永远不会为null

Based on what I've read in the aforementioned posts, if you know item will never be null , you could try something like this ... 根据我在上述文章中所读的内容,如果您知道item永远不会为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);

Option 2: Array.newInstance() 选项2:Array.newInstance()

requires Class parameter 需要Class参数

If you can't guarantee the item will never be null , and you can't provide any special handling for null values, you could force the Class<?> parameter to be passed in, as follows... 如果您不能保证该项永远不会为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);

Option 3: Object Comparator Wrapper 选项3:对象比较器包装

ugly, but it works 丑陋,但是行得通

Alternatively you can create a Comparator<Object> to wrap your existing Comparator<E> , as follows (I think it's a bit of a hack, but it works consistently for me) ... 或者,您可以创建一个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);

Hope this helps! 希望这可以帮助!

You have to pass Class<E> so you may instantiate an array of E . 您必须传递Class<E>以便可以实例化E的数组。 (As <E> is dropped at runtime, E is just Object.) (由于<E>在运行时被删除,E只是对象。)

Class<E> klazz;

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

You did not declare <E> . 您没有声明<E> You would have to define your CompareElement as follows: 您必须按如下方式定义CompareElement

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

Then declare it as follows: 然后声明如下:

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

Whereas ? ? should be the type you want to compare. 应该是您要比较的类型。

Where is your E declared? 您的E在哪里声明? It seems like some type parameter that is declared in some enclosing class that we can't see. 似乎在一些看不到的封闭类中声明了某种类型参数。 It seems that your CompareElement class is a comparator that compares elements based on their natural ordering (ie according to Comparable ). 看来您的CompareElement类是一个比较器,它根据元素的自然顺序(即,根据Comparable )比较元素。 If so, then E must have a bound that guarantees that it is able to compare to itself, <E extends Comparable<? super E>> 如果是这样,则E必须具有一个保证能够与自身进行比较的界限, <E extends Comparable<? super E>> <E extends Comparable<? super E>> . <E extends Comparable<? super E>> You can change that bound where E is declared, or, if you want to do it like other people have suggested, to have CompareElement be parameterized separately from the enclosing class, you would do this: 您可以更改声明E边界,或者,如果您想要像其他人所建议的那样进行CompareElement ,以使CompareElement与封闭类分开进行参数化,则可以这样做:

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

Your first error is because the version of binarySearch you're trying to use, the one with a comparator, has restrictions on the types of the arguments. 您的第一个错误是因为您要使用的binarySearch版本(带有比较器)对参数类型有限制。 It is declared like this: static <T> int binarySearch(T[] a, T key, Comparator<? super T> c) . 声明如下: static <T> int binarySearch(T[] a, T key, Comparator<? super T> c) So If you have a Comparator<E> , then you will need an E[] as first parameter, whereas you have an Object[] . 因此,如果您有Comparator<E> ,则需要一个E[]作为第一个参数,而您有一个Object[] You have to think of some way to make it E[] . 您必须想办法使它成为E[]

But actually for you you're trying to do you don't need to use a comparator at all. 但是实际上,您要尝试执行的操作根本不需要使用比较器。 There is a version of the binarySearch method that does not take a comparator, and it already compares elements using their natural ordering. 有一个binarySearch方法版本,该版本不使用比较器,它已经使用其自然顺序比较元素。

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

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