开发者

How to search for closest value in a lookup table?

开发者 https://www.devze.com 2022-12-31 13:54 出处:网络
I have a simple one dimmensional array of integer values that represent a physical set of part values I have to work with.I then calculate and ideal value mathematically.

I have a simple one dimmensional array of integer values that represent a physical set of part values I have to work with. I then calculate and ideal value mathematically.

How could I write an efficient search algorithm that will find the smallest abosulte difference from my ideal value in the array?

The array is 开发者_开发知识库predetermined and constant, so it can be sorted however I need.

Example Lookup array:

100, 152, 256, 282, 300

Searching for an ideal value of 125 would find 100 in the array, whereas 127 would find 152.

The actual lookup array will be about 250 items long and never change.


Once array is sorted, use binary search


This is very similar to a binary search except if it does not find the exact key, it would return a key would be very close to the provided key.

Logic is to search till exact key is found or till there exactly one key left between high key and the low while performing binary search.

Consider an array n[] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20}
if you search for the key: 2, then using below algorithm
Step 1: high=10, low=0, med=5
Step 2: high=5, low=0, med=2
Step 3: high=2, low=0, med=1 In this step the exact key is found. So it returns 1.

if you search for the key:3 (which is not present in the array), then using below algorithm
Step 1: high=10, low=0, med=5
Step 2: high=5, low=0, med=2
Step 3: high=2, low=0, med=1
Step 4: high=1, low=0, At this step high=low+1 i.e. no more element to search. So it returns med=1.

Hope this helps...

public static <T> int binarySearch(List<T> list, T key, Comparator<T> compare) {
                int low, high, med, c;
                T temp;
                high = list.size();
                low = 0;
                med = (high + low) / 2;

                while (high != low+1) {
                    temp = list.get(med);
                    c = compare.compare(temp, key);

                    if (c == 0) {
                        return med;
                    } else if (c < 0){
                        low = med;
                    }else{
                        high = med;
                    }

                    med = (high + low) / 2;
                }

                return med; 
            }

    /** ------------------------ Example -------------------- **/

    public static void main(String[] args) {
                List<Integer> nos = new ArrayList<Integer>();
                nos.addAll(Arrays.asList(new Integer[]{1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20}));

                search(nos, 2); // Output Search:2  Key:1   Value:2
                search(nos, 3); // Output Search:3  Key:1   Value:2

                search(nos, 10); // Output Search:10    Key:5   Value:10
                search(nos, 11); // Output Search:11    Key:5   Value:10
            }

    public static void search(List<Integer> nos, int search){
                int key = binarySearch(nos, search, new IntComparator());
                System.out.println("Search:"+search+"\tKey:"+key+"\tValue:"+nos.get(key));
            }

            public static class IntComparator implements Comparator<Integer>{
                @Override
                public int compare(Integer o1, Integer o2) {
                    return o1.compareTo(o2);
                }
            }


The binary search algorithm from Wikipedia is as below:

int binary_search(int A[], int key, int imin, int imax)
{
  // continue searching while [imin,imax] is not empty
  while (imax >= imin)
    {
      // calculate the midpoint for roughly equal partition
      int imid = midpoint(imin, imax);
      if(A[imid] == key)
        // key found at index imid
        return imid; 
      // determine which subarray to search
      else if (A[imid] < key)
        // change min index to search upper subarray
        imin = imid + 1;
      else         
        // change max index to search lower subarray
        imax = imid - 1;
    }
  // key was not found
  return KEY_NOT_FOUND;
}

The end condition in case a key is not found is that imax < imin.

In fact, this condition can locate the nearest match. The nearest match will lie between imax and imin (taking into account either might be outside the array bounds). Note again that imax < imin in the end case. Some solutions use abs to find the difference, but we know that A[imax] < key < A[imin] so:

if imax <= 0 return 0
if imin >= A.count - 1 return A.count - 1
if (key - A[imax]) < (A[imin] - key) return imax
return imin


Python, brute force on unsorted list (cause it's fun writing Python) O(n):

table = (100, 152, 256, 282, 300)
value = 125

lookup_dict = dict([(abs(value-x),x) for x in table])
closest_val = ldict[min(ldict.keys())]

And a proper implementation that uses binary search to find the value O(log_n):

import bisect
'''Returns the closest entry in the sorted list 'sorted' to 'value'
'''
def find_closest(sorted, value):
    if (value <= sorted[0]):
        return sorted[0]
    if (value >= sorted[-1]):
        return sorted[-1]
    insertpos = bisect.bisect(sorted, value)
    if (abs(sorted[insertpos-1] - value) <= abs(sorted[insertpos] - value)):
        return sorted[insertpos-1]
    else:
        return sorted[insertpos]


Java has a Arrays.binarySearch function. Given an array of [10, 20, 30] you would get these results:

Search for Result
10 0
20 1
30 2
7 -1
9 -1
11 -2
19 -2
21 -3
29 -3
43 -4

Sample code:

import java.util.Arrays;


public class Solution {
    public static void main(String[] args) {
        int[] array = new int[]{10, 20, 30};
        int[] keys = new int[]{10, 20, 30, 7, 9, 11, 19, 21, 29, 43};
        for (int key: keys) {
            System.out.println(Arrays.binarySearch(array, key));
        }
    }
}

Sample output:

1
2
-1
-1
-2
-2
-3
-3
-4

Basically the negative numbers provide 2 crucial information. Negative denotes that the exact match was not found but we can get a "close enough" match. The negative value indicates where the match is, -2 means: array[0] < key < array[1] and -3 means array[1] < key < array[2]. -1 means it is smaller than the minimum value in the array.

Example based on sample data on the initial question:

public class Solution {
    public static void main(String[] args) {
        int[] array = new int[]{100, 152, 256, 282, 300};
        int[] keys = new int[]{125, 127, 282, 4, 900, 126};
        for (int key : keys) {
            int index = Arrays.binarySearch(array, key);
            if (index >= 0) {
                System.out.println("Found " + key);
            } else {
                if (index == -1) {
                    //smaller than smallest in the array
                    System.out.println("Closest to " + key + " is " + array[0]);
                } else if (-index > array.length) {
                    //larger than the largest in the array
                    System.out.println("Closest to " + key + " is " + array[array.length - 1]);
                } else {
                    //in between
                    int before = array[0 - index - 2];
                    int after = array[0 - index - 1];
                    if (key - before < after - key) {
                        System.out.println("Closest to " + key + " is " + before);
                    } else if (key - before > after - key) {
                        System.out.println("Closest to " + key + " is " + after);
                    } else {
                        System.out.println("Same distance from " + key + " to " + before + " and " + after);
                    }
                }
            }
        }
    }
}

And the output:

Closest to 125 is 100
Closest to 127 is 152
Found 282
Closest to 4 is 100
Closest to 900 is 300
Same distance from 126 to 100 and 152


Just going through the array and computing abs(reference-array_value[i]) would take O(N). carry the index with the smallest difference.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号