简体   繁体   中英

java method to find nearest match to a given no. in unsorted array of integers

I wanted help regarding Java program to find out nearest match to any given integer in unsorted array of integers

Can I please have suggestions about:

* How to get start off with this?
* Should i first sort the array

Thanks All

If you only need to perform the search once , you can scan the array from start to finish, keeping track of the value that's nearest to the one you're seeking.

If you need to search in the same array repeatedly , you should pre-sort the array and then repeatedly use binary search.

If you cannot sort the array, or you are only doing this once, you can do.

public static int closest1(int find, int... values) {
    int closest = values[0];
    for(int i: values)
       if(Math.abs(closest - find) > Math.abs(i - find))
           closest = i;
    return closest;
}

This will return one closest value. If you are looking for a value equally between two values, you will get the first one.


An optimised version.

public static int closest2(int find, int... values) {
    int closest = values[0];
    int distance = Math.abs(closest - find);
    for(int i: values) {
       int distanceI = Math.abs(i - find);
       if(distance > distanceI) {
           closest = i;
           distance = distanceI;
       }
    }
    return closest;
}

A multi-thread version

public static int closest3(final int find, final int... values) {
    final int procs = Runtime.getRuntime().availableProcessors();
    ExecutorService es = Executors.newFixedThreadPool(procs);
    List<Future<Integer>> futures = new ArrayList<Future<Integer>>();
    final int blockSize = values.length / procs;
    for (int i = 0; i < procs; i++) {
        final int start = blockSize * i;
        final int end = Math.min(blockSize * (i + 1), values.length);
        futures.add(es.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int closest = values[start];
                int distance = Math.abs(closest - find);
                for (int i = start + 1; i < end; i++) {
                    int n = values[i];
                    int distanceI = Math.abs(n - find);
                    if (distance > distanceI) {
                        closest = i;
                        distance = distanceI;
                    }
                }
                return closest;
            }
        }));
    }
    es.shutdown();
    int[] values2 = new int[futures.size()];
    try {
        for (int i = 0; i < futures.size(); i++)
            values2[i] = futures.get(i).get();
        return closest2(find, values2);
    } catch (Exception e) {
        throw new AssertionError(e);
    }
}

running this test

Random rand = new Random();
int[] ints = new int[100 * 1000 * 1000];
for (int i = 0; i < ints.length; i++)
    ints[i] = rand.nextInt();

for (int i = 0; i < 5; i++) {
    long start1 = System.nanoTime();
    closest1(i, ints);
    long time1 = System.nanoTime() - start1;

    long start2 = System.nanoTime();
    closest2(i, ints);
    long time2 = System.nanoTime() - start2;

    long start3 = System.nanoTime();
    closest3(i, ints);
    long time3 = System.nanoTime() - start3;
    System.out.printf("closest1 took %,d ms, closest2 took %,d ms, closest3 took %,d ms %n", time1 / 1000 / 1000, time2 / 1000 / 1000, time3 / 1000 / 1000);
}

for 100 million values prints

closest1 took 623 ms, closest2 took 499 ms, closest3 took 181 ms 
closest1 took 645 ms, closest2 took 497 ms, closest3 took 145 ms 
closest1 took 625 ms, closest2 took 495 ms, closest3 took 134 ms 
closest1 took 626 ms, closest2 took 494 ms, closest3 took 134 ms 
closest1 took 627 ms, closest2 took 495 ms, closest3 took 134 ms 

Using the second approach saves 0.8 ms per million entries. The third approach is much faster for large arrays, but is likley to be slower for smaller ones.

/**
 * @return the index of the closest match to the given value
 */
int nearestMatch(int[] array, int value) {
    if (array.length == 0) {
        throw new IllegalArgumentException();
    }
    int nearestMatchIndex = 0;
    for (int i = 1; i < array.length; i++) {
        if ( Math.abs(value - array[nearestMatchIndex])
                > Math.abs(value - array[i]) ) {
            nearestMatchIndex = i;
        }
    }
    return nearestMatchIndex;
}

Yes, sort the array and then use Arrays.binarySearch(int[], int)

Returns:
index of the search key, if it is contained in the array; otherwise, (-(insertion point) - 1) . The insertion point is defined as the point at which the key would be inserted into the array: the index of the first element greater than the key, or a.length if all elements in the array are less than the specified key. Note that this guarantees that the return value will be >= 0 if and only if the key is found.

No, you don't need to pre-sort the array. Just run through it, recording the position and value of the current nearest match, updating it at each iteration if necessary. This takes O(n) time while sorting would take O(n lg n) (unless you do a counting sort, which is not always applicable).

Only if you want to do this operation repeatedly will sorting pay off.

Don't sort the array first since it will modify the original array.

Instead, loop through the array keeping track of the difference between the current array element and your given value (and the array element with the smallest difference so far). The complexity here is linear; you can't beat that with sorting.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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