查找
查找即从一堆数据中找到我们想要的数据。查找算法有很多种,包括:[1]
- 顺序查找
- 二分查找
- 插值查找
- 斐波那契查找
- 树表查找
- 分块查找
- 哈希查找
鉴于水平有限,这篇博文仅讨论顺序查找、二分查找和树表查找中的二分搜索树查找。如果想了解其他查找算法,可以参考七大查找算法
查找表
在一个数据集合中查找想要的内容,这个数据集合就是查找表,查找表可以分为:
- 静态查找表:只做查找工作,查找过程中不会去改变查找表
- 动态查找表:在查找的过程中会插入不存在的数据元素,或者删除特定的元素,即在查找的过程中会去改变查找表
查找表存储在不同的数据结构上,其性能也是不同的
查找元素 | 插入元素 | 删除元素 | |
---|---|---|---|
普通数组 | O(N) | O(N) | O(N) |
顺序数组 | O(logN) | O(N) | O(N) |
二分搜索树 | O(logN) | O(logN) | O(logN) |
- 对于静态查找表,将其以顺序数组存储,可以采用二分查找法进行高效的查找操作
- 对于动态查找表,更多的是采用二分查找树在存储
- 另外哈希表(散列表)也可以解决一些查找问题
顺序查找
这是最简单的查找方式,顺序查找的思路就是:遍历整个数据集合,这样最好的情况下,时间复杂度是O(1),最坏情况下的时间复杂度是O(N),平均时间复杂度是O(N)
适用于静态查找表,对查找表中的记录没有要求,所以在数据量很小的查找表中可以使用顺序查找
二分查找
二分查找又称为折半查找,时间复杂度是O(logN),适用的条件是:
- 适用于有序的的一组数,所以说对于一组没有顺序的数,要使用二分查找法必须要先进行排序
- 存储结构要是顺序存储结构,链表就不能进行二分查找
/**
* @brief 循环方式实现二分查找
* @return 查找到了返回对应的index,否则返回-1
*/
template <typename T>
int binary_search(T array[], int size, T target){
int left = 0;
int right = size - 1;
int middle;
while(left <= right){
middle = left + (right - left) / 2;
if(target == array[middle]){
return middle;
}
else if(target < array[middle]){
right = middle - 1;
}
else{
left = middle + 1;
}
}
return -1;
}
/**
* @brief 递归方式实现二分查找
* @return 查找到了返回对应的index,否则返回-1
*/
template <typename T>
int binary_search(T array[], int left, int right, T target){
if(left > right){
return -1;
}
int middle = left + (right - left) / 2;
if(target == array[middle]){
return middle;
}
else if(target < array[middle]){
binary_search(array, left, middle - 1);
}
else{
binary_search(array, middle + 1, right);
}
}
参考文献
- [1]. 七大查找算法 – AI你一生