深入JDK源码之Arrays类中的排序查找算法(转)
原文出处: 陶邦仁
binarySearch()方法
二分法查找算法,算法思想:当数据量很大适宜采用该方法。采用二分法查找时,数据需是排好序的。 基本思想:假设数据是按升序排序的,对于给定值x,从序列的中间位置开始比较,如果当前位置值等于x,则查找成功;若x小于当前位置值,则在数列的前半段中查找;若x大于当前位置值则在数列的后半段中继续查找,直到找到为止。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
//针对int类型数组的二分法查找,key为要查找数的下标 private static int binarySearch0( int [] a, int fromIndex, int toIndex, int key) { int low = fromIndex; int high = toIndex - 1 ; while (low <= high) { int mid = (low + high) >>> 1 ; //无符号左移一位,相当于除以二 int midVal = a[mid]; if (midVal < key) low = mid + 1 ; else if (midVal > key) high = mid - 1 ; else return mid; // key found } return -(low + 1 ); // key not found. } |
sort()方法
针对引用类型数组采取的算法是归并排序,算法思想:归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
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
|
private static final int INSERTIONSORT_THRESHOLD = 7 ; //插入排序门槛 public static void sort(Object[] a) { Object[] aux = (Object[])a.clone(); mergeSort(aux, a, 0 , a.length, 0 ); } //归并排序 private static void mergeSort(Object[] src, Object[] dest, int low, int high, int off) { int length = high - low; if (length < INSERTIONSORT_THRESHOLD) { //若数组长度小于7,则用冒泡排序 for ( int i=low; i<high; i++) for ( int j=i; j>low && ((Comparable) dest[j- 1 ]).compareTo(dest[j])> 0 ; j--) swap(dest, j, j- 1 ); return ; } // Recursively sort halves of dest into src int destLow = low; int destHigh = high; low += off; high += off; int mid = (low + high) >>> 1 ; //无符号左移一位, mergeSort(dest, src, low, mid, -off); mergeSort(dest, src, mid, high, -off); // If list is already sorted, just copy from src to dest. This is an // optimization that results in faster sorts for nearly ordered lists. if (((Comparable)src[mid- 1 ]).compareTo(src[mid]) <= 0 ) { System.arraycopy(src, low, dest, destLow, length); return ; } // Merge sorted halves (now in src) into dest for ( int i = destLow, p = low, q = mid; i < destHigh; i++) { if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<= 0 ) dest[i] = src[p++]; else dest[i] = src[q++]; } } |
sort()方法
采取的是快速排序算法,算法思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
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
73
74
|
/** * Swaps x[a] with x[b]. */ private static void swap( int x[], int a, int b) { int t = x[a]; x[a] = x[b]; x[b] = t; } public static void sort( int [] a) { sort1(a, 0 , a.length); } private static int med3( int 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)); } /** * Sorts the specified sub-array of integers into ascending order. */ private static void sort1( int x[], int off, int len) { // Insertion sort on smallest arrays 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 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 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 } int 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); } |
sort()方法
针对double,float类型数组排序,采取了先把所有的数组元素值为-0.0d的转换成0.0d,再利用快速排序排好序,最后再还原。
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
|
public static void sort( double [] a) { sort2(a, 0 , a.length); } private static void sort2( double a[], int fromIndex, int toIndex) { //static long doubleToLongBits(double value) //根据 IEEE 754 浮点双精度格式 ("double format") 位布局,返回指定浮点值的表示形式。 final long NEG_ZERO_BITS = Double.doubleToLongBits(- 0 .0d); /* * The sort is done in three phases to avoid the expense of using * NaN and -0.0 aware comparisons during the main sort. */ /* * Preprocessing phase: Move any NaN's to end of array, count the * number of -0.0's, and turn them into 0.0's. */ int numNegZeros = 0 ; int i = fromIndex, n = toIndex; while (i < n) { if (a[i] != a[i]) { //这段搞不懂,源代码怪怪的,感觉多此一举 double swap = a[i]; a[i] = a[--n]; a[n] = swap; } else { if (a[i]== 0 && Double.doubleToLongBits(a[i])==NEG_ZERO_BITS) { a[i] = 0 .0d; numNegZeros++; } i++; } } // Main sort phase: quicksort everything but the NaN's sort1(a, fromIndex, n-fromIndex); // Postprocessing phase: change 0.0's to -0.0's as required if (numNegZeros != 0 ) { int j = binarySearch0(a, fromIndex, n, 0 .0d); // posn of ANY zero do { j--; } while (j>= 0 && a[j]== 0 .0d); // j is now one less than the index of the FIRST zero for ( int k= 0 ; k<numNegZeros; k++) a[++j] = - 0 .0d; } } |
http://www.importnew.com/19952.html#comment-499513
深入JDK源码之Arrays类中的排序查找算法(转)的更多相关文章
- JDK源码之Integer类分析
一 简介 Integer是int基本类型的包装类,同样继承了Number类,实现了Comparable接口,String类中的一些转化方法就使用了Integer类中的一些API,且fianl修饰不可继 ...
- JDK源码之String类解析
一 概述 String由final修饰,是不可变类,即String对象也是不可变对象.这意味着当修改一个String对象的内容时,JVM不会改变原来的对象,而是生成一个新的String对象 主要考虑以 ...
- JDK源码之Double类&Float类分析
一 概述 Double 类是基本类型double的包装类,fainl修饰,在对象中包装了一个基本类型double的值.Double继承了Number抽象类,具有了转化为基本double类型的功能. 此 ...
- JDK源码之AbstractStringBuilder类分析
一 概述 二 实现接口 AbstractStringBuilder实现了两个接口: Appendable 概述: Appendable的实现类的对象可以附加字符序列和值. 要追加的字符应该是Unico ...
- JDK源码之Byte类分析
一 简介 byte,即字节,由8位的二进制组成.在Java中,byte类型的数据是8位带符号的二进制数,以二进制补码表示的整数 取值范围:默认值为0,最小值为-128(-2^7);最大值是127(2^ ...
- JDK源码之Boolean类分析
一 简介 boolean类型的封装类,将基本类型为boolean的值包装在一个对象中,实现序列化接口,和Comparable接口 额外提供了许多便捷方法,比较简单,直接贴代码分析 二 源码分析 //t ...
- jdk源码理解-String类
String类的理解 简记录一下对于jdk的学习,做一下记录,会持续补充,不断学习,加油 1.String的hash值的计算方法. hash值的计算方法多种多样,jdk中String的计算方法如下,比 ...
- Activiti源码:ActivitiEventSupport类中eventListeners的设计
ActivitiEventSupport类成员eventListeners是使用CopyOnWriteArrayList实现的. public ActivitiEventSupport() { eve ...
- jdk源码阅读-Object类
native 关键字 private static native void registerNatives(); static { registerNatives(); } public final ...
随机推荐
- 转: sublime text常用插件和快捷键
Sublime Text 2是一个轻量.简洁.高效.跨平台的编辑器.博主之前一直用notepdd++写前端代码,用得也挺顺手了,早就听说sublime的大名,一直也懒得去试试看,认为都是工具用着顺手就 ...
- curl 返回响应头
demo:/root# curl -i baidu.com HTTP/1.1 200 OK Date: Wed, 27 Jul 2016 08:50:03 GMT Content-Type: text ...
- 【C++学习笔记】继承与派生基础概念
面向对象的程序设计主要有四个特点:抽象.封装.继承和多态.其中继承是我认为最最重要的一个特性,可以说继承是面向对象的精华所在. 举一个继承的浅显易懂的例子:假如我们已经有了一个“马”的类,其中成员变量 ...
- js数组练习
//查找数组对象中 age 大于 18 对象 function filterAdult(arr) { return arr.filter(function(item, index, array) { ...
- C# Code Snip
1.Tryf + TAB+TAB try { } finally { } 2.Prop+Tab+Tab public int MyProperty { get; set; } 3. #region + ...
- 前端CSS规范大全
一.文件规范 1.文件均归档至约定的目录中(具体要求以豆瓣的CSS规范为例进行讲解): 所有的CSS分为两大类:通用类和业务类.通用的CSS文件,放在如下目录中: 基本样式库 /css/core 通用 ...
- js 特效 手风琴效果
$(document).ready(function(){ //定义展开的块 var lastBlock = $('#a1'); //展开的块的宽度 var maxWidth = 406; //折叠的 ...
- Linux输入子系统(Input Subsystem)
Linux输入子系统(Input Subsystem) http://blog.csdn.net/lbmygf/article/details/7360084 input子系统分析 http://b ...
- BZOJ 100题留念
- Java学习之IO之File类二
之前学了File便想把我学习视频的名字改了,因为文件名太长不好看,便试着写了个功能实现 package com.gh.file; import java.io.File; /** * 批量文件命名 * ...