【算法设计与分析】分治算法(四)快速排序

实验目的

1)了解分治策略算法思想及基本原理;
2)掌握使用分治算法求解问题的一般特征;
3)掌握分解、治理的方法;
4)能够针对实际问题,能够正确的分解、治理,设计分治算法;
5)能够正确分析算法的时间复杂度和空间复杂度。

实验内容(要求)

代码实现快速排序

算法设计(问题分析、建模、算法描述)

问题分析:
     基本思想为通过一次排序将需要排序的序列分割成独立的两部分,首先设置一个基准数,进行一次排序后,其中一部分的所有数据比基准数小,另一部分的所有数据都比基准数大,这样基准数当前位置就是其在有序序列的位置,然后对新分出的两个序列递归地进行排序处理(由于两方互不影响,其满足最优子结构,有独立性),直到序列大小最小,这样通过一次分治的排序可以将所有元素放到有序序列的正确位置上,从而将整个序列有序化。

算法描述:

  1. 确定分界点: q[i] or q[(l+r)/2] or q[r] or 随机;
  2. 调整区间:把小于等于x的数放在x左边,大于等于x的数放在右边(等于x的在哪无所谓);
  3. 递归处理左右两段

优化版:(一种不太优美的暴力做法,浪费一点空间,但是思路简单)

  1. 开两个额外的数组a[ ],b[ ];
  2. 扫描整个区间q[ l ~ r ]
    q[i] <= x , x -> a[ ];
    q[i] >= x , x -> b[ ];
    3.先把a[ ]放入q[ ],再把b[ ]放入q[ ]。

超级优化版:(很优美的方法,不需要额外空间,用两个指针i, j实现)

  1. i -> l , j -> r
  2. 两个指针向中间移动(先移动还是后移动看1.步骤的指向)i 先向右移动,当 i 扫到 <= x的数时,停下。j 向左移动,当 j 扫到 >= x的数时,停下,交换两个指针指向的值。
  3. i 和 j 相遇,停止。
  4. 递归分别判左区域(l, i)和右区域(i+1, r)。
    注意边界问题,取到左边界就会死循环。

算法源码

#include<iostream>

using namespace std;
const int N = 1e6 + 10;
int n;
int q[N];

void quick_sort(int q[], int l, int r)
{
    if(l >= r) return;

    int x = q[l], i = l - 1, j = r + 1;
    while(i < j)
    {
        do i ++ ; while(q[i] < x);
        do j -- ; while(q[j] > x);
        if(i < j) swap(q[i], q[j]);
    }

    quick_sort(q, l, j);
    quick_sort(q, j + 1, r);
}

int main()
{
    scanf("%d", &n);
    for(int i = 0; i < n; i ++ ) scanf("%d", &q[i]);

    quick_sort(q, 0, n - 1);

    for(int i = 0; i < n; i ++ ) printf("%d ", q[i]);

    return 0;
}

测试数据及运算结果(要求:截图说明算法运行的结果)

测试数据1:
6
19 78 56 45 30 74

输出结果:
在这里插入图片描述

测试数据2:
10
2 8 7 5 8 8 1 0 3 9

输出结果:
在这里插入图片描述

算法分析(分析算法的时间复杂度和空间复杂度)

时间复杂度: O(n log n)
空间复杂度: O( n )

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

脑瓜上长蘑菇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值