快排的优化(快排还有优化?)

先说一下,表示我很懵逼,做了一道快排的模板,一直超时,简直要死了,在讨论区一看,啥!!!!!!!还要优化?(没听说过,长知识了)

这是我看的一个非常好的博客,讲解快排的优化方法:三种快排及四种优化方式。

我只是在这里将它的精华提取出来,具体的可以看博客。

首先看一下,这种方法的速度。
快排的优化(快排还有优化?)_第1张图片
最下面的是最终优化的方法,用三数取中+插排+聚集相等元素。

首先是三数取中,因为分析:最佳的划分是将待排序的序列分成等长的子序列,最佳的状态我们可以使用序列的中间的值,也就是第N/2个数。

再则是插排,原因:对于很小和部分有序的数组,快排不如插排好。当待排序序列的长度分割到一定大小后,继续分割的效率比插入排序要差,此时可以使用插排而不是快排
截止范围:待排序序列长度N = 10,虽然在5~20之间任一截止范围都有可能产生类似的结果,这种做法也避免了一些有害的退化情形。摘自《数据结构与算法分析》Mark Allen Weiness 著。

最后是聚集相等元素,这样可以减少重复的遍历,将与基准元素相同的元素,放在基准元素两侧,这样排两边的元素时,就可以去掉这一部分,从而提高效率。

给出一道模板题(需要用快排的优化才能过):P1177 【模板】快速排序
下面是代码:

#include
#include
#include
using namespace std;
const int maxn=1e5+9;
typedef long long ll;

/*函数作用:取待排序序列中low、mid、high三个位置上数据,选取他们中间的那个数据作为枢轴*/
int SelectPivotMedianOfThree(int arr[],int low,int high)
{
    int mid = low + ((high - low) >> 1);//计算数组中间的元素的下标

    //使用三数取中法选择枢轴
    if (arr[mid] > arr[high])//目标: arr[mid] <= arr[high]
    {
        swap(arr[mid],arr[high]);
    }
    if (arr[low] > arr[high])//目标: arr[low] <= arr[high]
    {
        swap(arr[low],arr[high]);
    }
    if (arr[mid] > arr[low]) //目标: arr[low] >= arr[mid]
    {
        swap(arr[mid],arr[low]);
    }
    //此时,arr[mid] <= arr[low] <= arr[high]
    return arr[low];
    //low的位置上保存这三个位置中间的值
    //分割时可以直接使用low位置的元素作为枢轴,而不用改变分割函数了
}
void InsertSort(int arr[],int low,int high)//插入排序,这是我自己写的
{
    int i=low+1;
    int j=high;
    for(;i<=j;i++)
    {
        if(arr[i]>=arr[i-1]) continue;
        int k=i-1,p=arr[i];
        while(k>=low&&arr[k]>p)
        {
            arr[k+1]=arr[k];
            k--;
        }
        arr[k+1]=p;
    }
    return ;
}
void QSort(int arr[],int low,int high)//优化的快排
{
    int first = low;
    int last = high;

    int left = low;
    int right = high;

    int leftLen = 0;
    int rightLen = 0;

    if (high - low + 1 < 10)//用插入排序
    {
        InsertSort(arr,low,high);
        return;
    }

    //一次分割
    int key = SelectPivotMedianOfThree(arr,low,high);//使用三数取中法选择枢轴

    while(low < high)
    {
        while(high > low && arr[high] >= key)
        {
            if (arr[high] == key)//处理相等元素
            {
                swap(arr[right],arr[high]);
                right--;
                rightLen++;
            }
            high--;
        }
        arr[low] = arr[high];
        while(high > low && arr[low] <= key)
        {
            if (arr[low] == key)
            {
                swap(arr[left],arr[low]);
                left++;
                leftLen++;
            }
            low++;
        }
        arr[high] = arr[low];
    }
    arr[low] = key;

    //一次快排结束
    //把与枢轴key相同的元素移到枢轴最终位置周围
    int i = low - 1;
    int j = first;
    while(j < left && arr[i] != key)
    {
        swap(arr[i],arr[j]);
        i--;
        j++;
    }
    i = low + 1;
    j = last;
    while(j > right && arr[i] != key)
    {
        swap(arr[i],arr[j]);
        i++;
        j--;
    }
    QSort(arr,first,low - 1 - leftLen);//去掉与枢轴元素相同的部分
    QSort(arr,low + 1 + rightLen,last);
}

int a[maxn];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0; iscanf("%d",&a[i]);
    }
    QSort(a,0,n-1);
    for(int i=0; iprintf("%d ",a[i]);
    return 0;
}

你可能感兴趣的:(ACM,算法,题目,杂类)