快排实现及优化

一、基本思想:

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,
然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
Partition 是快排的灵魂 , 函数实现了,选择一个主元,主元将数组分为两部分,左边部分小于主元;右边部分大于主元。

二、Partition的两种实现

1. 从头到尾遍历

从头到尾遍历,和主元比较,大的不管,小的换。
参考https://www.cnblogs.com/AlgrithmsRookie/p/5899160.html

int Partition1(int a[], int low, int high)
{
    int x = a[high];//将数组最后一个数作主元,用它来对数组进行划分
    //也可以随机选一个作主元,再和最后一个交换
    //int index = RandomINRange(low,high);
    //int x = a[index];
    //swap(a[index],a[high]);
    int i = low;
    for(int j=low;j<high;j++)//high不取等
    {
        if(a[j]<x)//从头到尾,和主元比较,大的不管,小的换
            swap(a[j],a[i++]);
    }
    swap(a[i],a[high]);//把主元放到i的位置
    return i;
}

2. 两头往中间扫

参考https://blog.csdn.net/AA2519556/article/details/77884962
取区间第一个数为基准数。先从后向前找,再从前向后找

int Partition2(int a[], int low, int high)
{
    int x = a[low];//第一个做主元
    while(low<high)
    {
        while(a[high]>=x && low<high)high--;//找到当前右边第一个比key小的值  
        a[low] = a[high]; //不用写成交换两个数,直接赋值
        while(a[low]<=x && low<high)low++;
        a[high] = a[low];
    }
    a[low] = x;//跳出循环时low=high 
    return low;
}

递归实现快排

void Quicksort(int a[],int low, int high)
{
    if(low<high)
    {
        int q = Partition2(a,low,high);
        Quicksort(a,low,q-1);
        Quicksort(a,q+1,high);
    }
}

三、优化

参考https://baike.baidu.com/item/%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/369842?fr=aladdin

1. 选轴

)选用待排数组最左边、最右边和最中间的三个元素的中间值作为中轴。
)随机选取中轴

2. 根据分区大小调整算法

快速排序对于小规模的数据集性能不是很好
当分区的规模达到一定小时,便停止快速排序算法
也即快速排序算法的最终产物是一个“几乎”排序完成的有序数列。数列中有部分元素并没有排到最终的有序序列的位置上,但是这种元素并不多。可以对这种“几乎”完成排序的数列使用插入排序算法进行排序以最终完成整个排序过程。
插入排序对于这种“几乎”完成的排序数列有着接近线性的复杂度。

3. 区间三分

当要分区的所有的元素值都相等时,一般的快速排序算法就陷入了最坏的一种情况,也即反复的交换相同的元素并返回最差的中轴值。无论是任何数据集,只要它们中包含了很多相同的元素的话,这都是一个严重的问题,因为许多“底层”的分区都会变得完全一样。
  对于这种情况的一种改进办法就是将分区分为三块而不是原来的两块:一块是小于中轴值的所有元素,一块是等于中轴值的所有元素,另一块是大于中轴值的所有元素。另一种简单的改进方法是,当分区完成后,如果发现最左和最右两个元素值相等的话就避免递归调用而采用其他的排序算法来完成。

4. 并行

由于快速排序算法是采用分治技术来进行实现的,这就使得它很容易能够在多台处理机上并行处理。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
快速排序是一种经典的排序算法,其主要思想是通过分治法将一个数组分为个子数组,然后递归地对个子数组进行排序。 以下是快速排序的几种常见实现方式: 1. Hoare算法 Hoare算法是最初实现快速排序的算法,它使用个指针分别从数组的端开始扫描,当左指针指向的元素大于基准元素时,停止扫描;当右指针指向的元素小于基准元素时,停止扫描,然后交换左右指针所指向的元素,最后将基准元素放到最终的位置上。 ``` void quicksort(int arr[], int left, int right) { if (left >= right) return; int i = left, j = right, pivot = arr[left]; while (i <= j) { while (arr[i] < pivot) i++; while (arr[j] > pivot) j--; if (i <= j) { swap(arr[i], arr[j]); i++; j--; } } quicksort(arr, left, j); quicksort(arr, i, right); } ``` 2. Lomuto算法 Lomuto算法是另一种常见的快速排序实现方式,它使用单个指针从左向右扫描数组,并将小于基准元素的元素交换到数组的左侧,最后将基准元素放到最终的位置上。 ``` void quicksort(int arr[], int left, int right) { if (left >= right) return; int i = left, j = left; for (; j < right; j++) { if (arr[j] < arr[right]) { swap(arr[i], arr[j]); i++; } } swap(arr[i], arr[right]); quicksort(arr, left, i - 1); quicksort(arr, i + 1, right); } ``` 3. 双向扫描 双向扫描是一种优化快速排序算法,它使用个指针分别从数组的端开始扫描,并且每次交换的元素都是不同的。这种算法可以减少交换次数,并且可以处理有大量重复元素的情况。 ``` void quicksort(int arr[], int left, int right) { if (left >= right) return; int i = left, j = right, pivot = arr[left + (right - left) / 2]; while (i <= j) { while (arr[i] < pivot) i++; while (arr[j] > pivot) j--; if (i <= j) { if (i < j) swap(arr[i], arr[j]); i++; j--; } } quicksort(arr, left, j); quicksort(arr, i, right); } ``` 无论使用哪种实现方式,快速排序的平均时间复杂度为O(nlogn),最坏情况下的时间复杂度为O(n^2),空间复杂度为O(logn)。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值