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