【排序】快速排序系列算法深入理解(c语言)

快速排序的流程比较经典:

选定枢轴,先右后左,找到不等关系后交换,直到左右相等。

int partition_up(List& list, int low, int high)  
{  
    list.elems[0] = list.elems[low];//记录  
    while (low < high) //三个判断条件都是low<high,所以一定终止在low==high
    {  
        //找不等关系,先右后左
        while (low < high && list.elems[high].key >= list.elems[0].key)  
        {  
            high--;  
        }  
        list.elems[low] = list.elems[high];  
        while (low < high && list.elems[low].key <= list.elems[0].key)  
        {  
            low++;  
        }  
        list.elems[high] = list.elems[low];  
    }  
    list.elems[low] = list.elems[0];//将枢轴插入  
    return low;//返回枢轴位置  
}  
void primitive_quick_sort_up(List& list, int low, int high)  
{  
    if (low >= high)//终止条件,low和high相等  
    {  
        return;  
    }  
    int pivot_pos = partition_up(list, low, high);  
    primitive_quick_sort_up(list, low, pivot_pos - 1);  
    primitive_quick_sort_up(list, pivot_pos + 1, high);  
} 

排序思路很简单,但是需要注意两个边界的问题:

1 最后一定是low==high吗?

是的,因为主循环条件是low<high,内部两个和游标移动的前提条件也是low<high,因为游标是逐个移动的,所以最后一定是因为low==high而导致三个循环相继退出。

2 随机选择的枢轴和最后的  low==high位置交换,为什么low==high位置的元素一定会换在枢轴合理的一侧呢?

首先我们要分析一下最后low==high是个什么东西。最终条件有两种情况,而且这两种是分先后的。

首先是由右到左的时候相等,这个时候相当于找比pivot更小的没找到,于是找到了low元素这里,low是个什么东西?low已经是上次排剩下的,已经确定比pivot小的元素了,好,现在的low==high元素是小于pivot的元素。

如果high提前卡住,也就是找到了比pivot小的元素,就可能触发第二种情况,在low找比pivot大的没有找到,最后导致low==high。在寻找low位置的时候,我们实际上是有比较high位置是否比pivot小的,因为在比较之前就已经被low==high卡住退出了(这点需要理解一下),那么会不会有这个位置实际上就比pivot大但是最后我们把大的换到左边了呢?

不会,因为在进行从右到左寻找的过程中已经确定high位置是小于pivot位置的了。也就是说,这种情况下,选定位置仍然是小于pivot的。

综上,只要你是先右后左,找不等关系,那最后low==high的时候,元素必定是小于pivot的。

那么,只要pivot放在low==high的左边,交换后必然是合理位置。

如何保证pivot一定在low==high左边?

这就是很多程序的写法,先随机找到一个位置当做枢轴量,但是人家会先把第一个元素和pivot交换,这就确保pivot同时具有随机性(防止单边情况)和最左边的条件。

很多算法都偷懒,选择第一个,但是又不告诉你选其他位置会怎样。

以上,我们从理论上证明了市面上快排的正确,总结一下套路:

随机选择一个元素作为pivot

将第一个元素和pivot交换,然后记录pivot位置,如果没有这步可能会被最后一步交换打乱顺序。

进行经典的快速排序:

先右后左,大前提是low<high,寻找不等关系,完成一趟快排

完成分治写法

如果是从大到小排序,那就是pivot放到最后,然后先左后右了,其实就是彻底反过来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亦梦亦醒乐逍遥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值