查找算法总结
1. 顺序查找
顺序查找适合于存储结构为顺序存储或链式存储的线性表。
- 算法实现:
/**
* 顺序查找的算法实现
*
* @param arr 查找的序列
* @param value 查找某个值
* @return 如果查到,返回这个值得位置下标
*/
public static int sequenceSearch(int arr[], int value) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == value) {
return i;
}
}
return -1;
}
- 算法优化:
设置 哨 兵 \color{red}哨兵 哨兵这一思想,将a[0]设置成哨兵则可以避免每次比较元素后都需要判断下标是否越界这一问题,从而节省了时间。当然,a[0]中将不能在存放有效元素
/**
* @param arr 待查找序列
* @param value 查找元素
* @return
*/
public static int sequenceSearchV2(int[] arr, int value) {
// 从后往前遍历数组
int i = arr.length - 1;
// 将a[0]设置成哨兵,避免每次比较元素后都需要判断下标是否越界这一问题
arr[0] = value;
// 若数组中无key,则一定会得到a[0]=key
while (arr[i] != value) {
i--;
}
//查找失败返回0
return i;
}
2. 二分查找
元素必须是有序的,如果是无序的则要先进行排序操作。
- 算法实现:
- 非递归实现
/**
* 二分查找算法 - 非递归实现
*
* @param arr 查找的序列
* @param value 查找某个值
* @return 如果查到,返回这个值得位置下标
*/
public static int binarySearch(int[] arr, int value) {
// 定义好首尾指针
int low = 0, hign = arr.length - 1;
while (low <= hign) {
int mid = (low + hign) / 2;
if (value == arr[mid]) {
return mid;
}
if (value < arr[mid]) {
hign = mid - 1;
}
if (value > arr[mid]) {
low = mid + 1;
}
}
return -1;
}
- 递归实现
/**
* 二分查找算法 - 递归实现
*
* @param arr 查找的序列
* @param value 查找某个值
* @return 如果查到,返回这个值得位置下标
*/
public static int binarySearchV2(int[] arr, int value, int low, int hign) {
// 递归的终止条件1:未查询到某个值
if (low > hign) {
return -1;
}
int mid = (low + hign) / 2;
if (value < arr[mid]) {
return binarySearchV2(arr, value, low, mid - 1);
} else if (value > arr[mid]) {
return binarySearchV2(arr, value, mid + 1, hign);
} else {
// 递归的终止条件2:查询到
return mid;
}
}
3. 插值查找
- 算法思想:
基于二分查找算法, 将 查 找 点 的 选 择 改 进 为 自 适 应 选 择 \color{red}将查找点的选择改进为自适应选择 将查找点的选择改进为自适应选择,
二分查找中查找点计算如下:mid = (low+high) / 2, 即mid = low + 1/2*(high-low);
通过类比,我们可以将查找的点改进为如下:mid = low + (key-a[low])/(a[high]-a[low]) * (high-low),
也就是将上述的比例参数1/2改进为自适应的,根据关键字在整个有序表中所处的位置,让mid值的变化更靠近关键字key,这样也就间接地减少了比较次数。可以提高查找效率。当然,插值查找也属于有序查找。
注:对于表长较大,而关键字分布又比较均匀的查找表来说,插值查找算法的平均性能比折半查找要好的多。反之,数组中如果分布非常不均匀,那么插值查找未必是很合适的选择。 - 算法实现:
/**
* 插值查找算法实现 - 将二分查找中的比例参数1/2改进为自适应的
*
* @param arr 待查找序列
* @param value 查找元素
* @param low
* @param high
* @return
*/
public static int insertSearch(int[] arr, int value, int low, int high) {
if (low > high) {
return -1;
}
int mid = low + (value - arr[low]) / (arr[high] - arr[low]) * (high - low);
if (value < arr[mid]) {
return insertSearch(arr, value, low, mid - 1);
} else if (value > arr[mid]) {
return insertSearch(arr, value, mid + 1, high);
} else {
return mid;
}
}
4. 斐波那契查找
- 算法思想:
也是二分查找的一种提升算法,通过运用黄金比例的概念在数列中选择查找点进行查找,提高查找效率。同样地,斐波那契查找也属于一种有序查找算法。
5. 树表查找
-
二叉树查找算法:
基本思想:二叉查找树是先对待查找的数据进行生成树,确保树的左分支的值小于右分支的值,然后在就行和每个节点的父节点比较大小,查找最适合的范围。 这个算法的查找效率很高,但是如果使用这种查找方法要首先创建树。二叉查找树(BinarySearch Tree,也叫二叉搜索树,或称二叉排序树Binary Sort Tree)或者是一棵空树,或者是具有下列性质的二叉树:
1)若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
2)若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
3)任意节点的左、右子树也分别为二叉查找树。
6. 分块查找
- 算法思想:
分块查找又称索引顺序查找,它是顺序查找的一种改进方法。
将n个数据元素”按块有序”划分为m块(m ≤ n)。每一块中的结点不必有序,但块与块之间必须”按块有序”;即第1块中任一元素的关键字都必须小于第2块中任一元素的关键字;而第2块中任一元素又都必须小于第3块中的任一元素,……
7. 哈希查找
散列表(Hash table,也叫哈希表),是根据键(Key)而直接访问在内存存储位置的数据结构。也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数,存放记录的数组称做散列表。
散列函数的规则是:通过某种转换关系,使关键字适度的分散到指定大小的的顺序结构中,越分散,则以后查找的时间复杂度越小,空间复杂度越高。
- 直接定址法:
取关键字或关键字的某个线性函数值为散列地址。即hash(k) = k 或 hash(k) = a · k + b,其中a、b为常数(这种散列函数叫做自身函数) - 数字分析法:
- 平方取中法:
- 折叠法:
- 随机数法:
- 除留余数法:
- 拉链法:
(未完待续。。。)
参考资料
https://blog.youkuaiyun.com/yimixgg/article/details/88900038
https://www.cnblogs.com/magic-sea/p/11395997.html