目次
検索アルゴリズム
検索アルゴリズムはデータのサイズに応じて次の2種類に分けられます。
- 内部検索: 内部検索とは、メモリまたは内部ストレージで検索操作を実行するアルゴリズムを指します。内部ルックアップは、データ サイズが小さい場合、メモリに保存されている場合、または高速にアクセスされる場合に適しています。一般的な内部検索アルゴリズムには、逐次検索、バイナリ検索、内挿検索などが含まれます。
- 外部検索: 外部検索は、大規模なデータ収集または外部ディスクなどの補助記憶媒体で検索操作を実行するアルゴリズムを指します。
検索対象のテーブルやデータに変更があったかどうかは、次の2種類に分けられます。
- 静的検索: 静的検索とは、検索対象のデータを変更せずに実行される検索操作を指します。つまり、検索対象のテーブルまたはデータは、検索プロセス中に変更されません。静的検索は、静的データまたは読み取り専用データが検索される状況に適しています。インデックスまたはテーブルを作成したら、データを変更せずに検索操作を繰り返すことができます。一般的な静的検索アルゴリズムには、逐次検索、バイナリ検索、内挿検索などが含まれます。
- 動的検索: 動的検索は、検索プロセス中に検索対象のデータが変更される可能性がある場合に実行される検索操作を指します。つまり、検索対象のテーブルまたはデータは、検索プロセス中に追加、削除、または更新される可能性があります。動的検索は、動的データが検索され、データの変更にリアルタイムで対応する必要があるシナリオに適しています。一般的な動的検索アルゴリズムには、二分探索ツリー、AVL ツリー、赤黒ツリーなどが含まれます。これらのツリー構造は効率的な検索を実現し、動的データの挿入と削除をサポートします。
1. 逐次検索
図:
アルゴリズム原理: 逐次検索は線形検索とも呼ばれ、基本的な検索アルゴリズムです。ターゲット要素が見つかるまで、またはシーケンス全体が走査されるまで、検索対象の要素のシーケンスを 1 つずつ比較します。具体的な手順は次のとおりです。
- シーケンスの最初の要素から開始して、順番にターゲット要素と比較されます。
- 現在の要素がターゲット要素と等しい場合、検索は成功し、対応する位置が返されます。
- 現在の要素がターゲット要素と等しくない場合は、次の要素に進み比較します。
- シーケンス全体を走査してもターゲット要素が見つからない場合、検索は失敗します。
ケースコード:
public class javaDemo1 {
public static void main(String[] args) {
int data[] = new int[100];
int Target = 99;
int TargetIndex = -1;
Random random = new Random();
for (int i=0;i< data.length;i++){
data[i] = random.nextInt(100);
}
// 循序查找
for (int j=0;j< data.length;j++){
if (data[j] == Target){
TargetIndex = j;
break;
}
}
System.out.println(Arrays.toString(data));
if (TargetIndex!= -1){
System.out.println("找到数据啦,在第"+(TargetIndex+1)+"个数据处");
}else {
System.out.println("抱歉,并没有找到目标数据 喵");
}
}
}
アルゴリズムの概要:順次検索の時間計算量は O(n) です。ここで、n は検索されるシーケンスの長さです。シンプルで直感的な特性により、小規模なデータや順序付けされていないデータ収集に適しています。
2.二分探索
図:
アルゴリズムの原理:バイナリ サーチは、ハーフサーチとも呼ばれ、検索するシーケンスが順序どおりである必要がある効率的な検索アルゴリズムです。検索範囲を継続的に絞り込むことで、目的の要素を素早く見つけ出します。具体的な手順は次のとおりです。
- 順序付けられたシーケンスの最初の要素と最後の要素は、それぞれ左側と右側の境界として使用されます。
- 中間位置midを計算し、シーケンスの途中の要素を取得します。
- 中間要素がターゲット要素と等しい場合、検索は成功し、対応する位置が返されます。
- 中央の要素がターゲット要素より大きい場合、ターゲット要素は左半分にある可能性があり、狭められる範囲は左境界から中央 1 までのシーケンスになります。
- 中央の要素がターゲット要素より小さい場合、ターゲット要素は右半分にある可能性があり、範囲はmid+1から右境界までのシーケンスに狭まります。
- 目的の要素が見つかるか、検索範囲が空になるまで、上記の手順を繰り返します。
ケースコード:
public class javaDemo2 {
public static void main(String[] args) {
int data[] = new int[10];
// 目标值与目标值对应的下角标
int Target = 3;
int TargetIndex = -1;
// 二分法的下界与上界
int low = 0;
int high = data.length-1;
int middle;
Random random = new Random();
for (int i=0;i< data.length;i++){
data[i] = random.nextInt(10);
}
// 形成有序数组
Arrays.sort(data);
// 二分法查找
while (low<=high){
middle = (low+high)/2;
if (data[middle]>Target){
high = middle-1;
}else if (data[middle]<Target){
low = middle + 1;
}else {
TargetIndex = middle;
break;
}
}
System.out.println(Arrays.toString(data));
System.out.println("目标值为"+Target);
if (TargetIndex!= -1){
System.out.println("找到数据啦,在第"+(TargetIndex+1)+"个数据处");
}else {
System.out.println("抱歉,并没有找到目标数据 喵");
}
}
}
アルゴリズムの概要: 二分探索の時間計算量は O(log n) です。ここで、n は探索されるシーケンスの長さです。検索範囲が毎回半分に減少するため、この方法の方が効率的です。
3. 補間探索方法
図:
アルゴリズム原理: 補間探索法は、二分法に基づいて最適化された探索アルゴリズムであり、順序付けされたシーケンス内の対象要素の推定位置に基づいて探索するため、探索速度が向上します。具体的な手順は次のとおりです。
- 最初と最後の要素に対するターゲット要素の推定位置を計算します。つまり、式 (target - arr[left]) / (arr[right] - arr[left]) * (right) の途中で補間位置を計算します。 - 左) + 左。
- 補間位置midが配列の範囲を超えていたり、対象の要素が先頭の要素より小さい、あるいは最後の要素より大きい場合は、対象の要素が存在しないことを意味します。
- 補間位置midの要素がターゲット要素と等しい場合、検索は成功し、対応する位置が返されます。
- 補間位置midの要素が対象要素より大きい場合、対象要素は左半分にある可能性があり、狭める範囲は左境界からmid-1までの列となります。
- 補間位置midの要素が対象要素より小さい場合、対象要素は右半分にある可能性があり、範囲はmid+1から右境界までの系列に縮小されます。
- 目的の要素が見つかるか、検索範囲が空になるまで、上記の手順を繰り返します。
ケースコード:
public class InsertSerach {
public static void main(String[] args) {
int data[] = new int[10];
int Target = 9;
int TargetIndex = -1;
int low = 0;
int high = data.length-1;
int middle;
Random random = new Random();
for (int i= 0;i< data.length;i++){
data[i] = random.nextInt(10);
}
// 实现数组排列有序
Arrays.sort(data);
// 插入查找
while (low<=high){
middle = low + (high - low) * (Target - data[low]) / (data[high] - data[low]);
if (data[middle]<Target){
low = middle +1;
}else if (data[middle]>Target){
high= middle -1;
}else {
TargetIndex = middle;
break;
}
}
System.out.println(Arrays.toString(data));
if (TargetIndex!= -1){
System.out.println("找到数据啦,在第"+(TargetIndex+1)+"个数据处");
}else {
System.out.println("抱歉,并没有找到目标数据 喵");
}
}
}
アルゴリズムの概要:内挿検索法の時間計算量は O(log log n) です。ここで、n は検索されるシーケンスの長さです。これは、均等に分散された順序付けされたシーケンスにはうまく機能しますが、不均一に分散されたシーケンスにはうまく機能しない可能性があります。
4. フィボナッチ探索法
図:
アルゴリズム原理:フィボナッチ検索メソッドは、黄金分割原理を使用して検索する改良されたバイナリ検索アルゴリズムです。まず、各要素が前の 2 つの要素の合計であるフィボナッチ数列を作成する必要があります。
フィボナッチ検索方法を使用する場合は、まずフィボナッチ数列の長さを、検索する配列の長さ以上になるように決定する必要があります。次に、フィボナッチ数列の長さに基づいて、2 つのフィボナッチ値 F(k)-1 と F(k-2)-1 を決定します。
次に、検索対象の順序付き配列内で、位置 F(k)-1 の要素が比較の中間値として使用されます。
- ターゲット値が中間値と等しい場合、検索は成功し、対応する位置が返されます。
- ターゲット値が中央値より小さい場合、フィボナッチ検索は中央値の左半分で続行されます。
- ターゲット値が中央値より大きい場合、フィボナッチ検索は中央値の右半分で続行されます。
各比較の後、検索範囲の絞り込みに従って、ターゲット値が見つかるか検索範囲が空になるまで、次の比較のために新しい中間値が選択されます。
ケースコード:
public class FibonacciSearch {
public static void main(String[] args) {
int data[] = new int[10];
int Target = 9;
int TargetIndex = -1;
int low = 0;
int high = data.length - 1;
int middle = 0;
Random random = new Random();
for (int i = 0; i < data.length; i++) {
data[i] = random.nextInt(10);
}
Arrays.sort(data);
// 生成斐波那契数列
int[] fibonacci = generateFibonacci(data.length);
// 根据斐波那契数列确定数组长度的最接近值
int length = getClosestFibonacciNumber(data.length);
// 扩展数组长度至斐波那契数列长度
int[] extendedData = Arrays.copyOf(data, length);
for (int i = data.length; i < extendedData.length; i++) {
extendedData[i] = extendedData[data.length - 1];
}
while (low <= high) {
int k = fibonacci[middle - 1];
if (Target < extendedData[middle]) {
high = middle - 1;
middle = low + k - 1;
} else if (Target > extendedData[middle]) {
low = middle + 1;
middle = low + k;
} else {
TargetIndex = Math.min(middle, high);
break;
}
}
System.out.println(Arrays.toString(data));
if (TargetIndex != -1) {
System.out.println("找到数据啦,在第" + (TargetIndex + 1) + "个数据处");
} else {
System.out.println("抱歉,并没有找到目标数据 喵");
}
}
// 生成斐波那契数列
private static int[] generateFibonacci(int length) {
int[] fibonacci = new int[length];
fibonacci[0] = 1;
fibonacci[1] = 1;
for (int i = 2; i < length; i++) {
fibonacci[i] = fibonacci[i - 1] + fibonacci[i - 2];
}
return fibonacci;
}
// 获取斐波那契数列中与数组长度最接近的数值
private static int getClosestFibonacciNumber(int n) {
int a = 0;
int b = 1;
while (b <= n) {
int temp = b;
b = a + b;
a = temp;
}
return a;
}
}
アルゴリズムの概要:従来の二分探索法に対するフィボナッチ探索法の利点は、ターゲット値に速く近づくことができ、二分探索で中間値を取得するときに発生する整数オーバーフローの問題を回避できることです。ただし、場合によっては、フィボナッチ探索法のパフォーマンスが二分探索法ほど良くない場合があるため、実際のアプリケーションでは、特定の状況に応じて適切な検索アルゴリズムを選択する必要があります。