排序算法学习经验(四)

来源:互联网 发布:刷手淘宝号 编辑:程序博客网 时间:2024/06/05 13:29

上次提到了快速排序并的基本实现方法,并简单分析了导致快速排序极度不平衡的情况发生的原因,针对这个原因,双路快排或许能够减少这种不平衡发生的次数。
双路快排
双路快排的原理是在快速排序的基础上,使标定点两边,关键码等于标定点的元素分布平衡,而不是全部分布在左半部分。
具体实现思路如下:
1.选定标定点同快速排序,用swap(arr[l], arr[rand() % ( r - l + 1) +l)]),然后标定点为arr[l]。
2.首先定义i为最后一个小于等于标定点的关键码的下标,j为第一个大于等于标定点的关键码的下标。
3.然后从标定点的下一个元素开始(即arr[l + 1]开始),向后扫描,如果arr[i]小于标定点的关键码,则继续向后扫描,直到arr[i]大于或者等于标定点的关键码后停止。
同理,从数组的最后一个元素开始(即arr[r]开始),向前扫描,如果arr[j]大于标定点的关键码,则继续向前扫描,直到arr[j]小于或等于标定点的关键码后停止。
4.此时,i下标对应的元素和j下标对应的元素进行交换(这一步就将快速排序的不平衡优化了),使与标定点相等关键码的元素比较均匀地分布在两边。
5.当i>j时,循环结束。
6.partition完成

下面看看C++代码实现:

#pragma once#include<iostream>using namespace std;//对小规模数组,使用插入排序优化template<typename T>void insertionSort3(T arr[], int l, int r){    for (int i = l + 1; i <= r; i++)    {        T e = arr[i];        int j;        for (j = i; arr[j - 1] > e && j > l; j--)        {            arr[j] = arr[j - 1];        }        arr[j] = e;    }}template<typename T>int partition2(T arr[], int l, int r){    //选定标定点    swap(arr[l], arr[rand() % (r - l + 1) + l]);    T e = arr[l];    int i = l + 1;//最后一个小于等于标定点关键码的元素下标    int j = r;//第一个大于等于标定点关键码的元素下标    while (true)    {        //向后扫描,到arr[i]>=e时停止        while (i <= r && arr[i] < e)        {            i++;        }        //向前扫描,到arr[i]<=e时停止        while (j >= l + 1 &&arr[j] > e)        {            j--;        }        if (i > j)            break;        //平衡操作        swap(arr[i], arr[j]);        i++;        j--;    }    swap(arr[l], arr[j]);    return j;}template<typename T>void __quickSort2Ways(T arr[], int l, int r){    //递归到底的情况,和前面类似用插入排序    if (r - l <= 9)    {        insertionSort3(arr, l, r);        return;    }    int p = partition2(arr, l, r);//标定点                                  //递归到底层后数组就成为有序的数组    __quickSort2Ways(arr, l, p - 1);//左层递归调用,继续partition    __quickSort2Ways(arr, p + 1, r);//右层递归调用,继续partition}template<typename T>void quickSort2Ways(T arr[], int n){    srand(unsigned(time(NULL))); //设置随机种子    __quickSort2Ways(arr, 0, n - 1);  //初次调用}
原创粉丝点击