用C++实现快排(思路+代码)

本文详细介绍了快速排序的基本思想及其实现方法——填坑法,并通过具体的数组实例演示了快速排序的过程。此外,还提供了完整的C++代码实现,帮助读者更好地理解和掌握快速排序算法。

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

快排的基本思想:
1.先从数列中取出一个数作为基准数。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。

实现方法:填坑法
比如数组
72 6 57 88 60 42 83 73 48 85
初始时,i = 0; j =9; X = a[i] = 72
由于已经将a[0]中的数保存到X中,可以理解成在数组a[0]上挖了个坑,可以将其它数据填充到这来。
从j开始向前找一个比X小或等于X的数。当j=8,符合条件,将a[8]挖出再填到上一个坑a[0]中。a[0]=a[8];i++; 这样一个坑a[0]就被搞定了,但又形成了一个新坑a[8],这怎么办了?简单,再找数字来填a[8]这个坑。这次从i开始向后找一个大于X的数,当i=3,符合条件,将a[3]挖出再填到上一个坑中a[8]=a[3];j–;
……
以此类推

实现代码:

#include<iostream>  
#include <vector>

using namespace std;
void quickSort(vector<int> &num, int l, int r);
int main()
{
    int array[] = { 34,65,12,43,67,5,78,10,3,70 }, k;
    int len = sizeof(array) / sizeof(int);
    cout << "The orginal arrayare:" << endl;
    vector<int> num(array, array + len);
    for (k = 0; k<num.size(); k++)
        cout << num[k] << ",";
    cout << endl;
    quickSort(num, 0, len - 1);
    cout << "The sorted arrayare:" << endl;
    for (k = 0; k<num.size(); k++)
        cout << num[k] << ",";
    cout << endl;
    system("pause");
    return 0;
}

void quickSort(vector<int> &num, int l, int r) {
    if (l >= r)     //先检查左右条件
        return;
    int i = l, j = r, x = num[l];
    while (i < j) {
        while (i < j && num[j] >= x)//从右向左找到第一个小于x的
            j--;
        if (i < j)
            num[i++] = num[j];//填坑之后i++
        while (i < j && num[i] <= x)//从左向右找第一个大于x的数
            i++;
        if (i < j)
            num[j--] = num[i];
    }
    num[i] = x;     //把最开始取出来的x放到i处
    quickSort(num, l, i - 1);//以i为中间值,分左右两部分递归调用
    quickSort(num, i + 1, r);
}

利用快排思想做的其它题目:
数组中第k大的数

