经典排序之快速排序

package 快速排序;

/*
 * 快排的思想:是一种分治策略,但不同于归并的分治,归并的分治是将数组分成相等的两部分处理问题再最后归并起来,
 * 而快排中间的分治是将数组分成不相等的两部分,就是选取一个支点,然后将小于支点的数据全部都放在支点的左边,将大于
 * 它的数据放在支点的右边,完成一次快排,最后进行递归操作左右部分
 *
 * 其中有一些技巧:首先是选取支点,可以使用三点取中值支点选取法(三点即第一个,中间一个,最后一个)
 *            其次是将支点挪到数组的倒数第二位
 *            
 * 具体方法:首先是选取支点,如上,然后就是从左往右和从右往左的顺序比较各个数据和支点的大小,
 * 左往右:令第一个索引是first+1,因为在三点取值法中已经将第一个和中间一个还有最后一个排好序了,所以直接从第二个开始
 *         若比支点大就停下脚步,等着  从右往左 的数据  比支点小的数据,而且左边索引比右边索引小,然后进行交换
 *       如果不比支点大的话,就继续向前进,注意当数字较小时使用另外的像插入排序之类的方法
 * 右往左同样处理
 */
public class quickSort {
    public static <T extends Comparable<? super T>> void sort(T[] a, int first,
            int last) {

        int MIN_SIZE = 4;
        // 如果排序数量较小就选择 插入排序哈!
        if (last - first + 1 < MIN_SIZE) {
            insertionSort(a, first, last);
        } else {
            // 创建划分,找到支点: 较小部分|支点|较大部分
            int pivotIndex = partition(a, first, last);
            // 对较小部分和较大部分子数组排序 递归的思想
            sort(a, first, pivotIndex - 1);
            sort(a, pivotIndex + 1, last);
        }
    }

    // 找到支点的位置
    public static <T extends Comparable<? super T>> int partition(T[] a,
            int first, int last) {
        // 三者取中值支点选择法 选择中间的值作为支点
        int mid = (first + last) / 2;
        if (a[first].compareTo(a[mid]) > 0)
            swap(a, first, mid);
        if (a[mid].compareTo(a[last]) > 0)
            swap(a, mid, last);
        if (a[first].compareTo(a[mid]) > 0)
            swap(a, first, mid);

        // 将支点移到数组的倒数第二个位置
        swap(a, mid, last - 1);
        int pivotIndex = last - 1;
        T pivot = a[pivotIndex];

        int indexFromLeft = first + 1;
        int indexFromRight = last - 2;

        boolean flag = false;
        while (!flag) {
            // 从左边往右边移动,当左边值小于支点值时不移动
            while (a[indexFromLeft].compareTo(pivot) < 0) {
                indexFromLeft++;
            }
            // 从右边往左边移动,当右边值大于支点值时不移动
            while (a[indexFromRight].compareTo(pivot) > 0) {
                indexFromRight--;
            }

            // 左边索引<右边索引 且左边值大于支点,右边值小于支点时
            if (indexFromLeft < indexFromRight) {
                swap(a, indexFromLeft, indexFromRight);
                indexFromLeft++;
                indexFromRight--;
            } else
                flag = true;

        }// end while()

        swap(a, pivotIndex, indexFromLeft);
        pivotIndex = indexFromLeft;

        return pivotIndex;

    }

    // 交换……
    private static void swap(Object[] arr, int i, int j) {
        Object item = arr[i];
        arr[i] = arr[j];
        arr[j] = item;
    }

    private static <T extends Comparable<? super T>> void insertionSort(T[] a,
            int first, int last) {
        for (int i = 1; i < a.length; i++) {
            int j = i - 1;
            T item = a[i];
            while (j >= 0&&a[j].compareTo(item) > 0) {
                a[j + 1] = a[j];
                j--;
            }
            a[j + 1] = item;
        }
    }

    // 测试
    public static void main(String[] args) {
        Integer[] a = {26,134,1246,242,643, 12, 2345, 13534, 242, 534, 24433, 42342, 535,};
        sort(a, 0, a.length - 1);
        for (int i = 0; i < a.length; i++)
            System.out.print(a[i] + ", ");
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值