zoukankan      html  css  js  c++  java
  • 深入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

  • 相关阅读:
    IDEA创建MAVEN JavaWeb项目中 Target文件夹中没有lib包
    2019年上半年下午第六题
    2021年上半年下午第六题
    2019年下半年下午第六题
    软考2019下半年下午第三题
    软考2019年下半年下午第二题
    2019年下半年软考下午第一题
    软考2019年上半年下午第三题
    2019软考上半年下午第二题
    2019年上半年软考下午题第一题
  • 原文地址:https://www.cnblogs.com/softidea/p/5614037.html
Copyright © 2011-2022 走看看