1.查找
- 查找:在一些数据元素中,通过一定的方法找出与给定关键字相同的数据元素的过程;
- 列表查找(线性表查找):从列表中查找指定元素;
- 输入: 列表,待查找元素
- 输出:元素下标(未找到元素时一般返回None或-1)
- 内置列表查找函数:index of ()
2. 顺序查找(Linear Search)
顺序查找
:也叫线性查找,从列表第一个元素开始,顺序进行搜索,直到找到元素或搜索到列表最后一个元素为止;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
* 线性查找/顺序查找
*
* @author wql
* @date 2022/12/7 21:44
*/
public class LinearSearch {
public static void main(String[] args) {
List<String> asList = Arrays.asList("A", "AB", "AC");
int index = handLinearSearch(asList, "AC");
System.out.println("index = " + index);
}
/**
* 顺序查找(线性查找)
*
* @param arr 待查找列表
* @param targetValue 目标值
* @return 目标值所处位置索引下标
*/
public static int handLinearSearch(List<String> arr, String targetValue) {
for (int i = 0; i < arr.size(); i++) {
if (Objects.equals(targetValue, arr.get(i))) {
return i;
}
}
return -1;
}
}
如上图所示:分析算法时间复杂度三部曲:寻找规模n,是否存在循环减半过程,k层关于n的循环;从代码中,我们可以看出不存在循环减半和k层n循环的过程,问题规模是n,那么这个顺序查找的
时间复杂度为: O(n)
3. 二分查找(Binary Search)
二分查找:又叫折半查找,从有序列表的初始候选区li[0:n] 开始,通过对待查找的值与候选区中间值的比较,可以是候选区减少一半;
案例:
我们要从列表里面寻找3的位置,问题规模是n,目标值是3,那么在使用二分查找的时候,我们的关键是如何为维护候选区,候选区指的是目标值所在区域;假设初始的时候left是0,right是n-1,其实就是下标;
那么我们求中间值就是left + right 之和,再除以2,也就是mid;
如上图所示,第一步中间值是5,5大于3,则要维护候选区,就是将right指针移动到mid-1的位置,如下图所示
第二步:重新计算新的mid下标,此时0+3 除以2 等于1,那么mid光标在 2上面
再比较2和3,发现2比3小,所以移动left,left的下一个位置等于mid位置+1
第三步:left=2,right=3,那么2+3=5,除以2,等于2,所以mid等于left,也就是3上面
最后一步:判断当mid值等于3时,输出mid值,也就是3的下标,如果left 大于right ,那么候选区没有值了,也就是找不到,返回-1
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
* 二分查找
*
* @author wql
* @date 2022/12/7 22:01
*/
public class BinarySearch {
public static void main(String[] args) {
List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
int index = handBinarySearch(asList, 3);
System.out.println("index = " + index);
}
/**
* 二分查找
* <p>
* 列表首先默认时排好序的
*
* @param arr 待查找列表
* @param targetValue 目标值
* @return 目标值所处位置索引下标
*/
public static int handBinarySearch(List<Integer> arr, Integer targetValue) {
//定义left right mid
int left = 0;
int right = arr.size() - 1;
//当left<=right时,表示候选区有值
while (left <= right) {
//获取中间值的下标
int mid = (left + right) / 2;
if (Objects.equals(targetValue, arr.get(mid))) {
return mid;
} else if (arr.get(mid) > targetValue) {
//如果中间值大于目标值,说明候选区在左侧
right = mid - 1;
} else if (arr.get(mid) < targetValue) {
//如果中间值小于目标值,说明候选区在右侧
left = mid + 1;
}
}
return -1;
}
}
时间复杂度:O(logn)
4. 顺序查找和二分查找对比
二分查找效率远远大于 线性查找,那为啥jdk里面的 index of 函数不使用二分查找,因为使用二分查找的前提是列表必须是有序的;所以在不能保证列表有序的情况下,使用线性查找;因为排序也可能消耗大量的时间;