首页 > 编程语言 >C和Python实现快速排序-三数中值划分选择主元(非随机)

C和Python实现快速排序-三数中值划分选择主元(非随机)

时间:2023-02-08 20:34:42浏览次数:50  
标签:sort arr right nums Python 三数 主元 Right left

一、快排基础

1.1 快排的流程

将数组A进行快速排序的基本步骤-quick_sort(A):
image

  • 递归基础情况:如果A中的元素个数是1或0,则返回
  • 选取主元:取A中的任意一个元素v,作为主元(pivot)。
  • 交换策略:将A-{v}即A中剩余元素,划分成两个不相交的集合(多重集)A1和A2,
  • 递归处理:递归调用quick_sort(A1),再调用quick_sort(A2)

伪代码
image

可视化快排
image
选取主元后,将原数组划分为:值小于等于主元的左子数组,值大于等于主元的右子数组。然后递归地对左右子数组进行上述操作,知道递归的基础情况直接返回子数组(递归调用的过程类似二叉树的前序遍历)。

比较基础的情况: 输入数组大小为3, 选取主元并划分后,左子数组和右子数组包含1个数,递归调用快排直接返回,此时已经是有序的。

1.2 主元选取

选取主元: 最优选取到输入数组的中位数,可以均衡进行递归处理。

1)如果直接选择输入数组的第一个元素,在输入数组是有序的情况下,那么将导致快排的最坏情况-平方复杂度。
image
左边每次取一个最小数,每次划分的复杂度和长度成线性递减,但需划分N-1次

2)随机选取主元: 代价不小

3)三数中值分割法:返回Left, Center, Right三个数中的中位数作为主元,避免最坏情况

  • 先让Left<=Center, Left<=Right(若已满足不用管,不满足则交换元素), 使Left是最小数;
  • 那么只需要确定Center, Right的大小。直接通过交换,让Center<=Right, Center即中位数

这时,三数中的最小者被分配在A[Left],其小于pivot; 最大者被分配在A[Right], 其大于pivot。
image
可以把pivot放在 A[Right - 1]并在分割阶段,将左右开始索引i=left, j=right-1(A[Right]已经划分好了)

Left和Right为输入数组的左右边界索引。

C语言实现主元选取
typedef int ElementType;
void Swap( int *a, int *b )
{
     int t = *a;
     *a = *b; 
     *b = t;
}

ElementType Median3( ElementType A[], int Left, int Right )
{   
    int Center = ( Left + Right) / 2;
    if ( A[Left] > A[Center] )
        Swap( &A[Left], &A[Center] );  /* 如果左大于中则交换,保证A[Left] <= A[Center] */
     
    if ( A[Left] > A[Right] )
        Swap( &A[Left], &A[Right] );   /* 如果左大于右则交换,保证A[Left] <= A[Right] */
                
    if ( A[Center] > A[Right] )
        Swap( &A[Center], &A[Right] ); /* 如果中大于右则交换,保证A[Center] <= A[Right] */

    /* A[Left] <= A[Cetner] <= A[Right] */
   
    Swap( &A[Center], &A[Right-1] );  /* 将Pivot藏到右边Right-1作为哨兵*/
    return A[Right-1]; /* 返回实际主元值 */
}

1.3 交换策略

元素的交换策略:左边找大于等于主元,右边找小于等于主元;
image

刚刚越界时i>=j, i元素 >= 主元, j元素 <= 主元, 两边已经交换好; i和right-1交换,即把主元和大于等于它的值交换。

快排实现-C
void Q_sort( ElementType A[], int Left, int Right )
{
    if (Right - Left <= 0) {
        return;
    } else {
        int i = Left;
        int j = Right - 1;
        ElementType pivot = Median3( A, Left, Right );

        if (Right - Left == 1) 
            return;

        for ( ; ; ) {    
            while( A[++i] < pivot );  /* 从左边找个大于等于pivot的数 */
            while( A[--j] > pivot );  /* 从右边找个小于等于pivot的数 */
            if ( i < j )  

                Swap( &A[i], &A[j] ); /* 未越界,则交换 */
            
else 
                break;
        }
        Swap( &A[i], &A[Right - 1] ); /* restroe pivot*/
        Q_sort( A, Left, i - 1 ); /* from pivot to divid sort */
        Q_sort( A, i + 1, Right );
    }        
}

void Quick_sort( ElementType A[], int N )
{
    Q_sort( A, 0, N-1 );
} 

