Java 容器 & 泛型:四、Colletions.sort 和 Arrays.sort 的算法
Writer:BYSocket(泥沙砖瓦浆木匠)
微博:BYSocket
豆瓣:BYSocket
本来准备讲 Map集合 ,还是喜欢学到哪里总结吧。最近面试期准备准备,我是一员,成功被阿里在线笔试秒杀回绝。平常心,继续努力。这次带来 Collections 和 Arrays 类中的经典算法剖析。
一、Colletions和Arrays
Collentions 此类完全是服务容器的”包装器“。提供了一些操作或者返回容器的静态方法。而Arrays是用来操作数组的各种方法。其中它们的联系在于其中的Sort方法,也就是这次博客的主题。
二、插入,快速、归并基本算法
① 插入排序
{a1},{a2,a3,a4,…,an}}
{{a1⑴,a2⑴},{a3⑴,a4⑴ …,an⑴}}
…
{{a1(n-1),a2(n-1) ,…},{an(n-1)}}
原理及记忆方法:每次处理就是将无序数列的第一个元素与有序数列的元素从后往前逐个进行比较,找出插入位置,将该元素插入到有序数列的合适位置中。这通俗的是找座位思想。Java版实现如下
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
import java.util.Arrays;public class InsertionSort{ public static void main(String[] args) { int[] intA = new int[]{2,1,3,4,6,7,5}; System.out.println(Arrays.toString(intA)); insertionSort(intA); System.out.println(Arrays.toString(intA)); } public static void insertionSort(int[] a) { int p,right; int temp; for (p = 0; p < a.length; p++) { temp = a[p]; /** * 将a[p]值往左侧有序列比较,插入。 */ for (right = p; right > 0 && a[right-1] > temp ; right--) a[right] = a[right-1];// 置换 a[right] = temp; } }} |
右键,run一下可以看到控制台结果:
|
1
2
|
[2, 1, 3, 4, 6, 7, 5][1, 2, 3, 4, 5, 6, 7] |
② 快速排序
![]()
快排是基于分治策略的算法,不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。 Java版实现如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
package javaBasic.algorithm;import java.util.Arrays;public class QuickSort{ public static void main(String[] args) { int[] intA = new int[]{2,1,3,4,6,7,5}; System.out.println(Arrays.toString(intA)); //middleSort(intA, 0, intA.length - 1); //System.out.println(Arrays.toString(intA)); sort(intA, 0, intA.length - 1); System.out.println(Arrays.toString(intA)); } // 快速排序中的一个划分过程 public static int middleSort(int a[] , int left , int right) { int temp = a[left]; // 作为中间轴数 while( left < right) { /** * 从右到左,找到第一个比中间轴数小的,移到左端 */ while( left < right && a[right] > temp ) right--; a[left] = a[right]; /** * 从左到右,找到第一个比中间轴数大的,移到右端 */ while( left < right && a[left] < temp) left++; a[right] = a[left]; } /** * 将中间轴数赋值 */ a[left] = temp; return left; } // 快速排序 public static void sort(int[] a , int left, int right) { if (left < right) { /** * 根据左右索引相同才停止。 * 不同的话,按着分治思想。 * 找到中间轴数,一分为二,以此类推。 */ int middle = middleSort(a, left, right); sort(a, left, middle - 1); sort(a, middle + 1, right); } } } |
记忆方法:分治,就是分工。这里演示的是对分。大量经验数据表面,采用两个枢轴来划分成3份的算法更高效,这就是DualPivotQuicksort。这样也是我们后面讲的JDK源码。右键,run一下可以看到控制台和插入排序一样的结果。
③ 归并排序
![]()
如图,来自百度百科。归并排序也是一种分治思想的算法,之不用快速是对分。归并是一种分解到合并的算法。如下实现方式:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
package javaBasic.algorithm;import java.util.Arrays;public class MergeSort{ public static void main(String[] args) { int[] intA = new int[]{10,4,6,3,8,2,5,7}; System.out.println(Arrays.toString(intA)); mergeSort(intA,0,intA.length-1); System.out.println(Arrays.toString(intA)); } public static void mergeSort(int[] a, int left ,int right) { if (left < right) { int middle = (left + right) / 2; // 中间索引 mergeSort(a, left, middle); // 对左侧数组递归 mergeSort(a, middle+1, right); // 对右侧数组递归 merge(a,left,middle,right); // 归并算法 } } private static void merge(int[] a, int left, int middle, int right) { int [] tmpArr = new int[a.length]; int mid = middle+1; int tmpArrLeft = left;// 记录左侧数组的索引 int tmpLeft = left; /** * 从两个数组中取出小的一部分复制 */ while (left <= middle && mid <= right) { if (a[left] <= a[mid]) tmpArr[tmpArrLeft++] = a[left++]; else tmpArr[tmpArrLeft++] = a[mid++]; } /** * 剩余部分右侧复制 */ while (mid <= right) { tmpArr[tmpArrLeft++] = a[mid++]; } /** * 剩余部分左侧复制 */ while (left <= middle) { tmpArr[tmpArrLeft++] = a[left++]; } /** * 分了再合 */ while(tmpLeft <= right) { a[tmpLeft] = tmpArr[tmpLeft++]; } } } |
结果和上图一样:
|
1
2
|
[10, 4, 6, 3, 8, 2, 5, 7][2, 3, 4, 5, 6, 7, 8, 10] |
三、JDK数则
在此谢谢@江南白衣大哥的文章,对我帮助很大。以下引用的:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
5. JDK7/8中排序算法的改进面试季的同学背一脑袋的插入、归并、冒泡、快排,那,JDK到底看上了哪家的排序算法?Colletions.sort(list) 与 Arrays.sort(T[])Colletions.sort()实际会将list转为数组,然后调用Arrays.sort(),排完了再转回List。而Arrays.sort(),对原始类型(int[],double[],char[],byte[]),JDK6里用的是快速排序,对于对象类型(Object[]),JDK6则使用归并排序。为什么要用不同的算法呢?JDK7的进步到了JDK7,快速排序升级为双基准快排(双基准快排 vs 三路快排);归并排序升级为归并排序的改进版TimSort,一个JDK的自我进化。JDK8的进步再到了JDK8, 对大集合增加了Arrays.parallelSort()函数,使用fork-Join框架,充分利用多核,对大的集合进行切分然后再归并排序,而在小的连续片段里,依然使用TimSort与DualPivotQuickSort。结论JDK团队的努力,从一些简单的New Features / Change List 根本看不到,所以没事升级一下JDK还是好的 |
我也查看了关于算法追踪到DualPivotQuicksort类,但是这类却不在JDK API。(抛出个问题:为什么这个类不出现在API里面?)哈哈,一看作者是Java之父参与写的,瞬间有研究的激情。根据白衣大哥说的,快速排序由双基准排序到三路快速排序。这也是在大量经验数据表面,采用两个枢轴来划分成3份的算法更高效。算法的思想也是分治思想。
下面又看到了一段发人自省的注释:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/** * If the length of an array to be sorted is less than this * constant, Quicksort is used in preference to merge sort. * 当数组长度小于286,为什么快速排序比归并排序好? */ private static final int QUICKSORT_THRESHOLD = 286; /** * If the length of an array to be sorted is less than this * constant, insertion sort is used in preference to Quicksort. * 当数组长度小于47,为什么插入排序比快速排序好? */ private static final int INSERTION_SORT_THRESHOLD = 47; |
为什么?第二个问题,欢迎大神解答。
我的理解:第一,建立在大量经验数据结果。第二,根据算法时间复杂度和空间复杂度。至于深入了解需要大神解答。
JDK排序顺序图如下:
![]()
Writer:BYSocket(泥沙砖瓦浆木匠)
微博:BYSocket
豆瓣:BYSocket
Java 容器 & 泛型:四、Colletions.sort 和 Arrays.sort 的算法的更多相关文章
- Java 容器 & 泛型:五、HashMap 和 TreeMap的自白
Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket Java 容器的文章这次应该是最后一篇了:Java 容器 系列. 今天泥瓦匠聊下 Maps. 一.Ma ...
- 关于Java中Collections.sort和Arrays.sort的稳定性问题
一 问题的提出 关于Java中Collections.sort和Arrays.sort的使用,需要注意的是,在本文中,比较的只有Collections.sort(List<T> ele ...
- Java的数组和list升序,降序,逆序函数Collections.sort和Arrays.sort的使用
list升序,降序,逆序List<Integer>list =new ArrayList<Integer>();//如果list是 5 7 2 6 8 1 41.升序:Coll ...
- Java8 Collections.sort()及Arrays.sort()中Lambda表达式及增强版Comparator的使用
摘要:本文主要介绍Java8 中Arrays.sort()及Collections.sort()中Lambda表达式及增强版Comparator的使用. 不废话直接上代码 import com.goo ...
- Java 容器 & 泛型:六、容器讲到为什么要使用泛型
Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket ArrayList是集合类中无处不在的,泛型也是,泛型对集合类尤其有用.但是为啥要使用泛型?理解好了这 ...
- Java 容器 & 泛型:二、ArrayList 、LinkedList和Vector比较
Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket 继续上一篇的容器文章认识容器,泥瓦匠慢慢带你们走进List的容器解说.今天泥瓦匠想说说 ArrayLi ...
- Java 容器 & 泛型:一、认识容器
Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket 容器是Java语言学习中重要的一部分.泥瓦匠我的感觉是刚开始挺难学的,但等你熟悉它,接触多了,也就“顺 ...
- Java 容器 & 泛型:三、HashSet,TreeSet 和 LinkedHashSet比较
Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket 上一篇总结了下ArrayList .LinkedList和Vector比较,今天泥瓦匠总结下Hash ...
- 5.4 集合的排序(Java学习笔记)(Collections.sort(),及Arrays.sort()底层分析)
1.Comparable接口 这个接口顾名思义就是用于排序的,如果要对某些对象进行排序,那么该对象所在的类必须实现 Comparabld接口.Comparable接口只有一个方法CompareTo() ...
随机推荐
- thymeleaf拆分头部(head)显示异常问题
问题描述: 刚用thymeleaf不久,考虑到公共头部的导入css,js代码,需要拆分. 拆分之后,bootstrap-select下拉多选框出现“样式异常”,本认为是头部拆分问题,css样式未导入成 ...
- Code First的实体继承模式
Entity Framework的Code First模式有三种实体继承模式 1.Table per Type (TPT)继承 2.Table per Class Hierarchy(TPH)继承 3 ...
- gson的特殊用法
1.gson包在处理 字符串转 Map 或者 List 的方法. List memberList = gson.fromJson(str,new TypeToken<List>() {}. ...
- POI导入和导出Excel总结
POI导入和导出Excel总结 POI使用总结 1.POI读取Excel 打开工作簿的方式有以下两种简单的应用,POI读取和输出工作簿文件都可以通过以下两种方式来声明: //通过输入流的方式打开本 ...
- DOTween的基本用法
首先声明一点,不要简单的认为 DOTween 只能用在 Transform 组件上完成一些简单的动画,或者是完成一些 UI 动画,DOTween 的用途是很广的,unity中有很多组件都可以使用 DO ...
- jdk环境变量的设置
一.jdk下载网址 https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 二.环境变 ...
- 【腾讯Bugly干货分享】iOS App 签名的原理
本文来自 WeRead 团队博客: http://wereadteam.github.io/ iOS 签名机制挺复杂,各种证书,Provisioning Profile,entitlements,Ce ...
- 背水一战 Windows 10 (97) - 选取器: CachedFileUpdater
[源码下载] 背水一战 Windows 10 (97) - 选取器: CachedFileUpdater 作者:webabcd 介绍背水一战 Windows 10 之 选取器 CachedFileUp ...
- 【备忘】EntityFramework 6 升级到 EntityFrameworkCore 注意点
正在将一个 .net framework 4.5 的项目升级到 .net core 2.1,其中使用到了 EF6,经历了一些修改: 命名空间的变化基本上可以靠自动提示补充完整,不需要强记. DbQue ...
- Jquery中attr()与prop()的区别
在jQuery中,attr()函数和prop()函数都用于设置或获取指定的属性,它们的参数和用法也几乎完全相同.但是,这两个函数的用处却并不相同.下面我们来详细介绍这两个函数之间的区别. 1.操作对象 ...