排序笔记_5( 快速排序)

package com.chapter_two;

import java.util.Random;

/***
 * 普通的快速排序 (Quick)
 * 
 * @author LuodiJack
 * 
 *         思想:分治思想。将一个数组分成两个数组,将两部分独立排序, 关键在切分。
 * 
 *         和归并排序比较:
 * 
 *         快速排序和归并排序是互补的,归并排序将数组分成两个子数组分别排序,
 * 
 *         并将有序的数组归并以将整个数组排序;
 * 
 *         而快速排序将数组排序的方式则是当两个子数组都有序时整个数组自然也就有序了。
 * 
 *         第一种情况下,递归调用发生在处理整个数组之前,第二种情况下则相反(详见代码)。
 * 
 *         关键:切分方法。
 * 
 * 
 *         改进:
 * 
 *         ①切换到插入排序
 * 
 *         对于小数组插入排序要比快速排序快;
 * 
 *         因为递归,快速排序的sort()方法在小数组中也会调用自己。
 * 
 *         因此,在排序小数组时应该改成插入排序。
 * 
 *         即:
 * 
 *         将sort()中的语句 ------- if( high <= low) return;
 * 
 *         改成:if( high <= low + M) { Insertion.sort(a, low, high); return; }
 * 
 *         转换参数M的最佳值是和系统相关的,但是 5~15 之间的任意值在大多数情况下都能令人满意。
 * 
 *         ②三取样切分
 * 
 *         使用子数组的一小部分元素的中位数来切分数组。这样做得到的切分更好(今后实现)。
 * 
 *         ③熵最优的排序 P187
 * 
 *         将数组切分成三部分,分别对应小于、大于、和等于切分元素的数组元素。
 * 
 *         [详见三向切分的快速排序(Quick3Way.java)](http://blog.csdn.net/a199581/article/details/50688491)
 */

public class Quick {
    /***
     * 先任意的去a[low]为切分元素,即那个将会被排定的元素,
     * 
     * 然后我们从数组的左端开始向右扫描,直到找到一个大于等于它的元素,
     * 
     * 再从数组的右端开始向左扫描,直到找到一个小于等于它的元素,
     * 
     * 交换他们的位置。如此继续,我们就可以保证左指针 i 的左侧元素都不大于切分元素,
     * 
     * 右指针 j 的右边的元素都不小于切分元素,
     * 
     * 当两个指针相遇时,我们只需要将切分元素 a[low] 和左子数组最右侧的元素(即 a[j])交换,
     * 
     * 然后返回 j 即可。
     * 
     * @param a
     *            排序数组
     * @param low
     *            下界
     * @param high
     *            上界
     * @return 经一次排序后切分元素的位置
     */
    @SuppressWarnings("rawtypes")
    private static int partition(Comparable[] a, int low, int high) {
        int i = low;
        int j = high + 1;
        Comparable v = a[low];
        while (true) {
            while (Template.less(a[++i], v)) {
                if (i == high) {// 可以去掉
                    break;
                }
            }
            while (Template.less(v, a[--j])) {
                if (j == low) {// 可以去掉
                    break;
                }
            }

            if (i >= j) {
                break;
            }
            Template.exch(a, i, j);
        }
        Template.exch(a, low, j);
        return j;
    }

    @SuppressWarnings("rawtypes")
    private static void shuffle(Comparable[] a) {// 将数组a的元素重新打乱顺序
        for (int i = 0; i < a.length; i++) {
            int index = new Random().nextInt(a.length);
            Comparable tmp = a[index];
            a[index] = a[i];
            a[i] = tmp;
        }
    }

    @SuppressWarnings("rawtypes")
    public static void sort(Comparable[] a) {
        shuffle(a);// 消除对输入的依赖 P186 比如说第一、二次或者每一次都从最小的元素切分,
                    // 则每次只会移除一个元素,效率很低。
        sort(a, 0, a.length - 1);
    }

    @SuppressWarnings("rawtypes")
    private static void sort(Comparable[] a, int low, int high) {
        if (high <= low) {
            return;
        }
        int j = partition(a, low, high);
        sort(a, low, j - 1);
        sort(a, j + 1, high);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值