快速排序及优化

快速排序

顾名思义,快速排序是时间复杂度比较快的一种排序。

1. 快速排序

快速排序的算法思想是:通过一趟排序将待排序的数组分割成两部分,其中一部分的关键字均比另一部分的关键字小,然后继续对这两部分继续排序,最后整个序列就是有序的了。很明显,快速排序的思想的一种递归的思想。
首先要选择一个关键字作为枢轴值,然后想办法使得将它放到一个位置,使得左边的值小于枢轴值,右边的值大于枢轴值。
其中最重要的就是这个合适的位置怎么找?
可以使用一个low和high分别指向要排序的这一段的第一个关键字和最后一个关键字,然后从high向前和枢轴值比较,如果枢轴值大,high向前移动,知道出现枢轴值大于high所指向的关键字,然后将high和low所指向的关键字交换,然后又从low开始向后比较枢轴值和如果枢轴值比low指向的关键字大时,交换high和low所指向的关键字。重复上述过程直到low >= high。
假设现在要排序的数组为{45, 64, 13, 25, 48, 78, 32, 11},选择枢轴值为第一个关键字45,如下图,然后从high开始比较,11小于45,所以将high和low所指向的关键字交换;然后接下来从low开始,11小于45,当然low的加1,然后64大于45,所以将low和high所指向的关键字交换……
快速排序
上述的这个过程的实现如下:

while (low < high) {
        while (low < high && a[high] >= pivotKey)
            high--;
        temp = a[low];
        a[low] = a[high];
        a[high] = temp;
        while (low < high && a[low] <= pivotKey)
            low++;
        temp = a[low];
        a[low] = a[high];
        a[high] = temp;
    }

快速排序的代码如下:

// 交换函数
void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}
// 因为是递归实现的所以会有下面的这个函数
void QuickSort(int a[], int n) {
    QSort(a, 0, n - 1);
}
// 下面的这个函数是递归进行对数组进行分割排序
void QSort(int a[], int low, int high) {
    int pivot;
    if (low < high) {
        // 将a数组一分为二,并算出枢轴值pivot
        pivot = Partition(a, low, high);
        // 对低于枢轴值的表排序
        QSort(a, low, pivot - 1);
        // 对高于枢轴值的表排序
        QSort(a, pivot + 1, high);
    }
}
// 下面这个函数的作用是定位枢轴值
int Partition(int a[], int low, int high) {
    int pivotKey;
    pivotKey = a[low];
    // 核心
    while (low < high) {
        while (low < high && a[high] >= pivotKey)
            high--;
        swap(&a[low], &a[high]);
        while (low < high && a[low] <= pivotKey)
            low++;
        swap(&a[low], &a[high]);
    }
    return low;
}

void QSort(int a[], int low, int high) {
    int pivot;
    if (low < high) {
        // 将a数组一分为二,并算出枢轴值pivot
        pivot = Partition(a, low, high);
        // 对低于枢轴值的表排序
        QSort(a, low, pivot - 1);
        // 对高于枢轴值的表排序
        QSort(a, pivot + 1, high);
    }
}

2. 快速排序的时间复杂度

快速排序的时间复杂度的计算很复杂,总的来说它的时间复杂度为O(nlogn)。

3. 排序算法的优化

上面的只是最基本的快速排序,当然它也可以优化。

3.1 优化选择枢轴值

枢轴值的作用是将数组或者表分成两部分,使得前半部分小于枢轴值,后半部分大于枢轴值。**枢轴值选择的最好情况是有序数组中间的那个关键字,**因为这样的话分成的前后两部分的长度将一样大或者差1,这样选择枢轴值递归的深度将是最低的。
之前的快排算法中,我们选择的枢轴值都是low所指向的关键字,如果需要排序的数组是一个基本有序的,那么固定的选择第一个值肯定是不合理的。
当然出现问题,就会有人改进,有人提出在low和high随机选择一个作为枢轴值。既然是随机的,那么它有可能会比之前的更块,也有可能比之前的更慢。
再继续改进就出现了三数取中法,意思就是在low所指向的关键之和(low+high)/2所指向的关键字以及high所指向的关键字中取一个中间值作为枢轴值。这种方法比之前的那种方法靠谱多了。
代码如下:

