快速排序的写法

面试中一个频率极高的问题就是要手写快速排序,实际上涉及下标变换的代码极其容易写错,基本上涉及整数下标操作的问题都算是难度中等偏上的了。

对于一些经典问题,我们要时不时的去练习,这里给出算法导论上的和STL中实现的快速排序的两种不同写法。

算法导论中的写法极其简单,在面试中十分推荐写这种写法:

template <typename T>
size_t partition(T *a, size_t p, size_t q)
{
    size_t r = q; // pivot
    for (size_t i = p; i < q; i++)
        if (a[i] > a[r])
            swap(a[i--], a[--q]);
    swap(a[q], a[r]);
    return q;
}

template <typename T>
void quick_sort(T *a, size_t n)
{
    if (n < 2) return;
    size_t m = partition<T>(a, 0, n - 1);
    quick_sort(a, m);
    quick_sort(a + m + 1, n - m - 1);
}

算法的关键是partiton函数,该函数将数组a[p..q]中的最后一个元素作为分割标准pivot,从左到右依次与pivot比较,如果a[i]小于等于pivot则按兵不动,如果a[i]大于pivot则将a[i]与数组的倒数第二个交换,注意swap(a[i--], q[--q]);这行的细节:q初始为数组最后一个元素的下标,交换时它先指向倒数第二个元素,再交换,也就是说q始终保持指向未划分完成的区域的最后一个指针的下一个指针,即左闭右开区间[p, q)始终表示当前未划分的元素的下标。而i--的保证了交换元素后下一次循环依旧使用当前位置的元素与pivot进行比较,因为刚刚交换过来的元素还未与pivot比较过。

for循环的终止条件判定为i<q,这是说明指针要遍历尚未划分元素的区间[p,q)内的每一个元素。

当for循环终止时,q之前的所有元素a[i]均满足a[i]<=pivot,而q及q之后的元素[q,r)则满足a[q]>pivot。这时将a[r]与a[q]进行交换就刚好满足a[q]位置的左侧不大于它,a[q]的右侧比它大。

再来参考STL中的partition写法,为了简便使用了整数。

// [p, q)
int partition(int *a, int p, int q, int pivot)
{
    while (p != q) {
        while (a[p] <= pivot) {
            ++p;
            if (p == q) return p;
        }
        do
        {
            --q;
            if (p == q) return p;
        } while (a[q] > pivot);
        swap(a[p], a[q]);
        ++p;
    }
    return p;
}

其快排的写法应为:

void quick_sort(int *a, int n)
{
    if (n < 2) return;
    
    //int m = partition(a, 0, n - 1);
    int m = partition(a, 0, n, a[0]);
    swap(a[0], a[m-1]);
    
    quick_sort(a, m - 1);
    quick_sort(a + m, n - m);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值