快速排序 ——双游标、单游标实现

本文详细介绍了快速排序算法的实现,包括使用双游标和单游标的方法。通过实例分析,阐述了两种策略的步骤与区别,帮助读者深入理解快速排序的内部工作机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <cstdio>
#include <iostream>

using namespace std;
// 双游标版本 
int* partition(int *l, int *r)
{
    int *i = l+1, *j = r-1;
    int aim = *l, temp;
    while(i<=j) {
        while(i<=j && *i<=aim)    i++;
        while(i<=j && *j>aim)    j--;
        if(i<=j) {
            temp = *i;
            *i = *j;
            *j = temp;
            i++;
            j--;
        }
    }
    temp = *l;
    *l = *j;
    *j = temp;
}
// 单游标版本 1
// 维护这样一个区间 [ <=aim | >aim | unknown], k指向第一个>aim的位置 
int* partition2(int *l, int *r)
{
    int *k = l+1;
    int aim = *l, temp;
    for(int *p=l+1; p < r; p++) {
        if(*p <= aim) {
            temp = *p;
            *p = *k;
            *k = temp;
            k++;
        }
    }
    temp = *(k-1);
    *(k-1) = *l;
    *l = temp;
    
//    for(int *p=l; p < r; p++) {
//        printf("%d ", *p);
//    }
//    printf("\n");
    
    return k-1;
}

// 单游标版本 2
// 维护这样一个区间 [ <=aim | >aim | unknown], k指向最后一个<=aim的位置 
int* partition3(int *l, int *r)
{
    int *k = l;
    int aim = *l, temp;
    for(int *p=l+1; p < r; p++) {
        if(*p <= aim) {
            temp = *p;
            *p = *(k+1);
            *(k+1) = temp;
            k++;
        }
    }
    temp = *k;
    *k = *l;
    *l = temp;
    
//    for(int *p=l; p<r; p++) {
//        printf("%d ", *p);
//    }
//    printf("\n");

    return k;
}

void quick_sort(int *l, int *r)
{
    if(r-l<2)    return; // 只有当序列长度>=2时,才需要排序 
//    int *mid = partition(l, r);
    int *mid = partition3(l, r);
    quick_sort(l, mid);
    quick_sort(mid+1, r);
}

int main ()
{
    int a[] = {6,2,1,8,7,5,3,4};
//    int a[] = {2,4,3,1};
    int n = sizeof(a) / sizeof(int);
    quick_sort(a, a+n);
    for(int i=0; i<n; i++)    printf("%d ", a[i]);
    
    return 0;    
} 

 

### Java实现快速排序时先移动右指针的原因 在Java中实现快速排序的过程中,通常会优先移动右指针再移动左指针。这种设计的主要原因是为了确保分区操作能够正确完成并保持稳定性。 #### 1. **防止死循环** 当基准值`pivot`被选为数组的第一个元素时,如果先移动左指针,在某些情况下可能会导致无限循环的发生。这是因为左指针可能一开始就停留在基准值本身的位置上[^3]。此时如果没有其他条件限制,程序将无法正常终止。因此通过首先调整右指针可以有效避免这种情况发生。 ```java while(r >= l && arr[r] >= pivot){ r--; } ``` 这段代码展示了如何安全地减少右侧范围直到找到一个小于等于`pivot`的数值为止[^5]。 #### 2. **保证最终交换的有效性** 另一个重要原因是这样可以帮助我们更方便地构建有效的分割逻辑。具体来说,当我们从右边开始寻找第一个小于`pivot` 的元素之后才去考虑左边的情况,则更容易保证最后一步把`pivot` 放置到合适位置的操作顺利完成: ```java // 将基准值放到中间位置 arr[low] = arr[l]; arr[l] = pivot; ``` 只有当先前已经找到了应该位于该区域内的较小项(即由右向左扫描所得结果),才能确信当前索引处确实适合放置新的中心点[^4]。 #### 3. **提高效率与简化边界处理** 此外,采用这种方式还可以稍微优化性能表现,并使整个算法结构更加清晰简洁。因为一旦发现某个方向上的所有剩余项目均满足特定关系后就可以立即停止进一步探索那个子区间,从而减少了不必要的比较次数[^1]。 综上所述,在基于游标的版本里预先变动较高一侧指标的做法不仅有助于规避潜在陷阱还能增强实际执行效果。 ```python def quick_sort(arr): ... # 右侧先行判断能更好地定位枢轴位置 while (l < r and arr[r] >= key): r -= 1 ... ``` ### 示例代码片段说明 以下是按照上述原则编写的一个简例子来展示这一过程: ```java public static void quickSort(int[] arr, int left, int right) { if (left >= right) return; int l = left, r = right; int key = arr[left]; // 先移动右指针 while (l < r) { while (l < r && arr[r] >= key) r--; while (l < r && arr[l] <= key) l++; if (l < r) swap(arr, l, r); } swap(arr, left, l); quickSort(arr, left, l - 1); quickSort(arr, l + 1, right); } private static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } ``` 此方法遵循了标准做法——先改变高位指向器的状态后再做低位相应动作,以此达成理想中的划分目标[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值