3-排序之快速排序



import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * 快速排序:基于分治思想,将一个数组分成两个数组独立排序,与归并排序是互补的,与归并排序不同的是它不是任意的划分,而是基于某个值的切分,使两边的数组分别不大于
 * 和不小于这个值,所以当两边子数组都有序时整个数组也有序了,并不需要归并;其核心方法是切分,切分的过程也就是排序的过程,每次切分后返回选定值的索引。
 * 时间复杂度:对于长度为N的任意数组,快速排序平均需要 ~2NlogN 次比较,最多需要 ~1/2N^2 次比较,所以排序之前随机打乱很重要,可以避免最坏情况。
 *
 * 改进:
 * 1. 对于小数组,插入排序比快速排序快,只需要修改一行代码 --> if (hi <= lo + M) { Insertion.sort(toBeSortedArray,lo,hi); return;}
 * 2. 三取样切分
 * 3. 三向快速排序:针对包含大量重复元素的数组的排序优化
 */
public class QuickSort {
    private Comparable[]  toBeSortedArray; // 待排序的数组

    public QuickSort(Comparable[] toBeSortedArray) {
        this.toBeSortedArray = toBeSortedArray;
    }

    // 判断 toBeSortedArray[i] 是否小于 toBeSortedArray[j]
    private boolean less(int i, int j) {
        return toBeSortedArray[i].compareTo(toBeSortedArray[j]) < 0;
    }

    // 交换 toBeSortedArray[i] 和 toBeSortedArray[j]
    private void exch(int i, int j) {
        Comparable temp = toBeSortedArray[i];
        toBeSortedArray[i] = toBeSortedArray[j];
        toBeSortedArray[j] = temp;
    }

    // 判断数组是否有序
    public boolean isSorted() {
        for (int i = 1; i < toBeSortedArray.length; i++)
            if (!less(i-1,i))
                return false;
        return true;
    }

    public void sort() {
        // 随机打乱数组
        List<Comparable> list = Arrays.asList(toBeSortedArray);
        Collections.shuffle(list);
        list.toArray(toBeSortedArray);

//        sort2way(0, toBeSortedArray.length-1);
        sort3way(0, toBeSortedArray.length-1);
    }

    // 普通二向切分
    private void sort2way(int lo, int hi) {
        if (hi <= lo) return; // 递归返回条件

        int j = partition(lo, hi);  // 每次递归都会返回一个中间值的位置,必须使用栈内存,所以快速排序的空间复杂度就是栈用的空间 lgN
        sort2way(lo, j-1);  // 左半部分排序
        sort2way(j+1,hi);   // 右半部分排序
    }

    /*
    二向切分:选定第一个位置元素[lo]为切分标准,定义两个扫描指针,i从左往右找>=[lo]的,j从右往左找<=[lo]的,找到则交换它们,
    当i,j第一次相遇后,交换[lo] 和 [j] (因为j一定指向小于等于[lo]的元素);切分的过程也就是排序的过程,每次切分后将数组切分为
    [lo~j-1],[j],[j+1~hi] 最后返回选定值的索引 j。
     */
    private int partition(int lo, int hi) {
        int i = lo;
        int j = hi + 1; // 这里的取值是为了搭配下面的自增自减操作

        for (;;) {
            while (less(++i,lo)) if  (i == hi) break; // 从左往右扫描直到找到大于[lo]的或 到尾
            while (less(lo,--j)) if (j == lo) break; // 从右往左扫描直到找到小于[lo]的或 到头

            if (i >= j) break; // 第一次相遇退出

            exch(i,j); // 交换 [i] 和 [j]
        }

        exch(lo,j); // 最后交换 [lo] 和 [j]

        return j;
    }

    /*
     三向切分:选定一个值v,定义三个扫描指针lt、i、gt,使[lo~lt-1]<v,[lt~i-1]=v,[i~gt]?,[gt+1~hi]>v,一开始 lt=lo, i=lo+1, gt=hi,遍历数组对
     元素[i]进行三向比较:
        [i] < v, exch(lt++, i++);
        [i] > v, exch(gt--, i)
        [i] = v, i++
    最终:a[lo..lt-1] < v = a[lt..gt] < a[gt+1..hi]。
     */
    private void sort3way(int lo, int hi) {
        if (hi <= lo) return; // 递归返回条件

        int lt = lo; int i = lo + 1; int gt = hi; // 初始位置
        Comparable v = toBeSortedArray[lo];       // 选定起始值

        while (i <= gt) {
            int cmp = toBeSortedArray[i].compareTo(v);
            if      (cmp < 0) exch(lt++, i++);
            else if (cmp > 0) exch(i, gt--);
            else              i++;
        }

        // 最终:a[lo..lt-1] < v = a[lt..gt] < a[gt+1..hi]
        sort3way(lo, lt-1);
        sort3way(gt+1, hi);
    }

}

class Test{
    public static void main(String[] args) {
        Integer[] testArray = {5,8,4,1,2,3,7,9,6,0};
        QuickSort quickSortTD = new QuickSort(testArray);
        quickSortTD.sort();
        System.out.println(quickSortTD.isSorted());
        System.out.println(Arrays.toString(testArray));
    }
    /*
    true
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
     */
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种广泛应用于系统编程和嵌入式开发的高级编程语言。函数指针是C语言中的一个重要概念,它可以指向函数,并且可以通过函数指针来调用函数。快速排序算法是一种常用的排序算法,它的核心思想是通过分治的策略将一个大问题分解为多个小问题,并通过递归的方式解决这些小问题。 下面是C语言中使用函数指针实现快速排序算法的示例代码: ```c #include <stdio.h> // 交换两个元素的值 void swap(int* a, int* b) { int temp = *a; *a = *b; *b = temp; } // 快速排序的分区函数 int partition(int arr[], int low, int high) { int pivot = arr[high]; // 选取最后一个元素作为基准 int i = (low - 1); // 定义一个指针,用于指向小于基准的元素 for (int j = low; j <= high - 1; j++) { if (arr[j] < pivot) { i++; swap(&arr[i], &arr[j]); } } swap(&arr[i + 1], &arr[high]); return (i + 1); } // 快速排序函数 void quickSort(int arr[], int low, int high) { if (low < high) { int pi = partition(arr, low, high); // 将数组分区,并获取分区点的位置 quickSort(arr, low, pi - 1); // 对分区点左边的子数组进行快速排序 quickSort(arr, pi + 1, high); // 对分区点右边的子数组进行快速排序 } } // 打印数组元素 void printArray(int arr[], int size) { for (int i = 0; i < size; i++) { printf("%d ", arr[i]); } printf("\n"); } int main() { int arr[] = {10, 7, 8, 9, 1, 5}; int n = sizeof(arr) / sizeof(arr[0]); printf("原始数组:"); printArray(arr, n); quickSort(arr, 0, n - 1); printf("排序后的数组:"); printArray(arr, n); return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值