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 的算法的更多相关文章

  1. Java 容器 & 泛型:五、HashMap 和 TreeMap的自白

    Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket Java 容器的文章这次应该是最后一篇了:Java 容器 系列. 今天泥瓦匠聊下 Maps. 一.Ma ...

  2. 关于Java中Collections.sort和Arrays.sort的稳定性问题

    一 问题的提出   关于Java中Collections.sort和Arrays.sort的使用,需要注意的是,在本文中,比较的只有Collections.sort(List<T> ele ...

  3. Java的数组和list升序,降序,逆序函数Collections.sort和Arrays.sort的使用

    list升序,降序,逆序List<Integer>list =new ArrayList<Integer>();//如果list是 5 7 2 6 8 1 41.升序:Coll ...

  4. Java8 Collections.sort()及Arrays.sort()中Lambda表达式及增强版Comparator的使用

    摘要:本文主要介绍Java8 中Arrays.sort()及Collections.sort()中Lambda表达式及增强版Comparator的使用. 不废话直接上代码 import com.goo ...

  5. Java 容器 & 泛型:六、容器讲到为什么要使用泛型

    Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket ArrayList是集合类中无处不在的,泛型也是,泛型对集合类尤其有用.但是为啥要使用泛型?理解好了这 ...

  6. Java 容器 & 泛型:二、ArrayList 、LinkedList和Vector比较

    Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket 继续上一篇的容器文章认识容器,泥瓦匠慢慢带你们走进List的容器解说.今天泥瓦匠想说说 ArrayLi ...

  7. Java 容器 & 泛型:一、认识容器

    Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket 容器是Java语言学习中重要的一部分.泥瓦匠我的感觉是刚开始挺难学的,但等你熟悉它,接触多了,也就“顺 ...

  8. Java 容器 & 泛型:三、HashSet,TreeSet 和 LinkedHashSet比较

    Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket 上一篇总结了下ArrayList .LinkedList和Vector比较,今天泥瓦匠总结下Hash ...

  9. 5.4 集合的排序(Java学习笔记)(Collections.sort(),及Arrays.sort()底层分析)

    1.Comparable接口 这个接口顾名思义就是用于排序的,如果要对某些对象进行排序,那么该对象所在的类必须实现 Comparabld接口.Comparable接口只有一个方法CompareTo() ...

随机推荐

  1. mongooDb链接javaapi

    mongodb链接有多种:所以不同链接下的api也不太一样. 1.api比较全面 public void query2(){ String mondburl = Config.getInstance( ...

  2. bp代码

    #电池老化率测定的神经网络模型 import tensorflow as tf import numpy as np import matplotlib.pyplot as plt import pa ...

  3. 浅谈React数据流管理

    引言:为什么数据流管理如此重要?react的核心思想就是:UI=render(data),data就是我们说的数据流,render是react提供的纯函数,所以用户界面的展示完全取决于数据层.这篇文章 ...

  4. 不支持find_element_by_name元素定位方法,抛不支持find_element_by_name元素定位方法,会抛如下错误 org.openqa.selenium.InvalidSelectorException: Locator Strategy 'name' is not supported for this session的解决

    appium1.5后不支持find_element_by_name元素定位方法,会抛如下错误 org.openqa.selenium.InvalidSelectorException: Locator ...

  5. XSSearch 说明文档保存

    XSSearch All Packages | 属性 | 方法(函数) 包 XS 继承关系 class XSSearch » XSServer » XSComponent 版本 1.0.0 源代码 s ...

  6. 注入Shellcode并运行攻击

    注入Shellcode并运行攻击 一.实验步骤 1.安装execstack并修改设置 安装execstack apt-get install execstack 设置堆栈可执行 execstack - ...

  7. 1.3if判断语句+while和for循环语句+购物车作业

    1.if 语句 if userame=_usename and password=_password: print("welcome user {name} login..."). ...

  8. java实现四则运算

    http://blog.csdn.net/lip009/article/details/7768258 我之前找到的一个大神写的?还没看懂

  9. JS入门经典第二章总结

    document:在对网页编写脚本时,我们使用document对象代表网页.要引用一个属性,只需在document对象后加一个“.”号,然后再加上要引用的属性名. alert():该函数弹出一个消息框 ...

  10. Servlet创建完美教程

    简介:Servlet其实是Server Let的缩写,是服务器端应用程序.  java中有一个applet是客户端应用程序,与servlet对应.applet已经过时.Servlet作用:能在B/S架 ...