快速排序(详细图解 单路、双路、三路)

本文详细介绍了快速排序算法,包括单路、双路和三路排序的原理与实例解析。通过选取基准值,将数组分为小于、等于和大于基准值的三个区域,实现高效排序。并提供了相应的代码实现,特别是对于含有大量相等元素的数组,三路快速排序能显著提升效率。

一、快速排序

        选取待排序数组的任意一个数据作为基准值,遍历数组中的元素。将小于基准值的元素放在基准值的左边,大于基准值的放在基准值的右边,将基准值放在中间,此时基准值到达了最终位置。然后对基准值左边的子数组和右边的子数组采用同样的方式进行处理,直到区间缩小为1,就说明数组有序

二、单路排序

例题:给定一长度为10的数组{6,1,2,7,9,3,4,5,10,8}

解题步骤;

(1)快速排序的思想为将数组首元素6移动至序列的某一位置M,让M左侧的元素均<=6,M的右侧元素均>=6;因此我们需定义两个指针i和j分别位于序列的首尾;

(2)i依次向后移动(i++)移动至大于6的元素停下,j向前移动(j--)移动至小于6的元素,并将i,j对应的元素交换。

 (3)依照(2)的步骤依次遍历直到i,j重合;又因重合时所指元素为3,3<6两者交换;此时6的左边均小于6,6的右边均大于6。

(4)此时的序列元素6的左边均小于6,右边均大于6;取6的左部分重复(1)(2)(3)的步骤直到序列首元素为1;

(5)6的右部分也和左部分同理;

(7)代码实现;由(1)~(6)可知实现步骤一直是在重复,因此利用递归方法。

void Quick_Sort(int *arr, int begin, int end){
    if(begin > end)
        return;
    int tmp = arr[begin];
    int i = begin;
    int j = end;
    while(i != j){
        while(arr[j] >= tmp && j > i)
            j--;
        while(arr[i] <= tmp && j > i)
            i++;
        if(j > i){
            int t = arr[i];
            arr[i] = arr[j];
            arr[j] = t;
        }
    }
    arr[begin] = arr[i];
    arr[i] = tmp;
    Quick_Sort(arr, begin, i-1);
    Quick_Sort(arr, i+1, end);
}

三、双路排序

        之前说的快速排序算法是将>v和<v两个部分元素都放在索引值i所指向的位置的左边部分,而我们的双路快速排序算法则不同,他使用两个索引值(i、j)用来遍历我们的序列,将<v的元素放在索引i所指向位置的左边,而将>v的元素放在索引j所指向位置的右边。

(1)代码实现;

 
 
import java.util.Arrays;
import java.util.Random;
 
 
public class QuickSort {
 
    private static Random random;
    private QuickSort() {
 
    }
 
    
    public static <E extends Comparable<E>> void sort2ways(E[] arr) {
        random = new Random();
        sort2ways(arr, 0, arr.length - 1);
    }
 
    private static <E extends Comparable<E>> void sort2ways(E[] arr, int l, int r) {
        if (l >= r) {
            return;
        }
        int p = partition2(arr, l, r);
        sort2ways(arr, l, p - 1);
        sort2ways(arr, p + 1, r);
    }
 
    private static <E extends Comparable<E>> int partition2(E[] arr, int l, int r) {
 
        // 生成[l,r]之间的随机索引
        int p = l+random.nextInt(r-l+1);
        swap(arr,l,p);
 
        // arr[l+1...i-1]<= v;arr[j+1...r]>=v
        int i = l+1,j = r;
        while (true){
 
            while (i<=j && arr[i].compareTo(arr[l])<0)
                i++;
            while (j>=i && arr[j].compareTo(arr[l])>0)
                j--;
 
            if (i>=j)
                break;
 
            swap(arr,i,j);
            i++;
            j--;
        }
        swap(arr,l,j);
        return j;
 
    }
 
 
}

四、三路排序

        将整个数组按照划分值v,分成小于v的区域称为小于区,等于v的区域等于区和大于v的区域大于区三部分,在下一次的递归中就不必再处理等于v的等于区,因为等于区的元素已经到达了最终位置,对于存在大量等于v的数组三路快排大大提升了效率。

(1)代码实现

import java.util.*;
 
public class QuickSort3Ways {
 
    // 递归使用快速排序,对arr[l...r]的范围进行排序
    private static void sort(Comparable[] arr, int l, int r){
 
        // 对于小规模数组, 使用插入排序
        if( r - l <= 15 ){
            InsertionSort.sort(arr, l, r);
            return;
        }
 
        // 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot
        swap( arr, l, (int)(Math.random()*(r-l+1)) + l );
 
        Comparable v = arr[l];
 
        int lt = l;     // arr[l+1...lt] < v
        int gt = r + 1; // arr[gt...r] > v
        int i = l+1;    // arr[lt+1...i) == v
        while( i < gt ){
            if( arr[i].compareTo(v) < 0 ){
                swap( arr, i, lt+1);
                i ++;
                lt ++;
            } else if( arr[i].compareTo(v) > 0 ){
                swap( arr, i, gt-1);
                gt --;
            } else{ // arr[i] == v
                i ++;
            }
        }
 
        swap( arr, l, lt );
 
        sort(arr, l, lt-1);
        sort(arr, gt, r);
    }
 
    public static void sort(Comparable[] arr){
 
        int n = arr.length;
        sort(arr, 0, n-1);
    }
 
    private static void swap(Object[] arr, int i, int j) {
        Object t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
    }
 
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值