深入JDK源代码之Arrays类中的排序查找算法

java.util.Arrays类。这个类是个数组工具类。主要提供方法sort(),fill(),binarySearch(),还有数组复制等方法。打开源文件,刚超过4千行,不过包括很多注释,那么我在这里主要讲讲这里面涉及的排序算法和查找算法。
  一、binarySearch()方法,二分法查找算法, 算法思想:当数据量很大适宜采用该方法。采用二分法查找时,数据需是排好序的。 基本思想:假设数据是按升序排序的,对于给定值x,从序列的中间位置开始比较,如果当前位置值等于x,则查找成功;若x小于当前位置值,则在数列的前半段 中查找;若x大于当前位置值则在数列的后半段中继续查找,直到找到为止。
 

Java代码   收藏代码
  1. //针对int类型数组的二分法查找,key为要查找数的下标  
  2.     private static int binarySearch0(int[] a, int fromIndex, int toIndex,  
  3.                      int key) {  
  4.     int low = fromIndex;  
  5.     int high = toIndex - 1;  
  6.     while (low <= high) {  
  7.         int mid = (low + high) >>> 1;//无符号左移一位,相当于除以二  
  8.         int midVal = a[mid];  
  9.   
  10.         if (midVal < key)  
  11.         low = mid + 1;  
  12.         else if (midVal > key)  
  13.         high = mid - 1;  
  14.         else  
  15.         return mid; // key found  
  16.     }  
  17.     return -(low + 1);  // key not found.  
  18.     }  


二、sort()方法针对引用类型数组采取的算法是归并排序。算法思想:归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
 

Java代码   收藏代码
  1. private static final int INSERTIONSORT_THRESHOLD = 7;//插入排序门槛  
  2.   public static void sort(Object[] a) {  
  3.        Object[] aux = (Object[])a.clone();  
  4.        mergeSort(aux, a, 0, a.length, 0);  
  5.    }  
  6.    //归并排序  
  7.    private static void mergeSort(Object[] src,  
  8.               Object[] dest,  
  9.               int low,  
  10.               int high,  
  11.               int off) {  
  12.        int length = high - low;  
  13.   
  14.        if (length < INSERTIONSORT_THRESHOLD) { //若数组长度小于7,则用冒泡排序  
  15.            for (int i=low; i<high; i++)  
  16.                for (int j=i; j>low &&  
  17.          ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)  
  18.                    swap(dest, j, j-1);  
  19.            return;  
  20.        }  
  21.   
  22.        // Recursively sort halves of dest into src  
  23.        int destLow  = low;  
  24.        int destHigh = high;  
  25.        low  += off;  
  26.        high += off;  
  27.        int mid = (low + high) >>> 1//无符号左移一位,  
  28.        mergeSort(dest, src, low, mid, -off);  
  29.        mergeSort(dest, src, mid, high, -off);  
  30.   
  31.        // If list is already sorted, just copy from src to dest.  This is an  
  32.        // optimization that results in faster sorts for nearly ordered lists.  
  33.        if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {  
  34.            System.arraycopy(src, low, dest, destLow, length);  
  35.            return;  
  36.        }  
  37.   
  38.        // Merge sorted halves (now in src) into dest  
  39.        for(int i = destLow, p = low, q = mid; i < destHigh; i++) {  
  40.            if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)  
  41.                dest[i] = src[p++];  
  42.            else  
  43.                dest[i] = src[q++];  
  44.        }  
  45.    }  


三、sort()方法采取的是快速排序算法,算法思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
  

Java代码   收藏代码
  1. /** 
  2.     * Swaps x[a] with x[b]. 
  3.     */  
  4. private static void swap(int x[], int a, int b) {  
  5. int t = x[a];  
  6. x[a] = x[b];  
  7. x[b] = t;  
  8.    }  
  9. public static void sort(int[] a) {  
  10. sort1(a, 0, a.length);  
  11.    }  
  12.   
  13. private static int med3(int x[], int a, int b, int c) {//找出三个中的中间值  
  14. return (x[a] < x[b] ?  
  15.     (x[b] < x[c] ? b : x[a] < x[c] ? c : a) :  
  16.     (x[b] > x[c] ? b : x[a] > x[c] ? c : a));  
  17.    }  
  18.   
  19.   /** 
  20.     * Sorts the specified sub-array of integers into ascending order. 
  21.     */  
  22.  private static void sort1(int x[], int off, int len) {  
  23. // Insertion sort on smallest arrays  
  24. if (len < 7) {//采用冒泡排序  
  25.     for (int i=off; i<len+off; i++)  
  26.     for (int j=i; j>off && x[j-1]>x[j]; j--)  
  27.         swap(x, j, j-1);  
  28.     return;  
  29. }  
  30.    //采用快速排序  
  31. // Choose a partition element, v  
  32. int m = off + (len >> 1);       // Small arrays, middle element  
  33. if (len > 7) {  
  34.     int l = off;  
  35.     int n = off + len - 1;  
  36.     if (len > 40) {        // Big arrays, pseudomedian of 9  
  37.     int s = len/8;  
  38.     l = med3(x, l,     l+s, l+2*s);  
  39.     m = med3(x, m-s,   m,   m+s);  
  40.     n = med3(x, n-2*s, n-s, n);  
  41.     }  
  42.     m = med3(x, l, m, n); // Mid-size, med of 3  
  43. }  
  44. int v = x[m];  
  45.   
  46. // Establish Invariant: v* (<v)* (>v)* v*  
  47. int a = off, b = a, c = off + len - 1, d = c;  
  48. while(true) {  
  49.     while (b <= c && x[b] <= v) {  
  50.     if (x[b] == v)  
  51.         swap(x, a++, b);  
  52.     b++;  
  53.     }  
  54.     while (c >= b && x[c] >= v) {  
  55.     if (x[c] == v)  
  56.         swap(x, c, d--);  
  57.     c--;  
  58.     }  
  59.     if (b > c)  
  60.     break;  
  61.     swap(x, b++, c--);  
  62. }  
  63.   
  64. // Swap partition elements back to middle  
  65. int s, n = off + len;  
  66. s = Math.min(a-off, b-a  );  vecswap(x, off, b-s, s);  
  67. s = Math.min(d-c,   n-d-1);  vecswap(x, b,   n-s, s);  
  68.   
  69. // Recursively sort non-partition-elements  
  70. if ((s = b-a) > 1)  
  71.     sort1(x, off, s);  
  72. if ((s = d-c) > 1)  
  73.     sort1(x, n-s, s);  
  74.    }  


