常见的查找算法大概有顺序查找、二分查找、二叉排序树查找、哈希表法(散列表)、分块查找等,
下面简单了解一下其余几种查找算法。java
1.顺序查找算法
也就是暴力方法,按顺序比较每一个元素,直到找到关键字为止。
条件:无序或有序数据,时间复杂度:O(n)数组
2.二叉排序树查找数据结构
二叉排序树的性质:
1. 若它的左子树不空,则左子树上全部结点的值均小于它的根结点的值;
2. 若它的右子树不空,则右子树上全部结点的值均大于它的根结点的值;
3. 它的左、右子树也分别为二叉排序树。函数
在二叉查找树b中查找x的过程为:
1. 若b是空树,则搜索失败,不然:
2. 若x等于b的根节点的数据域之值,则查找成功;不然:
3. 若x小于b的根节点的数据域之值,则搜索左子树;不然:
4. 查找右子树。spa
时间复杂度:O(\log_2(n)) blog
3.哈希表查找排序
建立哈希表(散列表)
哈希查找的操做步骤:⑴用给定的哈希函数构造哈希表⑵根据选择的冲突处理方法解决地址冲突⑶在哈希表的基础上执行哈希查找。
创建哈希表操做步骤: ① 取数据元素的关键字key,计算其哈希 函数值。若该地址对应的存储 空间尚未被占用,则将该元素存入;不然执行step2解决冲突。 ② 根据选择的冲突处理方法,计算关键字 key的下一个存储地址。若下一个存储地 址仍被占用,则继续执行step2,直到找 到能用的存储地址为止。
时间复杂度:几乎是O(1),取决于产生冲突的多少。递归
4.分块查找it
将n个数据元素"按块有序"划分为m块(m ≤ n)。
每一块中的结点没必要有序,但块与块之间必须"按块有序";
即第1块中任一元素的关键字都必须小于第2块中任一元素的关键字;
而第2块中任一元素又都必须小于第3块中的任一元素,……。
而后使用二分查找及顺序查找。
通常是操做有序数组,查找过程从数组的中间元素开始,若是中间元素正好是要查找的元素,则搜素过程结束;
若是某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,并且跟开始同样从中间元素开始比较。若是在某一步骤数组为空,则表明找不到。
这种搜索算法每一次比较都使搜索范围缩小一半。时间复杂度:O(logn)。
二分查找通常是用在有序序列的查找,不少时候查找须要结合排序操做来进行。
可是须要注意,二分查找并不必定非要在有序序列中才能获得应用,
只要在二分以后能够淘汰掉一半数据的场景,均可以应用二分搜索。
public static int binSearch(int[] arr,int des){ if(arr==null || arr.length<1){ return -1; } int left=0; int right=arr.length-1;//注意防止数组下标越界 /** * 这里的判断条件必须包含等于, * 考虑{1,2,3},查找1,若是不判断等于,就丢失了比较致使查找错误 */ while(left<=right){ int mid=left+(right-left)/2; if(des==arr[mid]){ return mid; }else if(des<arr[mid]){//舍弃右侧 /** * 注意,此处的mid已经参与过比较了并失败了, * 因此从新二分不要包含进来,下同 */ right=mid-1; }else{//舍弃左侧 left=mid+1; } } return -1;//查找失败 返回-1 } /** * @Title: bSearchRecursion * 递归参数有不一样,left和right明显在每次递归时都是变的 */ public static int binSearchRecursion(int[] arr,int left,int right,int des){ if(arr==null || arr.length<1){ return -1; } if(left<=right){ int mid=left+(right-left)/2; if(des==arr[mid]){ return mid; }else if(des<arr[mid]){//舍弃右侧 return binSearchRecursion(arr,left,mid-1,des); }else{//舍弃左侧 return binSearchRecursion(arr,mid+1,right,des); } } return -1; }
折半查找,通常将待比较的key值与第mid=(low+high)/2位置的元素比较,
同时为了防止溢出,使用更高效的移位,也能够记作 mid=low+((low+high)>>1)。
比较结果分三种状况
1)相等,mid位置的元素即为所求
2)> ,low=mid+1;
3)< ,high=mid-1;
斐波那契查找要求元素表中记录的个数为某个斐波那契数减1,即n=Fk-1;
斐波那契数列:0、一、一、二、三、五、八、1三、2一、……
若是设F(n)为该数列的第n项(n∈N)。那么这句话能够写成以下形式:
F(0) = 0,F(1)=1,F(n)=F(n-1)+F(n-2) (n≥2),
这是一个线性递推数列,斐波那契数列的算法实现常常在数据结构教材的递归一节中出现。
对于二分查找,分割是从mid=(low+high)/2开始;而对于斐波那契查找,分割是从mid = low + F[k-1] - 1开始的; 经过上面知道了,数组a如今的元素个数为F[k]-1个,即数组长为F[k]-1,mid把数组分红了左右两部分, 左边的长度为:F[k-1] - 1, 那么右边的长度就为(数组长-左边的长度-1), 即:(F[k]-1) - (F[k-1] - 1) = F[k] - F[k-1] - 1 = F[k-2] - 1。
斐波那契查找的核心是:
1)当key=a[mid]时,查找成功;
2)当key<a[mid]时,新的查找范围是第low个到第mid-1个,此时范围个数为F[k-1] - 1个,即数组左边的长度,因此要在[low, F[k - 1] - 1]范围内查找;
3)当key>a[mid]时,新的查找范围是第mid+1个到第high个,此时范围个数为F[k-2] - 1个,即数组右边的长度,因此要在[F[k - 2] - 1]范围内查找。
与二分查找相比,斐波那契查找它只涉及加法和减法运算,而不用除法(用“>>1”要好点)。由于除法比加减法要慢,在海量数据的查找过程当中,这种细微的差异可能会影响最终的效率。
参考《大话数据结构》