在ArrayList中找到最接近的元素

时间:2014-02-26 14:29:02

标签: java binary-search

我有一个排序数组。给定一个键值(不一定在表中),我想找到表中关闭键值的元素。

我考虑使用二进制搜索,但如果键不在表中(不是-1),我需要返回最接近的元素。我该怎么做?

如果没有匹配项返回-1。这是我目前使用二进制搜索的尝试:

public static long binarySearch (ArrayList<Long> arr, int first, int last, long key)
{

    if (first > last) return -1;
    int mid = first + (last - first)/2;
    if (arr.get(mid) == key)
        return mid;
    else if (arr.get(mid) > key)
        return binarySearch(arr, first, mid - 1, key);
    else
        return binarySearch(arr, mid + 1, last, key);
}   

5 个答案:

答案 0 :(得分:1)

更改:

if (first > last) return -1;

if (first > last) {
   // if either first or last is negative, return the first element.
   // if either first or last are greater than arr length, return the last element.

   // otherwise, get values in the array for indecies first and last, compare then to 
   // your key and return the closest.

}

答案 1 :(得分:1)

尝试类似(未经测试)的内容:

public static Long getClosest(List<Long> sortedList, Long key) {
    int index = Collections.binarySearch(sortedList, key);
    Long closest;
    if (index >= 0) {
        closest = sortedList.get(index);
    } else {
        index = -index - 1;
        if (index == 0){
            closest = sortedList.get(index);
        } else if (index == sortedList.size()){
            closest = sortedList.get(index - 1);
        } else {
            Long prev = sortedList.get(index - 1);
            Long next = sortedList.get(index);
            closest = ((key - prev) < (next - key)) ? prev : next;
        }
    }
    return closest;
} 

如上所述,此代码未经测试,您可能需要检查它是否为所有极端情况返回正确的值。

答案 2 :(得分:0)

当中间位置的元素不等于键时,您可以将delta计算为abs(key-arr.get(mid))并检查它是否低于实际delta(最低delta,最接近的值''我有)。最后,如果在数组中找不到键,则返回delta而不是-1。

请注意,您不能将delta初始化为0,因为任何后来计算的delta都将大于0。

答案 3 :(得分:0)

这将解决问题,找到最接近的值,找到列表中接近索引的总和,例如{1,4,6,7,8,19}和密钥3.二进制搜索将最后的子集有1和4,

if(1 + 4> 3 + 3)?返回1否则返回4

    if (first > last)
    {
        // This makes an Invalid case
        return -1;
    }
    if (first == last)
    {
        // then get the valueOf(firstIndex)
        return arr.get(first-1);
    }
    if (first + 1 == last)
    {
        // gets value from the first Index
        int fistKey = arr.get(first-1);
        // gets value from first Index + 1 i.e next Index
        int nextKey = arr.get(first);
        // if valueof(firstIndex) + valueOf(nextIndex) > key then,
        // key will be closer to valueOf(firstIndex)
        // else key will be closer to valueOf(nextIndex)
        return ((fistKey + nextKey) > (key + key)) ? fistKey : nextKey;
    }
    else
    {
        // assuming List will start its index from 0, then "-1" used for mid calculation
        int mid = (last+1)/2;
        int keyFromList = arr.get(mid-1);
        if (keyFromList == key)
            return key;
        if (keyFromList > key)
            return binarySearch(arr, first, mid , key);
        else
            return binarySearch(arr, mid, last , key);
    } 

答案 4 :(得分:0)

幸运的是,Java标准库包含Arrays.binarySearch,如果元素未包含在元素中,它会为您提供元素的“插入点”:

  

返回:搜索键的索引(如果它包含在数组中);   否则,( - (插入点) - 1)。插入点定义为   密钥插入数组的点:   第一个元素的索引大于键,或者a.length如果全部   数组中的元素小于指定的键。注意   这保证了当且仅当时,返回值将> = 0   钥匙被发现。

有了这个,我们可以非常简洁地实现您的要求:

import java.util.Arrays;

public class ClosestValue
{
    static long closestValue(long[] sorted, long key)
    {
        if(sorted.length==1) {return sorted[0];}    // trivial case
        if(key<sorted[0]) {return sorted[0];} // lower boundary
        if(key>sorted[sorted.length-1]) {return sorted[sorted.length-1];} // upper boundary
        int pos = Arrays.binarySearch(sorted, key);
        if(pos>=0) {return sorted[pos];} // we found an exact match
        // we didn't find an exact match, now we have two candidates: insertion point and insertion point-1 (we excluded the trivial case before)
        // pos = -ip-1 | +ip -pos => ip = -pos-1
        int ip = -pos-1;
        long closest;
        if(sorted[ip]-key<key-sorted[ip-1]) {closest=sorted[ip];} // < can be <= if smaller value is preferred
        else                            {closest=sorted[ip-1];}
        return closest;
    }

    public static void main(String[] args)
    {
        System.out.println(closestValue(new long[] {1,4,6,7,8,19},3));
        System.out.println(closestValue(new long[] {1,2,4,5},3));
        System.out.println(closestValue(new long[] {1,2,4,5},7));
        System.out.println(closestValue(new long[] {1,2,4,5},-5));
    }
}