首页 > 编程语言 >Java面试要点54 - Java List的二分查找算法

Java面试要点54 - Java List的二分查找算法

时间:2024-12-02 09:28:59浏览次数:9  
标签:Java String int 54 List mid 查找 public left

在这里插入图片描述

文章目录


一、引言

在Java程序开发中,查找操作是一个非常基础且关键的算法需求。其中,二分查找(Binary Search)因其O(log n)的时间复杂度,在大规模有序数据集的查找中具有显著优势。

二、二分查找的基本原理

二分查找算法的核心思想是通过将有序数组不断平分,逐步缩小查找范围来定位目标元素。这种"分而治之"的策略使得每次查找都可以排除掉一半的搜索空间,从而实现对数级的时间复杂度。需要特别注意的是,二分查找的前提条件是操作的数据集必须是有序的。

public class BinarySearchBasic {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 3, 5, 7, 9, 11, 13, 15, 17);
        
        // 基本二分查找实现
        int target = 7;
        int index = basicBinarySearch(numbers, target);
        System.out.println("元素 " + target + " 的位置: " + index);
    }
    
    public static int basicBinarySearch(List<Integer> list, int target) {
        if (list == null || list.isEmpty()) {
            return -1;
        }
        
        int left = 0;
        int right = list.size() - 1;
        
        while (left <= right) {
            int mid = left + (right - left) / 2;  // 避免整数溢出
            int midVal = list.get(mid);
            
            if (midVal == target) {
                return mid;
            } else if (midVal < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        
        return -1;  // 未找到目标元素
    }
}

三、Java Collections工具类中的二分查找

Java Collections框架提供了现成的二分查找实现,通过Collections.binarySearch()方法可以直接进行查找操作。这个方法不仅支持基本数据类型,还支持自定义对象的查找。

public class CollectionsBinarySearch {
    static class Student implements Comparable<Student> {
        private String name;
        private int score;
        
        public Student(String name, int score) {
            this.name = name;
            this.score = score;
        }
        
        @Override
        public int compareTo(Student other) {
            return Integer.compare(this.score, other.score);
        }
        
        @Override
        public String toString() {
            return String.format("Student{name='%s', score=%d}", name, score);
        }
    }
    
    public static void main(String[] args) {
        // 对基本类型进行二分查找
        List<Integer> numbers = Arrays.asList(2, 4, 6, 8, 10, 12, 14);
        int numberIndex = Collections.binarySearch(numbers, 8);
        System.out.println("数字8的索引位置: " + numberIndex);
        
        // 对自定义对象进行二分查找
        List<Student> students = Arrays.asList(
            new Student("张三", 75),
            new Student("李四", 82),
            new Student("王五", 88),
            new Student("赵六", 92)
        );
        
        Student targetStudent = new Student("查找目标", 88);
        int studentIndex = Collections.binarySearch(students, targetStudent);
        System.out.println("分数为88的学生索引位置: " + studentIndex);
    }
}

四、自定义比较器的二分查找实现

在实际开发中,我们经常需要按照特定的规则进行查找。Java允许我们通过自定义Comparator来实现这一需求。这种方式特别适合那些没有实现Comparable接口的类,或者需要按照不同于自然顺序的方式进行查找的场景。

public class CustomComparatorSearch {
    static class Product {
        private String name;
        private double price;
        private int stock;
        
        public Product(String name, double price, int stock) {
            this.name = name;
            this.price = price;
            this.stock = stock;
        }
        
        // getter方法
        public String getName() { return name; }
        public double getPrice() { return price; }
        public int getStock() { return stock; }
        
        @Override
        public String toString() {
            return String.format("Product{name='%s', price=%.2f, stock=%d}", 
                               name, price, stock);
        }
    }
    
    public static void main(String[] args) {
        List<Product> products = Arrays.asList(
            new Product("商品A", 29.99, 100),
            new Product("商品B", 49.99, 50),
            new Product("商品C", 99.99, 75),
            new Product("商品D", 149.99, 25)
        );
        
        // 按价格查找
        Comparator<Product> priceComparator = 
            Comparator.comparing(Product::getPrice);
        
        Product targetPrice = new Product("", 99.99, 0);
        int priceIndex = Collections.binarySearch(
            products, targetPrice, priceComparator);
        
        System.out.println("价格为99.99的商品索引: " + priceIndex);
        
        // 按库存查找
        Comparator<Product> stockComparator = 
            Comparator.comparing(Product::getStock);
            
        Product targetStock = new Product("", 0, 75);
        int stockIndex = Collections.binarySearch(
            products, targetStock, stockComparator);
            
        System.out.println("库存为75的商品索引: " + stockIndex);
    }
}

五、处理特殊情况

在实际应用中,需要考虑多种特殊情况,如处理重复元素、处理未找到的情况、处理边界值等。

下面的代码展示了如何处理这些特殊情况。

public class SpecialCaseHandler {
    public static void main(String[] args) {
        // 处理重复元素
        List<Integer> numbersWithDuplicates = 
            Arrays.asList(1, 3, 3, 3, 5, 7, 7, 9);
            
        // 查找第一个出现的位置
        int firstOccurrence = findFirstOccurrence(numbersWithDuplicates, 3);
        System.out.println("3第一次出现的位置: " + firstOccurrence);
        
        // 查找最后一个出现的位置
        int lastOccurrence = findLastOccurrence(numbersWithDuplicates, 3);
        System.out.println("3最后一次出现的位置: " + lastOccurrence);
    }
    
    public static int findFirstOccurrence(List<Integer> list, int target) {
        int left = 0;
        int right = list.size() - 1;
        int result = -1;
        
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (list.get(mid) == target) {
                result = mid;
                right = mid - 1;  // 继续向左搜索
            } else if (list.get(mid) < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        
        return result;
    }
    
    public static int findLastOccurrence(List<Integer> list, int target) {
        int left = 0;
        int right = list.size() - 1;
        int result = -1;
        
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (list.get(mid) == target) {
                result = mid;
                left = mid + 1;  // 继续向右搜索
            } else if (list.get(mid) < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        
        return result;
    }
}

六、性能优化与最佳实践

对于频繁查找操作的场景,应当维护数据的有序性,避免重复排序带来的性能开销。如果数据集经常变动,可以考虑使用TreeSet或TreeMap等自平衡的数据结构。在实现自定义比较器时,应确保比较操作的性能开销尽可能小。对于复杂对象的比较,可以缓存比较字段的值,避免重复计算。

public class OptimizedBinarySearch {
    static class CachedComparator implements Comparator<String> {
        private final Map<String, Integer> cache = new HashMap<>();
        
        private int getComplexValue(String str) {
            return cache.computeIfAbsent(str, 
                k -> k.chars().sum() * k.length());  // 复杂计算
        }
        
        @Override
        public int compare(String s1, String s2) {
            int val1 = getComplexValue(s1);
            int val2 = getComplexValue(s2);
            return Integer.compare(val1, val2);
        }
    }
    
    public static void main(String[] args) {
        List<String> strings = Arrays.asList(
            "apple", "banana", "cherry", "date", "elderberry");
        
        CachedComparator comparator = new CachedComparator();
        Collections.sort(strings, comparator);  // 先排序
        
        // 执行多次查找
        String target = "cherry";
        int index = Collections.binarySearch(strings, target, comparator);
        System.out.println("查找结果索引: " + index);
    }
}

七、总结

二分查找是一种高效的查找算法,它在有序数据集中能实现O(log n)的时间复杂度。Java通过Collections框架提供了内置的二分查找实现,同时也支持通过自定义比较器来满足特定的查找需求。在日常开发中,合理使用二分查找算法不仅能提升程序性能,也能让代码更加简洁优雅。

标签:Java,String,int,54,List,mid,查找,public,left
From: https://blog.csdn.net/weixin_55344375/article/details/144174489

相关文章

  • Java 并发集合容器
    在多线程编程中,高效地访问和操作数据结构是一个重要的挑战。Java提供了并发集合容器(ConcurrentCollectionContainers)来解决这个问题。这些容器通过内部的同步机制实现了线程安全,使得开发者无需显式同步代码就能在并发环境下安全使用。本文将详细介绍Java并发集合容器中......
  • 分类算法学业警示管理系统|Java|SSM|JSP| 前后端分离
    【重要1⃣️】前后端源码+万字文档+部署文档            【包含内容】【一】项目提供非常完整的源码注释【二】相关技术栈文档【三】源码讲解视频                     【其它服务】【一】可以提供远程......
  • Java基础39道常见面试题及详细答案
    最近看到网上流传着,各种面试经验及面试题,往往都是一大堆技术题目贴上去,而没有答案。为此我业余时间整理了,Java基础常见的40道常见面试题,及详细答案,望各路大牛,发现不对的地方,不吝赐教,留言即可。八种基本数据类型的大小,以及他们的封装类引用数据类型Switch能否用string做参数e......
  • Java基础全解:构建扎实编程技能
    文章目录1.HelloWorld程序深入解析:2.数据类型深入解析:3.条件判断深入解析:4.循环结构深入解析:5.数组深入解析:6.方法定义与调用深入解析:1.HelloWorld程序深入解析:类声明:publicclassHelloWorld定义了一个公共类。public关键字意味着这个类可以......
  • 【娱乐项目】基于批处理脚本与JavaScript渲染视频列表的Web页面
    Demo介绍一个简单的视频播放器应用,其中包含了视频列表和一个视频播放区域。用户可以通过点击视频列表中的项来选择并播放相应的视频,播放器会自动播放每个视频并在播放完毕后切换到下一个视频。本项目旨在通过自动化脚本和动态网页渲染,帮助用户快速生成并展示本地视频资源(......
  • javaweb
    1,静态web是什么(网页)2,动态web是什么Server和Servlet的区别主要在于它们的功能和角色。Server通常指的是一个提供服务的程序或者系统,能够响应客户端的请求并返回响应。而Servlet是一个在Server端运行的程序,专门用于处理用户请求并生成动态的Web内容。Server:Server是提供某种服......
  • JAVA开源毕业设计 医护人员排班系统 Vue.JS+SpringBoot+MySQL
    本文项目编号T014,文末自助获取源码\color{red}{T014,文末自助获取源码}......
  • JAVA开源毕业设计 美容院管理系统 Vue.JS+SpringBoot+MySQL
    本文项目编号T012,文末自助获取源码\color{red}{T012,文末自助获取源码}......
  • 执行SQL发生错误!错误:Unknown column 'sortdesc' in 'field list'
    根据错误信息,您遇到的问题是因为SQL语句中引用了一个不存在的列 sortdesc。以下是几种可能的解决方案:检查列名:确认SQL语句中引用的列名 sortdesc 是否正确。可能是拼写错误或列名不匹配。使用 DESCRIBEtable_name; 或 SHOWCOLUMNSFROMtable_name; 查看表的结......
  • 高级java每日一道面试题-2024年12月01日-JVM篇-你知道哪些JVM性能调优参数?
    如果有遗漏,评论区告诉我进行补充面试官:你知道哪些JVM性能调优参数?我回答:在Java高级面试中,JVM性能调优是一个非常重要的主题。了解JVM的性能调优参数可以帮助你更好地管理和优化应用程序的性能。以下是一些常见的JVM性能调优参数及其详细解释:1.堆内存相关参数-Xms......