int Partition(int a[], int low, int high) {
    int pivotKey;
    int mid = (low + high) / 2;
    if (a[low] > a[high]) {
        swap(&a[low], &a[high]);
    }
    if (a[mid] > a[high]) {
        swap(&a[mid], &a[high]);
    }
    if (a[mid] > a[low]) {
        swap(&a[mid], &a[low]);
    }
    // 此时的a[low]已经是三个值中的中间值了。
    pivotKey = a[low];
    while (low < high) {
        while (low < high && a[high] >= pivotKey)
            high--;
        swap(&a[low], &a[high]);
        while (low < high && a[low] <= pivotKey)
            low++;
        swap(&a[low], &a[high]);
    }
    return low;
}

3.2 优化不必要的交换

从上面的那张图中不难看出,枢轴值在排序的过程中不断的在和其它的数字交换,这是因为定位的枢轴值,所以才会存在在排序的过程中出现大量其它数字和枢轴值交换的过程。但是其中的好多交换其实是没有必要的。因此可以对这里进行优化。优化的措施是将原本的交换变成替换。
代码如下:

int Partition(int a[], int low, int high) {
    int pivotKey;
    int mid = (low + high) / 2;
    if (a[low] > a[high]) {
        swap(&a[low], &a[high]);
    }
    if (a[mid] > a[high]) {
        swap(&a[mid], &a[high]);
    }
    if (a[mid] > a[low]) {
        swap(&a[mid], &a[low]);
    }
    // 此时的a[low]已经是三个值中的中间值了。
    pivotKey = a[low];
    while (low < high) {
        while (low < high && a[high] >= pivotKey)
            high--;
        a[low] = a[high];
        while (low < high && a[low] <= pivotKey)
            low++;
        a[high] = a[low];
    }
    a[low] = pivotKey;
    return low;
}

3.3 优化小数组的排序

这种优化不能算是对快速排序算法的优化,它是对于排序的优化,对数组小的时候,快速排序不如直接插入排序快,(直接插入排序时简单排序中性能最好的)所以可以加个判断当数组的长度小于某个数时采用直接插入排序。当然这个数组有人认为7个比较好,有人认为50个更好。
这个比较简单这里就不给出代码了。

3.4 优化快排的递归操作

众所周知,递归对于算法的性能是有影响的。如果对于一个逆序的数组,之前的那种方式的递归将变得极不平衡。而且栈的大小也是有限的。这里可以使用尾递归,将两次递归操作变成一次递归。代码如下:

void QSort(int a[], int low, int high) {
    int pivot;
    while (low < high) {
        // 将a数组一分为二,并算出枢轴值pivot
        pivot = Partition(a, low, high);
        QSort(a, low, pivot - 1);   
        low = pivot + 1;
    }
}

上面这个尾递归将低子表使用递归进行处理,而将高子表使用循环处理,这样就大大的减少了栈空间的使用,从而提高了性能。
源码链接

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
神速百度SEO排名优化器主要为广大站长提供网站排名优化功能。可以按百度和(google)的规则快速提升指定关键词的排名。 神速百度SEO排名优化软件特点: 1、最容易收录的是.html的静态页面; 2、网页内容中关键词的密度和突出性(包括Title、DeScription和Keyword,还有正文中关键词的密度); 3、网站结构(目录的结构); 4、更新频率; 5、内容的价值(主要看是否是原创); 6、外链的价值; 神速百度SEO排名优化软件功能: 1、您可以指定几个您网站内容相关的关键词,软件可以自动通过这些关键词搜索到与您网站内容相符的文章。并下载。 2、用这些文章自动生成网页,并按随机而合理的密度插入您指定的关键词,自动配置好网页中的Title、DeScription和Keyword,插入关键词的网页和原文件已经不同,所以,内容接近原创,更容易得到百度的信任。并按指定的间隔上传生成的网页,建议每10小时上传一次。 3、定时更新上传优化的网页,增强网站的活跃性,使百度收录您网站内容的频率更快,网站排名迅速上升。 4、自动生成网站地图,也就是您所知道的sitemap.xml文件,但我们的软件会给它自动随机生成一个文件名,这样,就不容易被百度抓到规律K站了。上传网页自动更新网站地图文件。在百度站长平台提交网站地图文件后,百度会自动更新您的网页列表。 5、自动生成优化网页的列表,使优化网页的内链更合理。 6、自动交换友情链接,自动形成友情链接的联盟。您的网址将会被成千上万个网站做反向链接。网站权重迅速上升。 用以上的方法,可以迅速提升您的网站排名,根据难度不同,理论上,排到第一页只是时间问题。 注意:生成的优化网页与您制作的网页是分开的,不会影响您正常网页的内容,优化的目的是提升网站在搜索引擎中的权重,权重高了,您的正常内容自然就会排到前面。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值