title: 常用查找算法及Java实现

description: 常用的一些查找算法,经典必会,Java实现。

tags:

查找算法

categories:

算法

toc: true

comments: true

date: 2020-07-30 20:05:54

常用算法

顺序查找

顺序查找也称为线形查找,属于无序查找算法。从数据结构线形表的一端开始,顺序扫描,依次将扫描到的结点关键字与给定值k相比较,若相等则表示查找成功;若扫描结束仍没有找到关键字等于k的结点,表示查找失败。

顺序查找的时间复杂度为O(n)。

public class Search {
public static void main(String[] args) {
int arr[] = {5, 11, 7, 9, 2, 3, 12, 8, 6, 1, 4, 10};
search(arr,3);
}
/**
* 顺序查找
*/
public static int order(int[] arr, int target) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
return i;
}
}
return -1;
}
}

二分查找

也称为是折半查找,属于有序查找算法。用给定值k先与中间结点的关键字比较,中间结点把线形表分成两个子表,若相等则查找成功;若不相等,再根据k与该中间结点关键字的比较结果确定下一步查找哪个子表,这样递归进行,直到查找到或查找结束发现表中没有这样的结点。

最坏情况下,关键词比较次数为log2(n+1),且期望时间复杂度为

O(log2n);
/**
* 常规二分查找
*/
public static int half(int[] arr, int target) {
//使数组有序
Arrays.sort(arr);
System.out.println(String.format("原数组%s中查找【%s】", Arrays.toString(arr), target));
int left = 0;
int right = arr.length - 1;
while (left <= right) {
int mid = ((right - left) >> 1) + left;
if (target > arr[mid]) {
left = mid + 1;
} else if (target < arr[mid]) {
right = mid - 1;
} else {
return mid;
}
}
return -1;
}
/**
* 递归二分查找
* @param high len-1
*/
public static int halfByRecurse(int[] arr, int target, int low, int high) {
int mid = ((high - low) >> 1) + low;
if (low == high) {
return -1;
}
if (target == arr[mid]) {
return mid;
}
if (target > arr[mid]) {
return halfByRecurse(arr, target, mid + 1, high);
}
if (target < arr[mid]) {
return halfByRecurse(arr, target, low, mid - 1);
}
return -1;
}

插值查找

基于二分查找算法,将查找点的选择改进为自适应选择,可以提高查找效率。当然,差值查找也属于有序查找

代码基本上和二分查找一样,有修改的地方就是mid的获取

在二分查找中$mid=$$low+high \over {2}$ 可改写成 $mid =low + $ $ {high-low} \over {2}$

也就是说我们的mid每次都是折中的取,但是对于一些均匀分布的有序表,这样做感觉有些费时,比如找字典的时候,找a这个字母,我们肯定不会从中间开始,而是偏向于字典前面一些开始。

插值查找就是基于这样的思想

我们对1/2进行改进:

$mid=low+$$key-a[low] \over a[high]=a[low]$$(high-low)$

key就是要查找的值,数组a是有序表

简单的理解就是计算出key所占比,然后更好地找到key所在的区间范围

但是对于极端分布的数组,插值查找的效率就大打折扣了

比如

int a[7]={0,1,2,100,102,1000,10000}
Java代码实现
/**
* 插值查找
*/
public static int insert(int[] arr, int target) {
//使数组有序
Arrays.sort(arr);
System.out.println(String.format("原数组%s中进行插值查找【%s】", Arrays.toString(arr), target));
int left = 0;
int right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) * ((target - arr[left]) / (arr[right] - arr[left]));
if (target > arr[mid]) {
left = mid + 1;
} else if (target < arr[mid]) {
right = mid - 1;
} else {
return mid;
}
}
return -1;
}
/**
* 递归插值查找
*
* @param high len-1
*/
public static int insertByRecurse(int[] arr, int target, int low, int high) {
int mid = low + (high - low) * ((target - arr[low]) / (arr[high] - arr[low]));
if (low <= high) {
if (target == arr[mid]) {
return mid;
} else if (target > arr[mid]) {
return insertByRecurse(arr, target, mid + 1, high);
} else {
return insertByRecurse(arr, target, low, mid - 1);
}
} else {
return -1;
}
}

斐波那契查找

斐波那契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89…….(从第三个数开始,后边每一个数都是前两个数的和)。然后我们会发现,随着斐波那契数列的递增,前后两个数的比值会越来越接近黄金分割0.618,利用这个特性,我们就可以将黄金比例运用到查找技术中。

也是二分查找的一种提升算法,通过运用黄金比例的概念在数列中选择查找点进行查找,提高查找效率。同样地,斐波那契查找也属于一种有序查找算法。

Java搜索的源代码 java 搜索_数组

树表查找

分块查找

哈希查找