<think>嗯,用户让我用C++写一段快速排序代码,并且讲解实现逻辑。首先,我需要回忆一下快速排序的基本原理,确保自己理解正确。快速排序是一种分治算法,通过选择一个基准元素,将数组分成两部分,一部分比基准小,另一部分比基准大,然后递归地对这两部分排序。 接下来,我得考虑如何在C++实现这个算法。通常,快排的函数会接受数组、起始索引和结束索引作为参数。然后选择基准元素,可能有不同的选择方法,比如中间元素或者随机元素,这里可能选中间或者最后一个,需要决定。然后进行分区操作,将小于基准的放在左边,大于的放在右边。分区过程是关键,需要用循环和交换来实现。 然后要考虑递归的终止条件,也就是当子数组的长度小于等于1时停止。还需要处理分区后的左右两部分,递归调用快排函数。 在代码结构上,可能需要两个函数,一个作为入口,处理整个数组,另一个处理具体的分区和递归。或者,可能用一个函数,通过参数控制范围。通常,快排的partition函数是单独写的,但这里可能为了简化,直接在quickSort函数里实现。或者用户可能希望看到标准的实现方式。 需要注意的是,C++中数组是传指针的,所以函数参数应该是指针或者用引用来传递vector。不过用户可能希望用原生的数组,所以可能需要处理起始和结束的索引。比如函数原型可能是void quickSort(int arr[], int low, int high),然后调用时传入0和n-1。 分区操作的实现是关键。假设选择最后一个元素作为基准,然后使用两个指针,i从low-1开始,j从low到high-1遍历,如果当前元素小于等于基准,就i递增,并交换i和j位置的元素。最后将基准放到正确的位置,即i+1的位置,然后返回该位置的索引作为分界点。 需要确保代码没有语法错误,比如循环的条件,变量的初始化,递归调用的参数是否正确。比如,分区后,递归处理low到pi-1和pi+1到high。 现在,思考用户可能的疑问,比如基准选择的影响,时间复杂度,以及分区过程的具体步骤。在讲解的时候需要把这些点涵盖进去,尤其是分区的逻辑,因为这是快排的核心。 用户可能对递归部分不太理解,需要解释递归如何拆分数组,直到每个子数组有序。另外,可能需要提到快排是不稳定的排序算法,以及平均情况下的时间复杂度是O(n log n),最坏情况是O(),但通过随机选择基准可以优化。 然后,测试代码的部分,可能需要一个main函数来演示如何使用这个快排函数,比如创建一个数组,排序后输出结果。但用户可能只需要核心的快排代码,所以可以提供一个示例,包括main函数,但需要说明。 在写代码时,要确保使用正确的语法,比如函数参数的传递,循环结构,交换元素的方法,可能使用std::swap或者自己写交换的代码。例如,使用临时变量来交换两个元素的值。 现在,把这些思路整理成代码结构。比如,先写一个分区函数,然后写递归的quickSort函数。或者将分区逻辑直接放在quickSort函数里。可能更清晰的是分开写,但有时候为了代码简洁,也可能合并。 例如: 分区函数返回分界点索引,然后递归调用左右部分。例如: int partition(int arr[], int low, int high) { int pivot = arr[high]; int i = low - 1; for (int j = low; j <= high - 1; j++) { if (arr[j] < pivot) { i++; swap(arr[i], arr[j]); } } swap(arr[i+1], arr[high]); return i + 1; } void quickSort(int arr[], int low, int high) { if (low < high) { int pi = partition(arr, low, high); quickSort(arr, low, pi - 1); quickSort(arr, pi + 1, high); } } 这样是标准的实现方式。但用户可能需要一个完整的例子,包括main函数。 然后,在讲解的时候,需要逐步解释每个步骤的作用,比如选择基准,分区过程,交换元素,递归排序。 还需要注意边界条件,比如当数组为空或只有一个元素的情况,此时不需要排序。 另外,可能需要提到这种实现是Lomuto分区方案,而Hoare分区方案可能不同,但Lomuto更易于理解。 总结来说,代码部分需要包括分区函数和递归的quickSort函数,以及示例使用。讲解时需要分步骤解释每个部分的作用,特别是分区的过程,基准的选择,以及递归拆分数组的逻辑。</think>以下是用C++实现的快速排序代码及分步讲解: ```cpp #include <iostream> using namespace std; // 分区函数:将数组分为左右两部分,返回基准索引 int partition(int arr[], int low, int high) { int pivot = arr[high]; // 选择最后一个元素作为基准 int i = (low - 1); // 记录较小元素的右边界 for (int j = low; j <= high - 1; j++) { // 当前元素小于等于基准时,将其交换到左侧 if (arr[j] <= pivot) { i++; // 扩展较小元素的边界 swap(arr[i], arr[j]); } } swap(arr[i + 1], arr[high]); // 将基准放到正确位置 return (i + 1); // 返回分界点索引 } // 快速排序主函数 void quickSort(int arr[], int low, int high) { if (low < high) { // pi是分区后的基准位置索引 int pi = partition(arr, low, high); // 递归排序左右子数组 quickSort(arr, low, pi - 1); quickSort(arr, pi + 1, high); } } // 示例用法 int main() { int arr[] = {10, 7, 8, 9, 1, 5}; int n = sizeof(arr) / sizeof(arr[0]); quickSort(arr, 0, n - 1); cout << "排序结果: "; for (int i = 0; i < n; i++) cout << arr[i] << " "; return 0; } ``` 实现逻辑分步解析: 1. **分区过程 (partition函数)**: - **基准选择**:选择最后一个元素`arr[high]`作为基准值(pivot) - **边界指针**:`i`指针记录较小元素的右边界,初始为`low-1` - **遍历比较**:`j`指针从左到右遍历数组,当发现`arr[j] <= pivot`时: - `i`指针右移 - 交换`arr[i]`和`arr[j]` - **基准归位**:遍历完成后,将基准值交换到`i+1`位置 - **返回分界点**:此时数组满足`[ <= pivot ] [pivot] [ > pivot ]` 2. **递归排序 (quickSort函数)**: - **终止条件**:当`low >= high`时停止递归(子数组长度≤1) - **分区操作**:通过partition函数获取基准位置 - **左右递归**: - 左子数组范围:`[low, pi-1]` - 右子数组范围:`[pi+1, high]` 3. **时间复杂度**: - 最优/平均情况:$O(n \log n)$ - 最坏情况:$O(n^2)$(可通过随机选择基准优化) 4. **算法特点**: - 原地排序:不需要额外存储空间 - 不稳定性:相同元素可能改变相对顺序 - 分治策略:通过递归不断缩小问题规模 **关键点理解**: 1. 每次分区确保基准元素到达最终排序位置 2. 通过递归将问题分解为更小的子问题 3. 实际应用中常采用三点中值法选择基准来优化性能 示例输出:`排序结果: 1 5 7 8 9 10` 可以通过修改main()中的测试数组来验证不同输入情况。这个实现使用了Lomuto分区方案,相比Hoare方案更易理解但交换次数稍多。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值