Java尚硅谷数据结构与算法学习记录(9)-查找算法

顺序(线性查找)(可查有序也可查无序)

顺序查找,又称为线性查找,主要用于在线性表中进行查找。
顺序查找 就是:遍历序列 逐一比对 找到就返回即可
代码实现:

package com.algorithm.search;

import java.util.ArrayList;
import java.util.List;

public class SeqSearch {
    public static void main(String[] args) {
        int[] arr = {1, 3, 2, 4, 6, 9, 8, 7, 1};
        seqSearch2(arr, 1);
        int index = seqSearch(arr, 1);
        if (index == -1) {
            System.out.println("没找到您要找的数据");
        } else {
            System.out.println("您要找的数据在数组中的下标为:" + index);
        }
    }

    //顺序(线性)查找:逐一比对 发现有相同值就返回下标
    //只有一个查找项
    public static int seqSearch(int[] arr, int value) {
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == value) {
                return i;
            }
        }
        return -1;
    }

    //有多个相同的查找项
    public static List<Integer> seqSearch2(int[] arr, int value) {
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == value) {
                list.add(i);
            }
        }
        for (Integer index : list) {
            System.out.println("您要找的数据在数组中的下标为:" + index);
        }
        return null;
    }
}

二分(折半)查找(只可查有序)

二分查找前提是表是按递增或递减顺序的规范表
二分查找的思路分析

  1. 首先确定该数组的中间的下标
    mid = (left + right) / 2
  2. 然后让需要查找的数 findVal 和 arr[mid] 比较
  3. 1 findVal > arr[mid] , 说明你要查找的数在mid 的右边, 因此需要递归的向右查找
    2.2 findVal < arr[mid], 说明你要查找的数在mid 的左边, 因此需要递归的向左查找
    2.3 findVal == arr[mid] 说明找到,就返回

什么时候我们需要结束递归

  1. 找到就结束递归
  2. 递归完整个数组,仍然没有找到findVal ,也需要结束递归 当 left > right 就需要退出

代码实现:

package com.algorithm.search;

import java.util.ArrayList;

public class BinarySearch {
    //    二分查找使用前提:数组必须是有序的
    public static void main(String[] args) {
       /* int[] arr = {1, 8, 10, 89, 1000, 1234};
        int index = binarySearch(arr, 0, arr.length-1, 88);
        if (index == -1) {
            System.out.println("没找到您要找的数据");

        } else {
            System.out.println("您要找的数据在数组中的位置是:" + index);
        }*/
        int[] arr = {1, 8, 10, 89, 1000,1000,1000, 1234};
        ArrayList<Integer> res = binarySearch2(arr, 0, arr.length-1, 1000);
        System.out.println("res="+res);

    }

    //   只有一个查找项
    public static int binarySearch(int[] arr, int left, int right, int findVal) {
        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;
        }
    }

    //    有多个相同的查找项
    public static ArrayList<Integer> binarySearch2(int[] arr, int left, int right, int findVal) {
        if (left > right) {//递归结束的条件
            return new ArrayList<Integer>();
        }
        int mid = (left + right) / 2;
        int midVal = arr[mid];
        if (findVal > midVal) {
            return binarySearch2(arr, mid + 1, right, findVal);//向右递归
        } else if (findVal < midVal) {
            return binarySearch2(arr, left, mid - 1, findVal);//向左递归
        } else {
                    /*思路分析:
                        1、当查找到mid索引值后 向左右两边扫描看是否有多个相同查找值
                        2、向mid索引值的左边扫描,若存在满足findVal的值则将其加入集合中
                        3、向mid索引值的右边扫描,若存在满足findVal的值则将其加入集合中
                        4、不要忘了把mid索引处的数据也加入集合中  最后返回集合即可
                    */
            ArrayList<Integer> list = new ArrayList<>();
            int temp = mid - 1;
            while (true) {
                if (temp < 0 || arr[temp] != findVal) {
                    break;
                } else {
                    list.add(temp);
                    temp--;//temp左移继续扫描
                }
            }
            list.add(mid);
            temp = mid + 1;
            while (true) {
                if (temp > arr.length - 1 || arr[temp] != findVal) {
                    break;
                } else {
                    list.add(temp);
                    temp++;//temp右移继续扫描
                }
            }
            return list;
        }
    }
}

插值查找(只可查有序)

插值查找原理介绍:

插值查找算法类似于二分查找,不同的是插值查找每次从自适应mid处开始查找。
将折半查找中的求mid 索引的公式 , low 表示左边索引left, high表示右边索引right.key 就是前面我们讲的 findVal
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
对应的代码公式:int mid = left + (right – left) * (findVal – arr[left]) / (arr[right] – arr[left])
在这里插入图片描述

代码实现:

package com.algorithm.search;

public class InsertValueSearch {
    public static void main(String[] args) {
       /* int[] arr = new int[100];
        for (int i = 0; i < 100; i++) {
            arr[i] = i + 1;
        }*/
        int[] arr = {1, 8, 10, 89, 1000,1000,1000, 1234};
        int index = insertValSearch(arr, 0, arr.length-1, 1234);
        System.out.println("index="+index);
    }

    //插值查找  要求数组有序
    public static int insertValSearch(int[] arr, int left, int right, int findVal) {
        //findVal < arr[0] || findVal > arr[arr.length - 1] 必须有 防止mid越界
        if (left > right || findVal < arr[0] || findVal > arr[arr.length - 1]) {
            return -1;
        }
        int mid = left + (right - left) * (findVal - arr[left]) / (arr[right] - arr[left])  ;
        int midVal = arr[mid];
        if (findVal > midVal) {
            return insertValSearch(arr, mid + 1, right, findVal);//向右递归
        } else if (findVal < midVal) {
            return insertValSearch(arr, left, mid - 1, findVal);//向左递归
        } else {
            return mid;
        }
    }
}

插值查找注意事项:

1、对于数据量较大,关键字分布比较均匀的查找表来说,采用插值查找, 速度较快.
2、关键字分布不均匀的情况下,该方法不一定比折半查找要好。

斐波那契(黄金分割法)查找(只可查有序)

利用斐波那契数列配合找到黄金分割点 然后再查找
在这里插入图片描述
代码实现:

package com.algorithm.search;

import java.util.Arrays;

public class FibonacciSearch {
    public static int maxSzie = 20;

    public static void main(String[] args) {
        int[] arr = {1, 8, 10, 89, 1000, 1234};
        int index= fibSearch(arr,1234);
        System.out.println("您要找的数据的下标是:"+index);
    }

    //获得斐波那契数列
    //非递归方式
    public static int[] fib() {
        int[] fib = new int[maxSzie];
        fib[0] = 1;
        fib[1] = 1;
        for (int i = 2; i < maxSzie; i++) {
            fib[i] = fib[i - 1] + fib[i-2];
        }
        return fib;
    }

    public static int fibSearch(int[] arr, int value) {
        int low = 0;
        int high = arr.length - 1;
        int k = 0;//表示斐波那契分割数值的下标
        int mid = 0;
        int fib[] = fib();//获取到斐波那契数列
        //获取到斐波那契额分割数值的下标
        while (arr.length > fib[k] - 1) {
            k++;
        }//退出循环时说明已经找到斐波那契分割的数值即fib[k]  fib[k]的值表示 要使用此方法所需的 元素的个数
        //因为fib[k]可能大于arr的长度 所以 这里构建一个新数组 补齐所需的元素
        // copyOf(oringinal, int newlength) oringinal:原数组      newlength:复制数组的长度
        int[] temp = Arrays.copyOf(arr, fib[k]);//不足的地方自动填充0
        //此方法实际应该在不足的地方填充arr的最后一个数据的值
        for (int i = high + 1; i < fib[k]; i++) {
            temp[i] = arr[high];
        }
        //开始查找(非递归)
        while (low <= high) {
            mid = low + fib[k - 1] - 1;
            if (value < temp[mid]) {//向数组左边查找
                high = mid - 1;
                //fib[k]=fib[k-1]+fib[k-2] 因为要找的值小于temp[mid] 所以去fib[k-1]这部分继续找
                //所以k-- 即 下次循环mid=low+fib[k-1-1]-1
                k--;
            } else if (value > temp[mid]) {//向数组右边查找
                low = mid + 1;
                //fib[k]=fib[k-1]+fib[k-2] 因为要找的值大于于temp[mid] 所以去fib[k-2]这部分继续找
                //所以k-=2 即 下次循环mid=low+fib[k-2-1]-1
                k -= 2;
            } else {
                //找到的话需要确定返回的下标
                if (mid <= high) return mid;
                else return high;
            }

        }
        return -1;
    }
}

