Java Collections(1)

今天简单介绍一下TimSort中的binary insertion sort(java 实现)

Code Segment

@SuppressWarnings({"fallthrough", "rawtypes", "unchecked"})
    private static void binarySort(Object[] a, int lo, int hi, int start) {
        assert lo <= start && start <= hi;
        if (start == lo)
            start++;
        for ( ; start < hi; start++) {
            Comparable pivot = (Comparable) a[start];

            // Set left (and right) to the index where a[start] (pivot) belongs
            int left = lo;
            int right = start;
            assert left <= right;
            /*
             * Invariants:
             *   pivot >= all in [lo, left).
             *   pivot <  all in [right, start).
             */
            while (left < right) {
                int mid = (left + right) >>> 1;
                if (pivot.compareTo(a[mid]) < 0)
                    right = mid;
                else
                    left = mid + 1;
            }
            assert left == right;

            /*
             * The invariants still hold: pivot >= all in [lo, left) and
             * pivot < all in [left, start), so pivot belongs at left.  Note
             * that if there are elements equal to pivot, left points to the
             * first slot after them -- that's why this sort is stable.
             * Slide elements over to make room for pivot.
             */
            int n = start - left;  // The number of elements to move
            // Switch is just an optimization for arraycopy in default case
            switch (n) {
                case 2:  a[left + 2] = a[left + 1];
                case 1:  a[left + 1] = a[left];
                         break;
                default: System.arraycopy(a, left, a, left + 1, n);
            }
            a[left] = pivot;
        }
    }

二分法插入排序简介

要素:数组S是一个已序的数组;
结果:查找元素q在数组S中的位置;
参数:low 为第一个元素的index,high为最后一个元素的index;
要求:low <= high
-概述:
0.比较元素q和S[mid]的大小,其中mid=(low + high) >>> 1;
1.如果元素q等于S[mid],则位置mid就是返回的结果;
2.如果元素q大于S[mid],则元素q可能出现在[low, mid-1]中;
3.如果元素q小于S[mid],则元素q可能出现在[mid+1, high]中;
4.重复上述步骤,当high < low时,说明数组S中不包含元素q。

@SuppressWarnings({"rawtypes", "unchecked"})
    public static int search(Object[] a, int lo, int hi, Comparable key) {
        assert a != null && hi <= a.length-1;

        if(lo > hi)
            return -1;//key not found

        int mid = (lo + hi) >>> 1;

        if(key.compareTo(a[mid]) == 0) {
            return mid;
        }

        if(key.compareTo(a[mid]) < 0) {
            return search(a, lo, mid - 1, key);
        }
        else {
            return search(a, mid + 1, hi, key);
        }

    }

关于更多的知识,请您看看大神Steven S. Skiena的The Algorithm Design Manual(2nd Edition)种4.9 Binary Search and Related Algorithm。

比较一下binarySort中用的的二分法查找

while (left < right) {
      int mid = (left + right) >>> 1;
      if (pivot.compareTo(a[mid]) < 0)
            right = mid;
      else
            left = mid + 1;
}
assert left == right;

0.不同之处在于有无mid-1,这决定了有无low>high(或者left>right)的可能;
1.一个是采用递归查找,一个是采用while循环查找。
2.作用不一样,search方法是查找key元素在数组的位置,而binarySort中的主要是查找pivot元素插入的位置。
Note: operator >>>代表无符号右移,相当于除以2。

插入排序(Insertion Sort)

插入排序的典型例子就是把扑克牌插入正确的位置。
前提:插入之前的数组已经有序;
步骤:
(0):将大于要插入的元素往右移;
(1):将元素插入已经腾出的位置。

    @SuppressWarnings({"rawtypes", "unchecked"})
    public static void sort(Comparable[] a) {
        assert a != null;

        int N = a.length;
        // i represents index of insertion element; 
        for(int i = 1; i < N; i++) {
            // this loop equals moving larger items one position to the right
            for(int j = i; j > 0 && a[j].compareTo(a[j - 1]) < 0; j--) {
                Comparable temp = a[j];
                a[j] = a[j -1];
                a[j - 1] = temp;
            }
        }
    }

有关插入排序的更多内容请看大神Robert Sedgewick和Kevin Wayna编写的Algorithm(4th Edition)中2.1节的Insertion Sort部分。

binarySort中的排序本质就是Insertion Sort

 for ( ; start < hi; start++) {
        Comparable pivot = (Comparable) a[start];

        ...

       int n = start - left;  // The number of elements to move
       // this switch block equals moving larger items one position to the right
       switch (n) {
            case 2:  a[left + 2] = a[left + 1];
            case 1:  a[left + 1] = a[left];
                   break
            default: System.arraycopy(a, left, a, left + 1, n);
       }
       a[left] = pivot;
  }

Note:使用arraycopy正如注释所说,起到优化的结果。

下一节主要讨论TimSort提到的Run的定义和方法countRunAndMakeAscending(T[] , int , int , Comparator< ? super T>)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值