原文出处: 陶邦仁

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类中的排序查找算法(转)的更多相关文章

  1. JDK源码之Integer类分析

    一 简介 Integer是int基本类型的包装类,同样继承了Number类,实现了Comparable接口,String类中的一些转化方法就使用了Integer类中的一些API,且fianl修饰不可继 ...

  2. JDK源码之String类解析

    一 概述 String由final修饰,是不可变类,即String对象也是不可变对象.这意味着当修改一个String对象的内容时,JVM不会改变原来的对象,而是生成一个新的String对象 主要考虑以 ...

  3. JDK源码之Double类&Float类分析

    一 概述 Double 类是基本类型double的包装类,fainl修饰,在对象中包装了一个基本类型double的值.Double继承了Number抽象类,具有了转化为基本double类型的功能. 此 ...

  4. JDK源码之AbstractStringBuilder类分析

    一 概述 二 实现接口 AbstractStringBuilder实现了两个接口: Appendable 概述: Appendable的实现类的对象可以附加字符序列和值. 要追加的字符应该是Unico ...

  5. JDK源码之Byte类分析

    一 简介 byte,即字节,由8位的二进制组成.在Java中,byte类型的数据是8位带符号的二进制数,以二进制补码表示的整数 取值范围:默认值为0,最小值为-128(-2^7);最大值是127(2^ ...

  6. JDK源码之Boolean类分析

    一 简介 boolean类型的封装类,将基本类型为boolean的值包装在一个对象中,实现序列化接口,和Comparable接口 额外提供了许多便捷方法,比较简单,直接贴代码分析 二 源码分析 //t ...

  7. jdk源码理解-String类

    String类的理解 简记录一下对于jdk的学习,做一下记录,会持续补充,不断学习,加油 1.String的hash值的计算方法. hash值的计算方法多种多样,jdk中String的计算方法如下,比 ...

  8. Activiti源码:ActivitiEventSupport类中eventListeners的设计

    ActivitiEventSupport类成员eventListeners是使用CopyOnWriteArrayList实现的. public ActivitiEventSupport() { eve ...

  9. jdk源码阅读-Object类

    native 关键字 private static native void registerNatives(); static { registerNatives(); } public final ...

随机推荐

  1. QT太多的内容和模块,怎么办?

    我有个问题,QT可以做许多不同的开源项目,而且每个QT新版本都那么内容,感觉学不过来.用不过来那么我们还应该学习和使用其它语言吗? 如果回答,在需要的时候学习,那么这句话意味着,这几年你基本上就局限于 ...

  2. 【Untiy3D 游戏开发之一】Unity3D For Window/Mac最新4.2.0版本破解教程

    转载请标明:转载自[小枫栏目],博文链接:http://blog.csdn.net/rexuefengye/article/details/11646885 一.Unity3D For Mac 1.首 ...

  3. type,isinstance判断一个变量的数据类型

    type,isinstance判断一个变量的数据类型 import types type(x) is types.IntType # 判断是否int 类型 type(x) is types.Strin ...

  4. Pascal向C++的跨越

    最近从pas转向了C++,觉得需要在语言上总结对比一下,以及记录一些注意点,关于STL,还需要之后好好地学习.同时,希望这篇文章对从pas转C++的同学有所帮助. 基本类型 首先是基本类型的比较: P ...

  5. IPTABLES 映射问题

    今天要做一个新的映射:将内网的一个8090口映射到外网的8087口. 在 /ETC/RC.LOCAL中最后插入: iptables -t nat -A PREROUTING -d outIP -p t ...

  6. SQL server 数据库视频总结

    用了半个多月的时间把,浙江大学耿建玲老师 数据库视频看了一遍.在看视频之前,曾经接收了一个学生信息管理系统,在学习  学生信息管理系统的时候,对于数据库的部分,总是那么一知半解.带着疑惑来看耿建玲老师 ...

  7. android经常使用的电话操作

    给大家分享一下我的一个Android工具类,能够获取手机里面的各种信息,包含拨打电话. 获取全部联系人姓名及电话,插入联系人姓名及电话,插入联系人姓名及电话.插入通话记录.获取用户全部短信.批量插入短 ...

  8. jQuery的AJAX方法简介及与其他文件$符号冲突的解决办法

    一.重要的jQuery AJAX方法简介 $.load(url) 从服务器载入数据 $.get(url,callback) 从服务器请求数据,并执行回调函数 $.post(url,data,callb ...

  9. 碰撞缓冲效果的导航条 js

  10. C#中继承,集合(Eleventh day)

    又到了总结知识的时间,今天在云和学院继续学习了继承的一些运用,和集合的运用.下面就总结下来吧 理论: 显示调用父类的构造方法,关键字: base:构造函数不能被继承:子类对象被实例化的时候会先去主动的 ...