算法导论-第七章快速排序

快速排序的最坏时间复杂度为θ(n2),但是它的平均性能很好,它的期望时间复杂度为θ(nlgn)

QUICKSORT(A,p,r)

实现了对子数组A[p..r]的原址重排

QUICKSORT(A,p,r)

QUICKSORT(A,p,r)
    if p < r
        q = PARTITION(A,p,r)
        QUICKSORT(A,p,q-1)
        QUICKSORT(A,q+1,r)

对于A[q]的疑问:我们人为的把数组拆分为A[p,q-1]和A[q+1,r]中的每一个元素,使得A[p,q-1]中的每个元素都小于等于A[q],而A[q+1,r]中的每个元素都大于等于A[q]中的每一个元素。而这一目的在我们调用PARTITION(A,p,r)获取q时就已经达到。

PARTITION(A,p,r)

PARTITION(A,p,r)
    x = A[r]        # 作为主元
    i = p - 1
    for j = p to r - 1
        if A[j] <= x
            i = i + 1
            exchange A[i] with A[j]
    exchange A[i + 1] with A[r]
    return i + 1

A:为要排序的目标数组;p、r表示要排序数组的下标范围为[p,r]

在每次执行完PARTITION(A,p,r)后,在循环体的下一轮迭代的开始时,对于任意的数组下标k,有:

  1. 若p<=k<=i,则A[k]<=x

  2. 若i+1<=k<=j-1,则A[k]>=x

  3. 若k==r,则A[k]=x

上面的三种排序后的情况中没有覆盖j<=k<=r-1的情况,在此情况下,元素没有特定的大小关系。也就说PARTITION(A,p,r)函数每次都只专注于A中的指定范围内元素的排序,而对于本次排序范围之外的元素的大小关系不必考虑在内,那是其他时刻需要做的事情。

修改为非递增序

PARTITION(A,p,r)

PARITITION(A,p,r)
    x = A[r]
    i = p - 1
    for j = p to r - 1
        do if A[j] >= x
            then i = i + 1
            exchange A[i] with A[j]
    exchange A[i + 1] with A[r]
    return i + 1
平衡与不平衡的划分
  • 不平衡的划分

    极端情况下,每次划分产生的两个子问题分别包含了n-1个元素和0个元素时,快速排序的最坏情况发生

  • 平衡的划分

    只要划分是常数比例的,算法的运行时间总是O(nlgn)

快速排序的随机化版本

使用随机化版本的快速排序作为大数据输入情况下的排序算法

通过对序列p,…,r的随机抽样,我们可以保证主元元素x=A[r]是等概率地从子数组的r-p+1个元素中选取的

RANDOMIZED-PARTITION(A,p,r)

RANDOMIZED-PARTITION(A,p,r)
    i = RANDOM(p,r)
    exchange A[i] with A[r]
    return PARTITION(A,p,r)

RANDOMIZED-QUICKSOR(A,p,r)

 RANDOMIZED-QUICKSOR(A,p,r)
    if p < r
        q = RANDOMIZED-PARTITION(A,p,r)
        RANDOMIZED-QUICKSOR(A,p,q-1)
        RANDOMIZED-QUICKSOR(A,q+1,r)
拓展

什么是原址排序?

在排序算法中,如果输入数组中仅有常数个元素需要在排序过程中存储在数组之外,则称排序算法是原址的。插入排序、堆排序、快速排序等都是原址排序。归并排序不是原址的。

  • 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、付费专栏及课程。

余额充值