<think>嗯,用户想了解Excel中的VLOOKUP函数的用法和参数含义。首先,我需要回忆一下VLOOKUP的基本结构。VLOOKUP是垂直查找函数,用于在表格的首列查找指定的值,然后返回该行中指定列的数据。它的四个参数分别是查找值、表格范围、列索引号和匹配模式。 接下来,我得确认每个参数的具体作用。第一个参数是lookup_value,也就是用户要查找的值,比如产品ID或者姓名。第二个参数是table_array,即查找的范围,这里要注意的是,查找值必须位于这个范围的第一列,否则函数无法正确工作。第三个参数是col_index_num,也就是用户想要返回的数据在表格范围中的第几列,这个列数是从表格范围的第一列开始算起的,不是整个工作表的列。第四个参数是range_lookup,决定是精确匹配还是近似匹配,通常用FALSE或0来指定精确匹配,避免错误。 然后,用户可能需要一个具体的例子来理解如何使用。比如,假设有一个产品价格表,用户想根据产品ID查找对应的价格。这时候,VLOOKUP就可以在ID列查找,然后返回价格列的数据。同时,要提醒用户注意表格范围最好使用绝对引用,比如$A$2:$C$100,这样在拖动公式时范围不会变化。 可能遇到的问题也需要考虑。比如,如果查找值不在表格的第一列,或者列索引号超过了表格的列数,函数会返回错误。此外,数据格式不一致也可能导致问题,比如查找值是数字,而表格中是文本格式的数字,这时候需要统一格式。还有,当出现#N/A错误时,可能是查找值不存在,或者匹配模式设置不正确,需要检查参数是否正确。 用户可能还会问到如何避免常见的错误,比如部分数据匹配出错的情况。这时候需要检查是否有多余的空格,或者数据格式不一致,或者表格范围没有锁定导致拖动时偏移。此外,XLOOKUP作为VLOOKUP的升级版,可能在某些情况下更方便,比如可以向左查找或者返回多列数据,这也是可以提及的内容。 最后,整理步骤,从基础语法到参数说明,再到具体案例,逐步引导用户理解如何使用VLOOKUP函数。同时,提供常见错误和解决方法,帮助用户在实际应用中避免问题。如果有必要,还可以比较VLOOKUP和其他查找函数的区别,比如HLOOKUP或XLOOKUP,但根据用户的问题,主要集中在VLOOKUP本身即可。</think>### Excel VLOOKUP函数详解 #### 一、基础语法与参数说明 VLOOKUP函数的语法为: $$=VLOOKUP(lookup\_value, table\_array, col\_index\_num, [range\_lookup])$$ 包含4个参数: 1. **lookup_value**(必填):要查找的值(如单元格引用或具体值) 2. **table_array**(必填):包含数据的表格范围(必须包含查找列和返回列) 3. **col_index_num**(必填):返回值所在列的序号(从table_array第一列开始计数) 4. **range_lookup**(可选):匹配类型 - `TRUE`/`1`:近似匹配(默认值,需数据升序排列) - `FALSE`/`0`:精确匹配(常用选项) [^1][^2] #### 二、使用步骤演示(工资表查询案例) 假设需要根据员工编号查询工资: 1. 建立查询单元格(如`B12`) 2. 输入公式: ```excel =VLOOKUP(A12, $A$2:$D$100, 4, 0) ``` - `A12`:待查询的员工编号 - `$A$2:$D$100`:锁定数据区域(绝对引用) - `4`:返回第4列(工资列) - `0`:精确匹配 [^2][^3] #### 三、常见错误与解决方法 | 错误现象 | 原因 | 解决方案 | |---------|------|---------| | #N/A | 查找值不存在 | 检查数据源或改用`IFERROR`容错 | | #REF! | 列序号超出范围 | 确认col_index_num ≤ 表格列数 | | 部分匹配失败 | 数据格式不一致 | 统一数值/文本格式 | | 结果错位 | 表格未锁定 | 使用`$`符号固定区域引用 | [^3][^4] #### 四、进阶技巧 1. **多条件查询**: 使用辅助列合并多个条件字段 ```excel =VLOOKUP(A2&B2, $D$2:$F$100, 3, 0) ``` 2. **通配符匹配**: `"*"`匹配任意字符,`"?"`匹配单个字符 ```excel =VLOOKUP("张*", $A$2:$C$100, 3, 0) ``` 3. **跨表查询**: 引用其他工作表数据 ```excel =VLOOKUP(A2, Sheet2!$A$2:$D$100, 4, 0) ``` [^1][^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值