`
jiangshuiy
  • 浏览: 339269 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

java类库中Arrays的排序算法探析(基础类型)

 
阅读更多

java.util.Arrays中有非常方便的array转换为list的方法,在 Java中List与Array的转换已经提及了,这里再介绍下其中的排序算法:

在java.util.Arrays中,排序(sort)部分占的篇幅最大,大量用到了重载,一种是根据参数类型的重载,也就是如:

 

public static void sort(long[] a);
public static void sort(int[] a);
……

 

 另外一种就是参数个数的重载,是和上面的相对应的:

 

public static void sort(int[] a);
public static void sort(int[] a, int fromIndex, int toIndex);

 

 其实在原理上都差不多,第一种重载是根据传入数组的类型选择对应的排序;第二种是根据传入的条件多少来决定,下面以

long[]的实现为例初步分析下过程:

 

 

public static void sort(long[] a) {
	sort1(a, 0, a.length);
    }

 

 其相同类型的重载为:

 

public static void sort(long[] a, int fromIndex, int toIndex) {
        rangeCheck(a.length, fromIndex, toIndex);
	sort1(a, fromIndex, toIndex-fromIndex);
    }

 

 可以看出,有起始限制的sort首先是验证传入的起始限界是否合法,而没有起始限制的sort默认就是全排序了:/**

     * Sorts the specified sub-array of longs into ascending order.
     */
    private static void sort1(long x[], int off, int len) {
	// Insertion sort on smallest arrays
        //如果待排序的范围很小,就选择插入排序,最是简洁,复杂度O(n2)
	if (len < 7) {
	    for (int i=off; i<len+off; i++)
		for (int j=i; j>off && x[j-1]>x[j]; j--)
		    swap(x, j, j-1);
	    return;
	}

	// Choose a partition element, v
        //选择快排,先找出一个分区值,这里有个小技巧,取一半时采用的是移位,比    有时候使用的len/2要好一点,预设为中间位置的值
	int m = off + (len >> 1);       // Small arrays, middle element
	if (len > 7) {
	    int l = off;
	    int n = off + len - 1;
	    if (len > 40) {        // Big arrays, pseudomedian of 9,就是找9点点来确定更好的分区点,下面可以看出,这9个点是较均匀的插值,med3是计算x数组中后面三个位置上的哪个值在中间的一个方法
		int s = len/8;
		l = med3(x, l,     l+s, l+2*s);
		m = med3(x, m-s,   m,   m+s);
		n = med3(x, n-2*s, n-s, n);
	    }
	    m = med3(x, l, m, n); // Mid-size, med of 3,找到分区值
	}
	long v = x[m];

	// Establish Invariant: v* (<v)* (>v)* v*,其实就是构建区域,和分区值相等的区域,所有元素都小于分区值的区域,所有元素都大于分区值的区域,和分区值相等的区域
	int a = off, b = a, c = off + len - 1, d = c;
	while(true) {
            //将与分区值相等的值移到头部,尾部为全部小于分区值的元素
	    while (b <= c && x[b] <= v) {
		if (x[b] == v)
		    swap(x, a++, b);
		b++;
	    }
           //将与分区值相等的值移到尾部,头部为全部大于分区值的元素
	    while (c >= b && x[c] >= v) {
		if (x[c] == v)
		    swap(x, c, d--);
		c--;
	    }
           //中止条件
	    if (b > c)
		break;
	    swap(x, b++, c--);
	}

	// Swap partition elements back to middle,交换,成为三个区域,分别为小于、等于和大于分区值的三个
	int s, n = off + len;
	s = Math.min(a-off, b-a  );  vecswap(x, off, b-s, s);
	s = Math.min(d-c,   n-d-1);  vecswap(x, b,   n-s, s);

	// Recursively sort non-partition-elements,在两边的区域递归
	if ((s = b-a) > 1)
	    sort1(x, off, s);
	if ((s = d-c) > 1)
	    sort1(x, n-s, s);
    }

 

区域交换算法,简洁美:

 

/**
     * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)].
     */
    private static void vecswap(long x[], int a, int b, int n) {
	for (int i=0; i<n; i++, a++, b++)
	    swap(x, a, b);
    }

 返回三个数中间数的算法,稍微有点晕:

 

/**
     * Returns the index of the median of the three indexed longs.
     */
    private static int med3(long x[], int a, int b, int c) {
	return (x[a] < x[b] ?
		(x[b] < x[c] ? b : x[a] < x[c] ? c : a) :
		(x[b] > x[c] ? b : x[a] > x[c] ? c : a));
    }

 关于long数组的排序就结束了!

其它基本类型如int, byte, char处理过程完全类似;

folat和double的后期处理也一样,只是会多一个初始化过程,这是由于浮点数的特性决定的,以float为例,在执行sort1之前的预处理:

 

private static void sort2(float a[], int fromIndex, int toIndex) {
        final int NEG_ZERO_BITS = Float.floatToIntBits(-0.0f);
        /*
         * The sort is done in three phases to avoid the expense of using
         * NaN and -0.0 aware comparisons during the main sort.避免事实上不需要比较,如NaN,-0.0和0.0事实上相等等
         */

        /*
         * Preprocessing phase:  Move any NaN's to end of array, count the
         * number of -0.0's, and turn them into 0.0's.预处理阶段,将NaN移到队尾,计算-0.0的个数并转换为0.0
         */
        int numNegZeros = 0;
        int i = fromIndex, n = toIndex;
        while(i < n) {
            if (a[i] != a[i]) {
		float swap = a[i];
                a[i] = a[--n];
                a[n] = swap;
            } else {
                if (a[i]==0 && Float.floatToIntBits(a[i])==NEG_ZERO_BITS) {
                    a[i] = 0.0f;
                    numNegZeros++;
                }
                i++;
            }
        }

        // Main sort phase: quicksort everything but the NaN's,主流程,和上面long的除了数组类型和元素类型不同之外完全相同
	sort1(a, fromIndex, n-fromIndex);

        // Postprocessing phase: change 0.0's to -0.0's as required。后处理阶段,将之前转换为0.0的归位为-0.0
        if (numNegZeros != 0) {
            int j = binarySearch0(a, fromIndex, n, 0.0f); // posn of ANY zero
            do {
                j--;
            } while (j>=0 && a[j]==0.0f);

            // j is now one less than the index of the FIRST zero
            for (int k=0; k<numNegZeros; k++)
                a[++j] = -0.0f;
        }
    }

 在传入对象数组的时候,采用的是归并排序,算法和上面的快排有所区别,后面探讨。

分享到:
评论

相关推荐

    java编写的插入排序算法

    ### Java编写的插入排序算法 #### 一、插入排序算法基本思想 插入排序是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在...

    Java直接插入排序算法源码

    总的来说,Java中的直接插入排序算法是一个直观易懂的排序方法,虽然在效率上不敌更高级的排序算法,但它在理解和实现上相对简单,对于初学者来说是很好的学习材料。通过阅读和实践这个源代码,你可以深入理解排序...

    最快的排序算法 java最快的排序-在Java中对列表进行排序的最快方法,排序算法数据结构

    在 Java 中,还有其他的排序算法,如 Arrays.sort() 方法,该方法使用的排序算法是快速排序,它具有高效的性能,但不稳定排序算法。 在实际应用中,选择合适的排序算法取决于具体的应用场景。例如,在有大量元素...

    java 8种排序算法

    在Java中,这些排序算法都可以用代码实现,可以通过`java.util.Arrays.sort()`方法使用内置的快速排序或归并排序,也可以自定义排序逻辑。在`AllSort`这个压缩包中,可能包含了这八种排序算法的Java实现代码,通过...

    JAVA排序汇总 java应用中一些比较经典的排序算法

    在Java中实现这些排序算法时,通常会使用数组作为数据结构,通过定义辅助方法如`swap()`来进行元素交换,`printArray()`用于输出排序结果。例如,`bubbleSort()`函数展示了冒泡排序的具体实现,根据参数`sortType`...

    ECharts - Java类库.zip

    然而,"ECharts - Java 类库.zip" 提到的可能是将 ECharts 集成到 Java 应用程序中的一个工具或框架,以便在服务器端生成 ECharts 图表配置,并将其发送到前端展示。在这个压缩包中,包含的 "ECharts-master" 文件...

    Java排序算法 Java排序算法.rar

    在编程领域,排序算法是计算机科学中的核心...在Java中,可以使用内置的`Arrays.sort()`或`Collections.sort()`方法,它们底层实现了高效的排序算法,如TimSort,一种混合排序算法,具有稳定性且在实际应用中表现出色。

    8中排序算法(java实现)

    在IT领域,排序算法是计算机科学中的基础概念,它们用于对数据进行有序排列。以下是关于标题"8种排序算法(Java实现)"及其描述中提到的排序算法的详细讲解: 1. **插入排序**: - **直接插入排序**:基本思想是从...

    Java各种排序算法代码

    下面我们将详细探讨Java中常见的几种排序算法。 1. 冒泡排序(Bubble Sort) 冒泡排序是一种简单的交换排序,通过不断比较相邻元素并交换位置,将最大或最小的元素逐渐“冒泡”到数组的一端。虽然效率较低,但其...

    Java排序算法包 支持自定义比较条件

    - 在Java中,`java.util.Arrays`类提供了内置的排序方法,如`Arrays.sort()`,可以对基本类型数组和对象数组进行排序。 2. **自定义比较器(Comparator)**: - 当内置的排序规则不能满足需求时,可以使用`...

    java四大排序算法总结.zip

    总的来说,理解和掌握这些基础排序算法是每个Java程序员必备的技能,它们不仅有助于提升编程能力,也是深入学习高级算法和数据结构的基础。通过不断的实践和学习,我们可以更好地应对各种编程挑战。

    Java 排序算法大结合

    在实际应用中,Java还提供了内置的`Arrays.sort()`方法,它使用了混合排序算法(Timsort),这是一种稳定的、具有优秀性能的排序算法,尤其适用于处理已部分有序的数据。对于特定场景,开发者可以根据需求选择最合适...

    java实现常见的集中排序算法

    在Java中,我们可以使用ArrayUtils、Collections等工具类进行排序,例如`Arrays.sort()`和`Collections.sort()`,它们内部使用了高效的排序算法,如TimSort,是混合排序算法,结合了插入排序和归并排序的优点,对小...

    Java排序算法,常用算法集代码

    在Java中,`java.util.Arrays.sort()`方法提供了快速排序和归并排序的实现,对于数组的排序非常方便。同时,`Collections.sort()`方法可用于排序集合对象,如ArrayList。 这个压缩包中的代码集可能包含了以上提到的...

    031112_【第11章:Java常用类库】_Arrays笔记

    031112_【第11章:Java常用类库】_Arrays笔记

    常见的八大排序算法及其JAVA实现

    在Java中,冒泡排序可以表示为: ```java void bubbleSort(int[] arr) { int n = arr.length; for (int i = 0; i ; i++) { for (int j = 0; j ; j++) { if (arr[j] &gt; arr[j + 1]) { int temp = arr[j]; arr[j...

    Java-各种排序算法

    1. **冒泡排序**:冒泡排序是最基础的排序算法之一,它通过重复遍历待排序数组,比较相邻元素并交换顺序(如果需要)来实现排序。虽然效率相对较低,但它的逻辑简单,适合教学用途。在Java中,你可以通过两层循环...

    排序算法的Java实现

    在编程领域,排序算法是计算机科学中的核心概念,特别是在数据结构和算法分析中。...在实际开发中,还可以考虑结合Java的内置排序函数`Arrays.sort()`,它使用了一种高效的混合排序算法,可以处理各种数据类型。

    常用各种排序算法Java的实现_差不多了__.rar

    在Java中,除了使用上述基本排序算法,还可以使用内置的`Arrays.sort()`方法,该方法内部实现了高效的TimSort算法,适用于处理大数据集,具有稳定性,并且在数据部分有序的情况下表现出色。 这个压缩文件中的".htm"...

    基于JAVA语言的常见排序算法分析与比较.zip

    在Java中,我们可以使用内置的`Arrays.sort()`方法对数组进行排序,但这只是冰山一角,因为还有许多其他排序算法可以手动实现,每种都有其独特的特性和适用场景。 1. 冒泡排序(Bubble Sort):这是一种简单的排序...

Global site tag (gtag.js) - Google Analytics