数据结构和算法 十五、线性算法/二分查找/插值查找

一、线性查找(Linear Search)

        查找数据的最简单策略就是线性查找,它简单地遍历每个元素以寻找目标,访问每个数据点从而查找匹配项,找到匹配项后,返回结果,算法退出循环,否则,算法将继续查找,直到到达数据末尾。线性查找的明显缺点是,由于固有的穷举搜索,它非常慢。它的优点是不需要数据排好序。

1、线性查找示例

public <T extends Comparable<T>> int find(T[] array, T value) {
    for (int i = 0; i < array.length; i++) {
        if (array[i].compareTo(value) == 0) {
            return i;
        }
    }
    return -1;
}

@Test
void LinearSearch()
{
    // just generate data
    Random r = new Random();
    int size = 200;
    int maxElement = 100;
    Integer[] integers
            = Stream.generate(() -> r.nextInt(maxElement)).limit(size).toArray(Integer[]::new);

    // the element that should be found
    Integer shouldBeFound = integers[r.nextInt(size - 1)];

    int atIndex = find(integers, shouldBeFound);

    System.out.println(
            String.format(
                    "Should be found: %d. Found %d at index %d. An array length %d",
                    shouldBeFound, integers[atIndex], atIndex, size));
}

2、结合线程线性查找

package com.thealgorithms.searches;

import java.util.Scanner;

public class LinearSearchThread {
    public static void main(String[] args) {
        int[] list = new int[200];
        for (int j = 0; j < list.length; j++) {
            list[j] = (int) (Math.random() * 100);
        }
        for (int y : list) {
            System.out.print(y + " ");
        }
        System.out.println();
        System.out.print("Enter number to search for: ");
        Scanner in = new Scanner(System.in);
        int x = in.nextInt();
        Searcher t = new Searcher(list, 0, 50, x);
        Searcher t1 = new Searcher(list, 50, 100, x);
        Searcher t2 = new Searcher(list, 100, 150, x);
        Searcher t3 = new Searcher(list, 150, 200, x);
        t.start();
        t1.start();
        t2.start();
        t3.start();
        try {
            t.join();
            t1.join();
            t2.join();
            t3.join();
        } catch (InterruptedException e) {
        }
        boolean found = t.getResult() || t1.getResult() || t2.getResult() || t3.getResult();
        System.out.println("Found = " + found);
    }
}

class Searcher extends Thread {
    private final int[] arr;
    private final int left, right;
    private final int x;
    private boolean found;

    Searcher(int[] arr, int left, int right, int x) {
        this.arr = arr;
        this.left = left;
        this.right = right;
        this.x = x;
    }

    @Override
    public void run() {
        int k = left;
        found = false;
        while (k < right && !found) {
            if (arr[k++] == x) {
                found = true;
            }
        }
    }

    boolean getResult() {
        return found;
    }
}

二、二分查找(Binary Search)

        二分查找算法的前提条件是数据有序。算法反复地将当前列表分成两部分,跟踪最低和最高的两个索引,直到找到它要找的值为止。

        二分查找之所以如此命名,是因为在每次迭代中,算法都会将数据分成两部分。如果数据有N项,则它最多需要O(log N)步来完成迭代,这意味着算法的运行时间为O(log N)。

/**
 * @param array is an array where the element should be found
 * @param key is an element which should be found
 * @param <T> is any comparable type
 * @return index of the element
 */
public <T extends Comparable<T>> int find1(T[] array, T key) {
    return search(array, key, 0, array.length);
}

/**
 * This method implements the Generic Binary Search
 *
 * @param array The array to make the binary search
 * @param key The number you are looking for
 * @param left The lower bound
 * @param right The upper bound
 * @return the location of the key
 */
private <T extends Comparable<T>> int search(T array[], T key, int left, int right) {
    if (right < left) {
        return -1; // this means that the key not found
    }
    // find median
    int median = (left + right) >>> 1;
    int comp = key.compareTo(array[median]);

    if (comp == 0) {
        return median;
    } else if (comp < 0) {
        return search(array, key, left, median - 1);
    } else {
        return search(array, key, median + 1, right);
    }
}


@Test
    void binary_search()
    {
        // Just generate data
        Random r = ThreadLocalRandom.current();

        int size = 100;
        int maxElement = 100000;

        Integer[] integers
                = IntStream.generate(() -> r.nextInt(maxElement))
                .limit(size)
                .sorted()
                .boxed()
                .toArray(Integer[]::new);

        // The element that should be found
        int shouldBeFound = integers[r.nextInt(size - 1)];
        
        //自己的二分查找
        int atIndex = find1(integers, shouldBeFound);
        
        System.out.println(
                String.format(
                        "Should be found: %d. Found %d at index %d. An array length %d",
                        shouldBeFound, integers[atIndex], atIndex, size));
        //系统的二分查找
        int toCheck = Arrays.binarySearch(integers, shouldBeFound);
        System.out.println(
                String.format(
                        "使用系统的二分查找 index: %d. Is equal: %b", toCheck, toCheck == atIndex));
    }

三、插值查找(Interpolation Search)

        插值查找,有序表的一种查找方式。插值查找是根据查找关键字与查找表中最大最小记录关键字比较后的查找方法。插值查找基于二分查找,将查找点的选择改进为自适应选择,提高查找效率。

        如果数据分布不均匀,则插值查找算法的性能会很差,该算法的最坏时间复杂度是O(N)。如果数据分布得相当均匀,则最佳时间复杂度是O(log(log N))。 

/**
 * @param array is a sorted array
 * @param key is a value what shoulb be found in the array
 * @return an index if the array contains the key unless -1
 */
public int find2(int array[], int key) {
    // Find indexes of two corners
    int start = 0, end = (array.length - 1);

    // Since array is sorted, an element present
    // in array must be in range defined by corner
    while (start <= end && key >= array[start] && key <= array[end]) {
        // Probing the position with keeping
        // uniform distribution in mind.
        int pos = start + (((end - start) / (array[end] - array[start])) * (key - array[start]));

        // Condition of target found
        if (array[pos] == key) {
            return pos;
        }

        // If key is larger, key is in upper part
        if (array[pos] < key) {
            start = pos + 1;
        } // If key is smaller, x is in lower part
        else {
            end = pos - 1;
        }
    }
    return -1;

}

@Test
void interpolation_search()
{
    Random r = new Random();
    int size = 100;
    int maxElement = 100000;
    int[] integers = IntStream.generate(() -> r.nextInt(maxElement)).limit(size).sorted().toArray();

    // the element that should be found
    Integer shouldBeFound = integers[r.nextInt(size - 1)];

    int atIndex = find2(integers, shouldBeFound);

    System.out.println(
            String.format(
                    "Should be found: %d. Found %d at index %d. An array length %d",
                    shouldBeFound, integers[atIndex], atIndex, size));

    int toCheck = Arrays.binarySearch(integers, shouldBeFound);
    System.out.println(
            String.format(
                    "Found by system method at an index: %d. Is equal: %b", toCheck, toCheck == atIndex));
}

猜你喜欢

转载自blog.csdn.net/bashendixie5/article/details/123569103
今日推荐