データ構造とアルゴリズム15.線形アルゴリズム/二分探索/補間探索

1.線形探索

        データを見つけるための最も簡単な戦略は線形検索です。線形検索では、各要素を調べてターゲットを見つけ、各データポイントにアクセスして一致を見つけます。一致が見つかると、結果が返され、アルゴリズムがループを終了します。それ以外の場合は、データの終わりに達するまで、アルゴリズムは検索を続けます。線形ルックアップの明らかな欠点は、固有の徹底的な検索のために非常に遅いことです。データを並べ替える必要がないという利点があります。

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

2.二分探索

        二分探索アルゴリズムの前提は、データが順序付けられていることです。アルゴリズムは、現在のリストを2つの部分に繰り返し分割し、探している値が見つかるまで、最低と最高の2つのインデックスを追跡します。

        二分探索は、各反復でアルゴリズムがデータを2つの部分に分割するため、このように名付けられています。データに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));
    }

3.補間検索

        補間検索、順序付きリストの検索方法。補間検索は、検索キーとルックアップテーブルの最大および最小のレコードキーに基づく検索方法です。補間検索は二分探索に基づいており、検索ポイントの選択は、検索効率を向上させるために適応選択に改善されています。

        データが均等に分散されていない場合、内挿ルックアップアルゴリズムのパフォーマンスは低下し、このアルゴリズムの最悪の時間計算量は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