递归与分治策略之快速排序

前言

快速排序是基于分治策略的一个排序算法,时间复杂度为 O(NlogN) ,故效率较高,也因此被广泛使用。

快速排序的基本思想

快速排序分为三步:
(1)分解:选取一个基准,使得该基准左边的数都小于它,右边的数都大于它!
(2)递归求解:在次对该基准的左右两边递归进行步骤(1)的操作,知道最后只剩下一个元素
(3)合并:逐步将选取的基准与左右两边已经排序好的数列进行合并。

图形解析

我们以如下数据进行算法分析:

0123456
3343883686015

第一步进行分解,选取基准a[0]=33 i=0 j=6

  • 从右往左扫描,遇到比基准小的则交换
    我们找到15比33小,交换后为:
0123456
1543883686033

此时,i=1 j=6

  • 从左往右扫描,遇到比基准大的则交换
    我们找到43比33大,交换后为:
0123456
1533883686043

此时,i=1 j=5

  • 从右往左扫描,遇到比基准小的则交换
    我们找到8比33小,交换后为:
0123456
1588836336043

此时,i=2 j=5

  • 从左往右扫描,遇到比基准大的则交换
    我们找到88比33大,交换后为:
0123456
1583336886043

此时,i=2 j=3

  • 从右往左扫描,遇到比基准小的则交换
    最后当j==i==2的时候,说明第一遍排序完成,最终结果:
0123456
1583336886043

下面就是递归的用上面的算法对基准左右数组进行上叙步骤,就可以得到一个从小到大排序好的数组。

算法描述

在编写算法的时候,我们可以考虑优化上面图解:
因为基准是不变的,而且每次都是在与基准进行交换,并且最后总是a[i]==a[j]==基准
故,我们可以将基准单独存放,最后一次填充即可,无需做很多次的交换!

#include<stdio.h>
#include<string.h>

void quickSort(int a[], int i, int j) { //i 是左边游标 j是右边游标
    if(i<j) {
        int l=i,r=j,base=a[l];  //设置左边游标位置 右边游标位置 以及基准
        while(l<r) {
            while(a[r]>base&&r>l) {     //从右往左扫描
                r--;
            }

            //找到右边一个比基准小的
            if(l<r) {               //判断是否j>i
                a[l++]=a[r];
            }

            while(a[l]<base&&r>l) {     //接下来,从左往右扫描
                l++;
            }
            //找到左边一个比基准大的

            if(l<r) {               //判断是否i<j
                a[r--]=a[l];
            }
        }
        //扫描完成 ,填充基准 此时 l==r
        a[l]=base;
        //依次对左右调用上面的算法
        quickSort(a,i,l-1);
        quickSort(a,l+1,j);
    }
}

int main() {

    int a[100];
    int n;
    printf("请输入数组大小:");
    scanf("%d",&n);
    for(int i=0; i<n; i++) {
        scanf("%d",&a[i]);
    }

    quickSort(a,0,n-1);
    for(int i=0; i><n; i++) {
        printf("%d ",a[i]);
    }
    putchar('\n');
}

最后

OJ链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2020
杭电OJ的这一题只是做了一点点小小的变形!

    原文作者:递归与分治算法
    原文地址: https://blog.csdn.net/zjq_1314520/article/details/74143438
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