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() ...
随机推荐
- Python Day 6
阅读目录: 内容回顾: 深浅拷贝: 元组: 字典 集合 ##内容回顾 #1.数字类型 int | float | bool | complex #2.字符串 #常规操作: -- 索 ...
- python 基础 ------字符串的调用详解(1)
Python 字符串的的调用方法~~~ 废话不多说直接奔主题 >>>>>>>>>>>>>>>>> ...
- h3c acl配置一列
acl number 3004 rule 0 permit ip source 10.2.1.4 0 rule 1 deny ip source 192.168.1.91 0 rule 2 deny ...
- 值得推荐的C/C++框架和库 (真的很强大)〔转〕
http://m.blog.csdn.net/article/details?id=42541419
- 【转】mysqldump与innobackupex知多少
作者:罗小波 [目录] 1. 先看mysqldump 1.1 mysqldump备份过程解读 1.2 mysqldump备份过程中的关键步骤 1.2.1 FLUSH TABLES和FLUSH TABL ...
- 20155205 郝博雅 Exp4 恶意代码分析
20155205 郝博雅 Exp4 恶意代码分析 一.实验目标 1.监控你自己系统的运行状态,看有没有可疑的程序在运行. 2.分析一个恶意软件,就分析Exp2或Exp3中生成后门软件:分析工具尽量使用 ...
- java中的抽象类的作用
抽象函数的作用有很多,我就举一个例子,(mars老师的例子): 打印机: 父类---Printer 子类---HBPrinter 子类----CanonPrinter 测试类----Test //定义 ...
- Spring aop框架使用的jar包
除了前两个jar包,后面的jar包spring框架包中都有,前两个jar包的下载地址:https://pan.baidu.com/s/1L-GLGT1c8vnwFwqLxzzZuw
- 乘法器的Verilog HDL实现(转载)
原文地址:http://www.cnblogs.com/shengansong/archive/2011/05/23/2054401.html 1. 串行乘法器 两个N位二进制数x.y的乘积用简单的方 ...
- grep 笔记
-a :将 binary 文件以 text 文件的方式搜寻数据-c :计算找到 '搜寻字符串' 的次数-i :忽略大小写的不同,所以大小写视为相同-n :顺便输出行号-v :反向选择,亦即显示出没有 ...