快排的三种优化方式。

对于快排而言,其核心在partition中,主要是对于pivot的选取上,所以我们可以按以下三种方案进行优化:

1.在数组长度大于某一个阈值范围时,我们进行递归快排,当数据长度小于阈值时,我们进行插入排序。

2.在partition中选取pivot时,选取首尾中的进行比较,选取中位数为pivot,以保证pivot能够尽可能的固定在中间,而让两端递归的子数组更加均衡。

3.进行三路partition优化。即将数组划分为左边小于pivot,中间等于pivot,右边大于pivot,这样两端递归时可以缩小递归数组的大小,大大提高效率。

第三种算法代码如下:

private void quickSort(int[] a, int left, int right) {
    if (right <= left)
        return;

    /* 
     * 工作指针
     * p指向序列左边等于pivot元素的位置
     * q指向序列右边等于Pivot元素的位置
     * i指向从左向右扫面时的元素
     * j指向从右向左扫描时的元素
     */
    int p, q, i, j;
    int pivot;// 锚点
    i = p = left;
    j = q = right - 1;
    /*
     * 每次总是取序列最右边的元素为锚点
     */
    pivot = a[right];
    while (true) {
        /*
         * 工作指针i从右向左不断扫描,找小于或者等于锚点元素的元素
         */
        while (i < right && a[i] <= pivot) {
            /*
             * 找到与锚点元素相等的元素将其交换到p所指示的位置
             */
            if (a[i] == pivot) {
                swap(a, i, p);
                p++;
            }
            i++;
        }
        /*
         * 工作指针j从左向右不断扫描,找大于或者等于锚点元素的元素
         */
        while (left <= j && a[j] >= pivot) {
            /*
             * 找到与锚点元素相等的元素将其交换到q所指示的位置
             */
            if (a[j] == pivot) {
                swap(a, j, q);
                q--;
            }
            j--;
        }
        /*
         * 如果两个工作指针i j相遇则一趟遍历结束
         */
        if (i >= j)
            break;

        /*
         * 将左边大于pivot的元素与右边小于pivot元素进行交换
         */
        swap(a, i, j);
        i++;
        j--;
    }
    /*
     * 因为工作指针i指向的是当前需要处理元素的下一个元素
     * 故而需要退回到当前元素的实际位置,然后将等于pivot元素交换到序列中间
     */
    i--;
    p--;
    while (p >= left) {
        swap(a, i, p);
        i--;
        p--;
    }
    /*
     * 因为工作指针j指向的是当前需要处理元素的上一个元素
     * 故而需要退回到当前元素的实际位置,然后将等于pivot元素交换到序列中间
     */
    j++;
    q++;
    while (q <= right) {
        swap(a, j, q);
        j++;
        q++;
    }

    /*
     * 递归遍历左右子序列
     */
    quickSort(a, left, i);
    quickSort(a, j, right);
}

private void quick(int[] a) {
    if (a.length > 0) {
        quickSort(a, 0, a.length - 1);
    }
}

private void swap(int[] arr, int a, int b) {
    int temp = arr[a];
    arr[a] = arr[b];
    arr[b] = temp;
}

其核心思想是:设置四个游标,左端a、b,右端c、d。b、c的作用跟之前两路划分时候的左右游标相同,就是从两端向中间遍历序列,并将遍历到的元素与pivot比较,如果等于pivot,则移到两端(b对应的元素移到左端,c对应的元素移到右端。移动的方式就是拿此元素和a或d对应的元素进行交换,所以a和d的作用就是记录等于pivot的元素移动过后的边界),反之,如果大于或小于pivot,还按照之前两路划分的方式进行移动。这样一来,中间部分就和两路划分相同,两头是等于pivot的部分,我们只需要将这两部分移动到中间即可。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值