菜鸟笔记之数据结构(7)

数据结构与算法—查找算法


声明:以下都是学的尚硅谷网课所记的笔记。可能会有一些错误,发现了会修改。

查找算法主要有顺序查找(线性查找),二分查找(折半查找),插值查找斐波那契查找

线性查找

顺序查找是按照序列原有顺序对数组进行遍历比较查询的基本查找算法。对于任意一个序列和一个给定的元素,将给定元素与序列中元素依次比较,直到找出与给定关键字相同的元素,或者将序列中的元素与其都比较完为止。

二分查找

二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。

思路: 首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

  1. 先确定数组的中间下标。mid = (left + right)/2
  2. 让查找的数findVal与arr[mid]比较。
    (1)findVal > arr[mid],则查找的数位于mid右边,需要递归的向右查找。
    (2)findVal < arr[mid],数位于mid左边,向左查询。
    (3)findVal == arr[mid],返回。
  3. 结束条件:找到findVal结束递归,或当left > right就退出。
public static int binarySearch(int[] arr,int left,int right,int findVal){
	//当left>right时,说明递归整个数组但是没有找到
	if(left > right){
		return -1;
	}
	int mid = (left + right)/2;
	int midVal = arr[mid];
	if(findVal > midVal){ //向右递归
		return binarySearch(arr,mid+1,right,findVal);
	} else if(findVal < midVal){ //向左递归
		return binarySearch(arr,left,mid-1,findVal);
	} else { //找到了
		return mid;
	}
}

插值查找

插值查找,有序表的一种查找方式。插值查找是根据查找关键字与查找表中最大最小记录关键字比较后的查找方法。类似于二分查找,不同的是mid值的选择不同(自适应选择,提高查找效率),同时也要求数组为有序的。

二分查找:mid = (low + high)/2 = low + (high - low)/2 -> 插值查找:mid = low + (high - low) × (findVal - arr[low]) / arr[high]-arr[low]

public static int insertValueSearch(int[] arr, int left, int right, int findVal){
	if(left > right || findVal < arr[0] || findVal > arr[arr.length-1]){
		return -1;
	}
	//计算mid
	int mid = left +(right - left) * (findVal - arr[left]) / arr[right]-arr[left];
	int midVal = arr[mid];
	if(findVal > midVal){ //向右递归
		return insertValueSearch(arr, mid+1, right, findVal);
	} else if(findVal < midVal){ //向左递归
		return insertValueSearch(arr, left, mid-1, findVal);
	} else { //找到了
		return mid;
	}
}

对数据量大,数据分布比较均匀的查找表来说,插值查找速度快,如果数据分布不均匀则不一定比二分查找效率好。

斐波那契查找

也叫黄金分割查找算法,是在二分查找的基础上根据斐波那契数列进行分割的,也是针对有序数组的。 黄金分割点指的是把一条线段分成两部分,使其中一部分与全长之比,等于另一部分与这部分之比(大约0.618)。

思想: 在斐波那契数列找一个等于略大于查找表中元素个数的数F[n],将原查找表扩展为长度为F[n] (如果要补充元素,则补充重复最后一个元素,直到满足F[n]个元素),完成后进行斐波那契分割,即F[n]个元素分割为前半部分F[n-1]个元素,后半部分F[n-2]个元素,找出要查找的元素在哪一部分并递归,直到找到。

与前两种查找算法相似,仅仅是中间节点mid的位置不同,mid = low + F[n-1] - 1 ,这样取得的mid就是位于黄金分割点附近。n怎么找? 当查找表中元素个数小于等于斐波那契数列的数F[n]时停止。

原理可参考 斐波那契查找算法原理

public final static int MAXSIZE = 20;
//斐波那契数列
public static int[] fibonacci() {
    int[] f = new int[MAXSIZE];
    int i = 0;
    f[0] = 1;
    f[1] = 1;
    for (i = 2; i < MAXSIZE; i++) {
        f[i] = f[i - 1] + f[i - 2];
    }
    return f;
}
 
public static int fibonacciSearch(int[] data, int findVal) {
    int low = 0;
    int high = data.length - 1;
    int mid = 0;
    int k = 0;
    int i = 0;
    // 获取斐波那契数列
    int[] f = fibonacci();
    //获取斐波那契分割数值下标
    while (data.length > f[k] - 1) {
        k++;
    }
    
    //序列补充至f[k]个元素
    //补充的元素值为最后一个元素的值
    int[] temp = new int[f[k] - 1];
    for (int j = 0; j < data.length; j++) {
        temp[j] = data[j];
    }
    for (i = data.length; i < f[k] - 1; i++) {
        temp[i] = temp[high];
    }

    //开始查找
    while (low <= high) {
        // low:起始位置
        mid = low + f[k - 1] - 1;
 
        if (temp[mid] > findVal) {
            // 查找前半部分,高位指针左移动
            high = mid - 1;
            // (全部元素) = (前半部分)+(后半部分)
            //   f[k]  =  f[k-1] + f[k-2],所以 k = k-1
            k = k - 1;
        } else if (temp[mid] < findVal) {
            // 查找后半部分,高位指针右移动
            low = mid + 1;
            // (全部元素) = (前半部分)+(后半部分)
            //   f[k]  =  f[k-1] + f[k-2],所以 k = k-2
            k = k - 2;
        } else {
            //找到相应的位置
            if (mid <= high) {
                return mid;
            } else {
                //出现这种情况是查找到补充的元素
                //而补充的元素与high位置的元素一样
                return high;
            }
        }
    }
    return -1;
}

---------------------------- 个人学习笔记----------------------------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值