快速选择算法与快速排序算法

快选和快排,都涉及到快速排序的思想。所以下面我们先介绍快速排序算法!

快速排序算法,时间复杂度为O(n log n),最坏的情况是O(n^2)。实现思想:选择一个基准元素,将数组分成两部分:比基准元素小的元素和比基准元素大的元素。然后,固定这个基准元素的位置,对这两部分分别递归地应用快速排序,直到整个序列有序

1. 选择基准元素,可以是第一个元素、最后一个元素、中间元素,或者随机选择。我是通常选择第一个,或者最后一个。下面以选择第一个为例子。

2. 设定两个指针,左指针指向数组的起始位置,右指针指向数组的结束位置,移动这两个指针,将数组分成两部分。下面是详细的分区方法:

使用两个指针,left 指向数组的起始位置,right 指向数组的末尾位置。

从右向左移动 right 指针,直到找到一个小于等于基准元素的元素。

从左向右移动 left 指针,直到找到一个大于等于基准元素的元素。

如果此时 left < right,则交换 nums[left] 和 nums[right]。

重复上述过程,直到 left >= right。最终 left 指针所在位置的元素与基准元素交换。

3. 递归排序,分别将左右两边的分别排序,直到完全排好。

#include <iostream>
#include <vector>
using namespace std;

// 快速排序函数
void quickSort(vector<int>& nums, int left, int right) {
    if (left >= right) {
        return;
    }
    
    // 选择基准元素,这里选择第一个元素作为基准
    int pivot = nums[left];
    int low = left;
    int high = right;
    
    // 开始分区操作
    while (low < high) {
        // 从右向左找到第一个小于基准元素的位置
        while (low < high && nums[high] >= pivot) {
            high--;
        }
        nums[low] = nums[high];  // 将小于基准元素的元素移到左边
        
        // 从左向右找到第一个大于基准元素的位置
        while (low < high && nums[low] <= pivot) {
            low++;
        }
        nums[high] = nums[low];  // 将大于基准元素的元素移到右边
    }
    
    // 将基准元素放到正确的位置
    nums[low] = pivot;
    
    // 递归排序基准元素左边和右边的部分
    quickSort(nums, left, low - 1);
    quickSort(nums, low + 1, right);
}

// 示例用法
int main() {
    vector<int> nums = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
    
    cout << "排序前:";
    for (int num : nums) {
        cout << num << " ";
    }
    cout << endl;
    
    quickSort(nums, 0, nums.size() - 1);
    
    cout << "排序后:";
    for (int num : nums) {
        cout << num << " ";
    }
    cout << endl;
    
    return 0;

本文主要详细介绍快速选择算法,快速选择算法的目标是找到未排序数组中第 k 大或第 k 小的元素,它通过分治的方式,在每次分区后只递归地处理包含目标元素的那一半数组。这使得它在平均情况下的时间复杂度为 O(n),最坏情况下为 O(n^2)。下面是代码。

#include <iostream>
#include <vector>
using namespace std;

// 快速选择函数
// 在数组 nums 中找到第 k 大的元素
int quickSelect(vector<int>& nums, int left, int right, int k) {
    if (left == right) {
        return nums[left];
    }
    
    // 选择基准元素,这里选择第一个元素作为基准
    int pivot = nums[left];
    int low = left;
    int high = right;
    
    // 分区操作
    while (low < high) {
        // 从右向左找到第一个大于基准元素的位置
        while (low < high && nums[high] <= pivot) {
            high--;
        }
        nums[low] = nums[high];  // 将大于基准元素的元素移到左边
        
        // 从左向右找到第一个小于基准元素的位置
        while (low < high && nums[low] >= pivot) {
            low++;
        }
        nums[high] = nums[low];  // 将小于基准元素的元素移到右边
    }
    
    // 将基准元素放到正确的位置
    nums[low] = pivot;
    
    // 判断基准元素的位置与 k 的关系
    if (k == low) {
        return nums[low];
    } else if (k < low) {
        return quickSelect(nums, left, low - 1, k);
    } else {
        return quickSelect(nums, low + 1, right, k);
    }
}

// 示例用法
int main() {
    vector<int> nums = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
    int k = 4;  // 要找第 k 大的元素,这里示例 k = 4
    
    cout << "数组:" << endl;
    for (int num : nums) {
        cout << num << " ";
    }
    cout << endl;
    // nums.size() - k是寻找的第K大的值的下标;公式 K+index = nums.size()
    int result = quickSelect(nums, 0, nums.size() - 1, nums.size() - k);  
    
    cout << "第 " << k << " 大的元素是:" << result << endl;
    
    return 0;
}

最后是我自己写的快选,不知道为什么会超时?请大佬指点一下

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        if (k > nums.size() || k < 1) return 0;
        return quicksort(nums, 0, nums.size() - 1, nums.size() - k); // 返回第 K 个大的值,nums.size() - k 为第 K 大的下标
    }

private:
    int partition(vector<int>& nums, int left, int right) {
        int pivot = nums[right]; // 选择最右边的元素作为基准值
        int i = left - 1; // 左指针,初始指向左边界的前一个位置

        for (int j = left; j < right; ++j) {
            if (nums[j] <= pivot) { // 将小于等于基准值的元素放到左侧
                i++;
                swap(nums[i], nums[j]);
            }
        }

        swap(nums[i + 1], nums[right]); // 将基准值放到正确的位置
        return i + 1; // 返回基准值的位置索引
    }

    int quicksort(vector<int>& nums, int low, int high, int k) {
        if (low <= high) {
            int q = partition(nums, low, high); // 分区操作

            if (q == k) {
                return nums[k];
            } else if (q > k) {
                return quicksort(nums, low, q - 1, k); // 左侧区间继续查找
            } else {
                return quicksort(nums, q + 1, high, k); // 右侧区间继续查找
            }
        }
        return -1; // 处理边界情况,这里可以返回一个合适的默认值或者处理逻辑
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值