二、Python版快排

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        def swap(nums, i, j):
            nums[i], nums[j] = nums[j], nums[i]

        def median3(nums, left, right):
            center = (left+right) // 2
            if nums[left] > nums[center]:
                swap(nums, left, center)

            if nums[left] > nums[right]:
                swap(nums, left, right)

            if nums[center] > nums[right]:
                swap(nums, center, right)

            swap(nums, center, right-1)
            return nums[right-1]

        def quick_sort(nums, left, right):
            if right-left > 0:
                pivot = median3(nums, left, right)
                if right-left == 1:
                    return
                i, j = left, right-1
                while True:
                    i += 1
                    while nums[i] < pivot: i += 1
                    j -= 1
                    while nums[j] > pivot: j -= 1

                    if i < j:
                        swap(nums, i, j)
                    else:
                        break
                swap(nums, i, right-1)
                quick_sort(nums, i+1, right)
                quick_sort(nums, left, i-1)

        quick_sort(nums, 0, len(nums)-1)
        return nums

arr_len = 输入数组arr长度 = right -left + 1, 需要处理好基准情况:

  • Case1: arr_len 小于等1时,直接返回(不处理了);
  • Case2: arr_len =2时, 这时right - left =1,取到的pivot实际为arr[left], left = center, = right-1, 不需要也不能进入划分子数组阶段(会越界),而且通过median3已经将长为2的数组排序,故可在调用median3后直接当前递归程序;
  • Case3: arr_len == 3,上述快排程序已经可以处理, 并可以进一步通过Case1结束递归;
  • Case4: arr_len > 3: 进行快排程序,并通过Case1到3结束递归;

处理基准情况,当输入数组较小时,right - left > 5,直接调用内置排序或插入排序处理,避免进一步递归调用。相当于把更下层的递归调用,直接实现而不用快排实现(快排更慢)。

点击查看代码
def quick_sort(arr, left, right):
    if right - left > 5:
        pivot = mcedian3(arr, left, right)
        i = left
        j = right-1
        while True:
            i += 1
            while arr[i] < pivot:
                i += 1
            j -= 1
            while arr[j] > pivot:
                j -= 1
            if i < j:
                swap(arr, i, j)
            else:
                break    
        
        swap(arr, i, right-1)    
        quick_sort(arr, left, i-1)
        quick_sort(arr, i+1, right)    
    else:
        arr[left:right+1] = sorted(arr[left:right+1])

快排的主元选取和划分操作,可以衍生出减治-快速选择。

标签:sort,arr,right,nums,Python,三数,主元,Right,left
From: https://www.cnblogs.com/justLittleStar/p/17102849.html

相关文章

  • Python常用技巧
    001两数交换#两数交换a=2b=3a,b=b,aprint("a=%db=%d"%(a,b))#a=3b=2002eval函数#eval函数exp='2**2+5'eval(exp)#9运算符描述​​+​​对象相加​​-​......
  • 使用Python获取春节档电影影评,制作可视化词云图
    春节电影听巳月说都还可以,我不信,我觉得还是要看看看过的观众怎么说,于是我点开了流浪地球2…看起来好像不错的样子,8.2的评分,三十多亿的票房就是这评价也太多了,那......
  • 软件测试|手把手教你用Python来模拟绘制自由落体运动过程中的抛物线
    学过高中物理的我们都知道,当我们在一定高度上以一定速度水平抛出一个物体时,物体的运动轨迹实际上就是一条抛物线,那么,我们如何用Python将这个抛物线绘制出来呢。思路其实解决......
  • Python__25--模块
    1创建模块.py文件,文件名不与python自带的标准模块名相同,见名知意2导入模块2.1import模块名称[as别名]导入该模块所有内容使用时需要:模块名称.函数名不会出现函......
  • 软件测试|Python实用炫酷技能——推导式
    Python推导式判断一个程序员水平的高低,不能光看他的发量,也不能光看他的代码量,还要看他代码蕴含的思想,代码的质量。代码蕴含的思想主要体现在各种设计模式的运用上,而代码的质......
  • 软件测试|一步到位教会你Python字典操作(一)
    字典(dict)是python中的基础数据类型之一,字典的设计并不复杂,我们经常会用到这种数据类型。同时,字典也有一些比较实用的情景。学习任何一种编程语言,基础数据类型都是必备的......
  • 软件测试|手把手教你使用Python获取B站视频选集内容
    背景B站是我们年轻人最喜欢的学习网站,这句话没有任何问题!只有我们想不到的,没有B站上没有的,我们可以在B站上学做饭,学音乐,学数学,学历史......总之,B站就是如此包罗万象。言归正......
  • ubuntu18容器中安装python3.10
    在python官网https://www.python.org/下载python3.10的tgz的源码包。安装编译环境apt-getupdateaptinstallwgetbuild-essentialcheckinstallaptinstalllibreadline......
  • Kong Customize Python Plugin
    KongCustomizePythonPlugin前情提要:由于公司业务需求,需要针对Kong自定义插件,而Kong的插件主要是Lua语言,公司的技术栈是Python,所以升级了Kong版本到3.1。Kon......
  • 腾讯课堂Python使用Numpy入门数据计算
    p2array创建及属性array元素类型相同,list可不同1.array转化一维数组importnumpyasnplis=[1]np.array(lis)2.array转化二维数组importnumpy......