查找算法
1. 线性查找
线性查找(Order Search)是最简单的一种查找算法,直接从头到尾遍历,直至找到要查找的值为止。
1.1 代码实现
package com.algorithm;
/**
* @author SnkrGao
* @create 2023-04-20 19:52
*/
public class OrderSearch {
public static void main(String[] args) {
int[] nums = {1, 8, 10, 89, 1000, 1234};
int searchValue = 89;
int searchIndex = orderSearch(nums, searchValue);
System.out.println("searchIndex=" + searchIndex);
}
public static int orderSearch(int[] nums, int searchValue) {
for (int i = 0; i < nums.length; i++) {
if (nums[i] == searchValue) {
return i;
}
}
return -1;
}
}
2. 二分查找
二分查找又叫折半查找,即从中间数开始查找,根据比较结果选择折半的一边,再次折半继续进行查找。二分查找是一种效率较高的查找方法,但是其要求线性表中的记录必须按关键字有序排列(即前提是线性表必须有序),并且必须采用顺序存储。
2.1 Binary Search设计思路(找到一个数就return)
- 确定当前数组的下标mid = (left + right) / 2;
- 让要查找的数searchValue与nums[mid]进行比较
- 若searchValue < nums[mid],说明待查找的数在mid左边,向左递归查找;
- 若searchValue > nums[mid],说明待查找的数在mid右边,向右递归查找;
- 若searchValue == nums[mid],说明找到该数,直接返回;
- 注意递归终止条件:
- 当找到待查找数时,结束递归;
- 递归查找完整个数组仍没有找到,也即当left > right时,结束递归;
- 此处应注意,left == right时,仍有可能找到,即nums[left] == nums[right] == nums[mid]可能为待查找值。
2.3 代码实现
递归:
public static int binarySearch(int[] nums, int searchValue, int left, int right) {
if (left > right) { // 递归终止条件
return -1;
}
// 折半
int mid = (left + right) / 2;
int midValue = nums[mid];
if (searchValue < midValue) {
return binarySearch(nums, searchValue, left, mid - 1);
} else if (searchValue > midValue) {
return binarySearch(nums, searchValue, mid + 1, right);
} else {
return mid;
}
}
迭代:
public static int binarySearch(int[] nums, int searchValue) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (searchValue < nums[mid]) {
right = mid - 1;
} else if (searchValue > nums[mid]) {
left = left + 1;
} else {
return mid;
}
}
return -1;
}
2.4 Binary Search设计思路(找到所有满足条件的值)
- 用一个List来接收所有满足条件的值;
- 向左递归和向右递归不需要修改,当找到第一个匹配的索引值mid时,不直接返回而是将下标mid添加到list中;
- 向mid索引的左侧继续扫描,将所有与searchValue相等的元素下标添加到list中;
- 向mid索引的右侧继续扫描,将所有与searchValue相等的元素下标添加到list中。
2.5 代码实现
package com.algorithm;
import java.util.ArrayList;
import java.util.List;
/**
* @author SnkrGao
* @create 2023-04-20 20:11
*/
public class BinarySearch {
public static void main(String[] args) {
int[] nums = {1, 8, 10, 89, 1000, 1000, 1000, 1000, 1234};
int searchValue = 1000;
List<Integer> searchIndex = binarySearch(nums, searchValue, 0, nums.length - 1);
System.out.println("searchIndex=" + searchIndex);
}
public static List<Integer> binarySearch(int[] nums, int searchValue, int left, int right) {
if (left > right) { // 递归终止条件,说明递归完毕仍没有找到
return new ArrayList<>();
}
// 折半
int mid = (left + right) / 2;
int midValue = nums[mid];
if (searchValue < midValue) {
// 向左递归查找
return binarySearch(nums, searchValue, left, mid - 1);
} else if (searchValue > midValue) {
// 向右递归查找
return binarySearch(nums, searchValue, mid + 1, right);
} else { // 已经找到了第一个与searchValue相等的值,继续在其周围找其他相同的值
List<Integer> searchIndexList = new ArrayList<>();
// 由于二分查找的前提是有序,因此相同的值一定在第一个找到的nums[mid]的两侧
// 继续向左扫描,但不折半
int temp = mid - 1;
while (temp >= 0 && nums[temp] == searchValue) {
searchIndexList.add(temp);
temp -= 1;
}
searchIndexList.add(mid);
// 继续向右扫描
temp = mid + 1;
while (temp <= right && nums[temp] == searchValue) {
searchIndexList.add(temp);
temp += 1;
}
return searchIndexList;
}
}
}
3. 插值查找
- 插值查找(Interpolation Search)类似于二分查找,不同的是插值查找每次从自适应mid处开始查找;
- 插值查找的mid值通过公式计算得来,mid = left + (right - left) × (searchValue - nums[left]) / (nums[right] - nums[left]);
- 该公式使得mid的变化更靠近searchValue,相当于间接减少了查找的次数;
- 插值查找同样只适用于有序序列,另外还要求数据元素的关键字在线性表中均匀分布;
- 对于数据量大且关键字分布均匀的有序序列来说,插值查找的速度较快;
- 对于分布不均匀的有序序列而言,插值查找并不一定比二分查找好。
3.1 代码实现
package com.algorithm;
import java.util.Arrays;
/**
* @author SnkrGao
* @create 2023-04-20 22:41
*/
public class InterpolationSearch {
public static void main(String[] args) {
int[] nums = new int[100];
for (int i = 0; i < nums.length; i++) {
nums[i] = i + 1;
}
System.out.println(Arrays.toString(nums));
int searchValue = 87;
int searchIndex = interpolationSearch(nums, searchValue, 0, nums.length - 1);
System.out.println("searchIndex=" + searchIndex);
}
public static int interpolationSearch(int[] nums, int searchValue, int left, int right) {
// 一定要添加下面的两个限制,否则根据mid的计算公式可能出现mid数组下标越界的问题
if (left > right || searchValue < nums[0] || searchValue > nums[nums.length - 1]) {
return -1;
}
int mid = left + (right - left) * (searchValue - nums[left]) / (nums[right - left]);
int midValue = nums[mid];
if (searchValue < midValue) {
return interpolationSearch(nums, searchValue, left, mid - 1);
} else if (searchValue > midValue) {
return interpolationSearch(nums, searchValue, mid + 1, right);
} else {
return mid;
}
}
}
标签:nums,int,searchValue,mid,算法,查找,left
From: https://www.cnblogs.com/SnkrGao/p/17341876.html