Java集合框架之算法

本文详细介绍了Java集合框架中的查找和排序算法,包括二分查找法、双轴快速排序、TimSort以及堆排序。重点讲解了TimSort的内部工作原理,它是如何结合二分插入排序和归并排序来实现稳定排序的。此外,还提到了Java 8引入的并行排序算法以及各种排序算法的性能对比和应用场景。
摘要由CSDN通过智能技术生成

Java集合框架中,还有两个工具类值得关注:Collections和Arrays。对于一个集合或数组,有很多必要的操作,比如查找、排序、反转、随机打乱、求最大值最小值等等。其中查找、排序都要用到合适的算法,以便快速完成这些操作。

1. 查找

Collections和Arrays中的查找都是二分查找法。二分查找法基于一个按升序排列的元素列表,分为三部分:中值前列表、中值、中值后列表。如果是中值,直接返回,如果元素比中值大,就把“中值后列表”变成新列表,反之,把“中值前列表”变成新列表。然后对新列表继续上述操作。一直循环下去,找到为止。在最坏的情况下,需要查找log2n次,所以二分查找法的时间复杂度是O(logn)。

因为二分查找法是基于一个按升序排列的元素列表,所以Collections中的二分查找法只针对List。List的实现又分为是不是RandomAccess。RandomAccess是一个标记接口,ArrayList有实现这个标记,而LinkedList没有实现这个标记。这两者的二分查找实现有细微的区别,如果是RandomAccess,就会基于数组下标进行二分查找,如果不是,就要依赖外部迭代器进行二分查找,显然通过数组下标查找效率会更高。

2. 排序

Collections的排序方法都是调用Arrays的排序方法。对于Arrays中的排序方法,分为两类,一类是基本数据类型,一类是对象类型。对于基本数据类型采用的是双轴快速排序(Dual-Pivot QuickSort),是一种改进的快速排序算法,早期版本是相对传统的快速排序。对于对象类型则是使用TimSort,思想上也是一种归并和二分插入排序(binarySort)结合的优化排序算法。TimSort 并不是 Java 的独创,简单说它的思路是查找数据集中已经排好序的分区(这里叫 run),然后合并这些分区来达到排序的目的。

TimSort的大致逻辑是,如果元素个数在32个以内,就用二分插入排序;如果多于32个元素,就采取结合二分插入排序和归并排序的办法。这就综合了两种排序算法在不同场景下的优势。两种算法有何不同,在本文第三节就讲到。

另外,Java 8 引入了并行排序算法(直接使用 parallelSort 方法),这是为了充分利用现代多核处理器的计算能力,底层实现基于 fork-join 框架,当处理的数据集比较小的时候,差距不明显,甚至还表现差一点;但是,当数据集增长到数万或百万以上时,提高就非常大了,具体还是取决于处理器和系统环境。

排序算法仍然在不断改进,最近双轴快速排序实现的作者提交了一个更进一步的改进,历时多年的研究,目前正在审核和验证阶段。根据作者的性能测试对比,相比于基于归并排序的实现,新改进可以提高随机数据排序速度提高 10%~20%,甚至在其他特征的数据集上也有几倍的提高。

3. 常见的排序算法

排序分内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。通常我们指的排序是内部排序。内部排序有很多,从大的层面可以分为两类:一类是比较排序(冒泡排序,选择排序,插入排序,归并排序,堆排序,快速排序……),一类是非比较排序(计数排序,基数排序,桶排序……)。

各类排序算法的性能对比:

 

从上表可以看出,排序算法还有一个稳定性的概念:如果Ai = Aj,排序前Ai在Aj之前,排序后Ai还在Aj之前,则称这种排序算法是稳定的。通俗地讲就是保证排序前后两个相等的数的相对顺序不变。需要注意的是,排序算法是否为稳定的最终是由具体算法决定的,不

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值