四、针对double,float类型数组排序的sort()方法,采取了先把所有的数组元素值为-0.0d的转换成0.0d,再利用快速排序排好序,最后再还原。
  

Java代码   收藏代码
  1. public static long doubleToRawLongBits(double value)根据 IEEE 754 浮点“双精度格式”位布局,返回指定浮点值的表示形式,并保留 NaN 值。   
  2. 第 63 位(掩码 0x8000000000000000L 选定的位)表示浮点数的符号。第 62-52 位(掩码 0x7ff0000000000000L 选定的位)表示指数。第 51-0 位(掩码 0x000fffffffffffffL 选定的位)表示浮点数的有效数字(有时也称为尾数)。   
  3.   
  4. 如果参数是正无穷大,则结果为 0x7ff0000000000000L。   
  5.   
  6. 如果参数是负无穷大,则结果为 0xfff0000000000000L。   
  7.   
  8. 如果参数是 NaN,则结果是表示实际 NaN 值的 long 整数。与 doubleToLongBits 方法不同,doubleToRawLongBits 并没有压缩那些将 NaN 编码为一个“规范的”NaN 值的所有位模式。   
  9.   
  10. 在所有情况下,结果都是一个 long 整数,将其赋予 longBitsToDouble(long) 方法将生成一个与 doubleToRawLongBits 的参数相同的浮点值。   
  11.   
  12.   
  13. 参数:  
  14. value - 双精度 (double) 浮点数。   


下面是源代码中的方法:

Java代码   收藏代码
  1. public static void sort(double[] a) {  
  2.     sort2(a, 0, a.length);  
  3.    }  
  4. private static void sort2(double a[], int fromIndex, int toIndex) {  
  5.  //static long doubleToLongBits(double value)   
  6. //根据 IEEE 754 浮点双精度格式 ("double format") 位布局,返回指定浮点值的表示形式。  
  7.      final long NEG_ZERO_BITS = Double.doubleToLongBits(-0.0d);  
  8.      /* 
  9.       * The sort is done in three phases to avoid the expense of using 
  10.       * NaN and -0.0 aware comparisons during the main sort. 
  11.       */  
  12.   
  13.      /* 
  14.       * Preprocessing phase:  Move any NaN's to end of array, count the 
  15.       * number of -0.0's, and turn them into 0.0's. 
  16.       */  
  17.      int numNegZeros = 0;  
  18.      int i = fromIndex, n = toIndex;  
  19.      while(i < n) {  
  20.          if (a[i] != a[i]) {  //这段搞不懂,源代码怪怪的,感觉多此一举  
  21. ouble swap = a[i];  
  22.              a[i] = a[--n];  
  23.              a[n] = swap;  
  24.          } else {  
  25.              if (a[i]==0 && Double.doubleToLongBits(a[i])==NEG_ZERO_BITS) {  
  26.                  a[i] = 0.0d;  
  27.                  numNegZeros++;  
  28.              }  
  29.              i++;  
  30.          }  
  31.      }  
  32.   
  33.      // Main sort phase: quicksort everything but the NaN's  
  34.   sort1(a, fromIndex, n-fromIndex);  
  35.   
  36.      // Postprocessing phase: change 0.0's to -0.0's as required  
  37.      if (numNegZeros != 0) {  
  38.          int j = binarySearch0(a, fromIndex, n, 0.0d); // posn of ANY zero  
  39.          do {  
  40.              j--;  
  41.          } while (j>=0 && a[j]==0.0d);  
  42.   
  43.          // j is now one less than the index of the FIRST zero  
  44.          for (int k=0; k<numNegZeros; k++)  
  45.              a[++j] = -0.0d;  
  46.      }  
  47.  } 

http://zengzhaoshuai.iteye.com/blog/1130376

http://hxraid.iteye.com/blog/665095/

猜你喜欢

转载自m635674608.iteye.com/blog/2286734