查找算法们(java)
顺序查找
二分查找
插值查找
斐波那契查找
树表查找
分块查找
哈希查找
一、顺序查找
描述:
遍历数组,依次比较,直到找到目标元素。
条件:
数组可以乱序可以有序,只要是可遍历的线性结构。
平均查找次数:(n+1)/2
时间复杂度:O(n)
代码:
public int seqSearch(int[] array,int target) {
//顺序查找
for(int i = 0;i < array.length;i ++) {
if(array[i] == target) {
return i;
}
}
return -1;
}
二、二分查找(折半查找)
描述:
每次将中点的元素与target做比较,若大于target,(以升序排列为 例)查找区间改为左半部分;若小于target,查找区间改为右半部分,在新的查找区间里再找中点的元素与target作比较,若不相等,再改变查找区间…直到找到目标元素(即中点元素等于target)。
条件:
数组必须是有序的
平均查找次数:log2n
时间复杂度:O(logn)
代码:
public static int binarySearch(int[] array,int target) {
//二分查找(以数组升序排列为例)
int left = 0;
int right = array.length-1;
while(left <= right) {
int mid = (left + right)/2;
if(array[mid] == target) {
return mid;
}else if(array[mid] > target) {
right = mid - 1;
}else {
left = mid + 1;
}
}
return -1;
}
三、插值查找
描述:
插值查找是二分查找的改进,二分查找是每次对数组下标的mid处查找,插值查找加入了数组中元素值的影响,每次从自适应的mid处查找。把二分法的(以数组升序排列为例)mid = (right+left)/2 = left+(right-left)/2公式,改为
mid = left+(right-left)*(target-array[left])/(array[right]-array[left])
条件:
数组必须是有序的
时间复杂度:O(loglogn)
代码:
public static int insertValueSearch(int[] array,int target) {
//插值查找(以数组升序排列为例)
int left = 0;
int right = array.length - 1;
if(target < array[left] || target > array[right])
return -1;
while(left <= right) {
int mid = left + (right - left)*(target - array[left])/(array[right] - array[left]);
if(array[mid] == target) {
return mid;
}else if(array[mid] > target) {
right = mid - 1;
}else {
left = mid + 1;
}
}
return -1;
}
四、斐波那契查找
描述:
斐波那契数列:fibonacci[0]=fibonacci[1]=1,
fibonacci[n]= fibonacci[n-1]+fibonacci[n-2]
n越大时fibonacci[n]/fibonacci[n-1]的值越接近黄金比例0.618,
斐波那契查找按照斐波那契函数进行分割,对于长度为fibonacci[n]的数组,进行分割时分割成fibonacci[n-1]长的前半部分和fibonacci[n-2]长的后半部分。找出最接近数组长度且大于数组长度的fibonacci函数值,多出的部分全部补充为数组最后一个元素。便于理解如图
条件:数组必须是有序的
时间复杂度:O(logn)
代码:
//斐波那契查找
private static int maxsize = 20;
public static int[] getFibonacci() {
//生成斐波那契数列
int[] fib = new int[maxsize];
fib[0] = 1;
fib[1] = 1;
for(int i = 2;i < maxsize;i ++) {
fib[i] = fib[i-1] + fib[i-2];
}
return fib;
}
public static int fibonacciSearch(int[] array,int target) {
//查找
int left = 0;
int right = array.length - 1;
int[] fib = getFibonacci();//获取斐波那契数列
int k = 0;//斐波那契分割数下标
while(right > fib[k]) {
k ++;
}
//构造k长度的新数组并把array里的元素拷贝过来
int[] temp = Arrays.copyOf(array, fib[k]);
//对新数组进行元素补充
for(int i = right + 1;i < k;i ++) {
temp[i] = array[right];
}
while(left <= right) {
int mid = left + fib[k-1] - 1;
if(temp[mid] > target) {
right = mid - 1;
//判断target在前半部分,而前半部分有fib[k-1]个元素,
//可以再分成fib[k-1]=fib[k-2]+fib[k-3],则下次循环就是k-2即在原来(k-1)的基础上减一
k -= 1;
}else if(temp[mid] < target) {
left = mid + 1;
//判断target在后半部分,而后半部分有fib[k-2]个元素,
//可以再分成fib[k-2]=fib[k-3]+fib[k-4],则下次循环就是k-3即在原来(k-1)的基础上减二
k -= 2;
}else {
//target=array[mid]的情况,此时要判断结果是否在补充的元素中,若在的话就返回原数组的最后一位
if(mid <= array.length-1) {
return mid;
}else {
return array.length-1;
}
}
}
return -1;
}
五、树表查找
描述:只介绍一种最简单的树表查找:二叉搜索树
二叉搜索树(又称二叉排序树),是一种对查找和排序都很有用的特殊二叉树。
二叉搜索树可以是空树,也可以是满足如下性质的二叉树:
(1)若其左子树非空,则左子树上所有节点的值均小于根节点的值;
(2)若其右子树非空,则右子树上所有节点的值均大于等于根节点的值;
即二叉搜索树中序遍历后会得到一个关键字递增的有序序列。
查找时先用数组构建一个二叉搜索树(尽量构建成一个平衡二叉树),然后对该二叉搜索树进行查找,
查找时,如果target等于根节点,则返回根节点地址,
如果target大于根节点,则继续查找右子树,
如果target小于 根节点,则继续查找左子树。
时间复杂度:二叉树有n个节点
如果二叉搜索树是平衡的,则其深度为log2n +1,时间复杂度为O(logn)
若果二叉搜索树完全不平衡,则其深度可能达到n,查找效率退化为O(n).
所以,一般二叉搜索树的查找时间复杂度在O(logn)和O(n)之间。
代码:
//简单树表查找(二叉搜索树)
public static TreeNode sortArrayTOtree(int[] array) {
//把待查找数组构建成一个二叉搜索树
int end = array.length;
if(end <= 0)
return null;
return buildTree(array,0,end-1);
}
public static TreeNode buildTree(int[] array,int start,int end) {
//构建二叉搜索树
if(start <= end) {
int mid = (start + end)/2;
//把数组中间的元素设置为二叉树根节点的数值
TreeNode root = new TreeNode(array[mid]);
root.left = buildTree(array, start, mid-1);
root.right = buildTree(array, mid+1, end);
return root;
}else {
return null;
}
}
public static TreeNode binaryTreeSearch(int[] array,int target) {
TreeNode root = sortArrayTOtree(array);
if(root == null)
return null;
TreeNode temp = root;
while(temp != null) {
//若根节点大于目标元素,则目标元素在其左子树上
if(temp.data > target) {
temp = temp.left;
//若左子树为空,则目标元素不在该二叉树上,返回空
if(temp == null) {
return null;
}
}
//若根节点小于目标元素,则目标元素在其右子树上
if(temp.data < target) {
temp = temp.right;
//若右子树为空,则目标元素不在该二叉树上,返回空
if(temp == null) {
return null;
}
}
if(temp.data == target) {
return temp;
}
}
return null;
}
二叉树的基本数据类型:
public class TreeNode {
int data;//存放当前节点的数据
TreeNode left;//当前节点的左子树
TreeNode right;//当前节点的右子树
TreeNode root;//根节点
//实现各个变量的get,set方法
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public TreeNode getLeft(TreeNode left) {
return left;
}
public void setLeft(TreeNode left) {
this.left = left;
}
public TreeNode getRight(TreeNode right) {
return right;
}
public void setRight(TreeNode right) {
this.right = right;
}
public TreeNode getRoot(TreeNode root) {
return root;
}
public void setRoot(TreeNode root) {
this.left = root;
}
public TreeNode(int data) {
this.data = data;
}
public TreeNode() {
}
}
分块查找和哈希查找待更