利用分治策略优化快速排序

1. 基本思想

    分治快速排序(Quick Sort)是一种基于分治法的排序算法,采用递归的方式将一个数组分割成小的子数组,并通过交换元素来使得每个子数组元素按照特定顺序排列,最终将整个数组排序。

快速排序的基本步骤:

  1. 选择基准元素:从数组中选择一个元素作为基准(pivot)。
  2. 分区操作:将数组分成两个部分,左边的部分所有元素都小于基准元素,右边的部分所有元素都大于基准元素。此时基准元素已经排好序。
  3. 递归排序:对基准元素左侧和右侧的子数组递归进行快速排序。

快速排序的核心思想:

  • 分治法:通过每次选择一个基准元素,将数组分割成两个子数组,然后递归地对两个子数组进行排序。
  • 每次选择基准元素后,通过分区将数组划分为两个部分,左侧部分的元素都小于基准,右侧部分的元素都大于基准。
  • 递归对子数组进行排序,直到每个子数组的长度为 1 或 0,排序完成。
// 分区函数,返回基准元素的正确位置
int Partition(vector<int>& arr, int low, int high) {
    int pivot = arr[high];  // 选择最后一个元素作为基准
    int i = low - 1;  // i 是小于基准元素的子数组的最后一个元素的索引

    // 遍历数组,将小于基准的元素移动到数组的前面
    for (int j = low; j < high; ++j) {
        if (arr[j] < pivot) {
            ++i;
            swap(arr[i], arr[j]);
        }
    }
    // 将基准元素放到正确的位置
    swap(arr[i + 1], arr[high]);
    return i + 1;  // 返回基准元素的索引
}

// 快速排序函数
void QuickSort(vector<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); // 排序右边子数组
    }
}

 2. 快速选择算法

    快速选择算法(Quickselect) 是一种基于快速排序(Quick Sort)的算法,用于在未排序的数组中找到第 k 小(大)的元素。与快速排序不同,快速选择只对包含第 k 小(大)元素的部分进行排序,而不需要对整个数组进行排序,因此它的时间复杂度通常较低。

快速选择的核心思想是:

  1. 与快速排序一样,通过选择一个“基准”元素并进行分区(Partition)操作,将数组分成左右两个部分。
  2. 如果基准元素的位置正好是 k,则基准元素即为第 k 小的元素。
  3. 如果基准元素的位置小于 k,则继续在右侧子数组中查找第 k 小元素。
  4. 如果基准元素的位置大于 k,则继续在左侧子数组中查找第 k 小元素。

通过将数组分成三个部分:小于基准、等于基准、大于基准,从而更有效地找到第 k 小的元素。相较于传统的快速选择算法,使用三个部分分区可以加速查找过程,特别是在处理重复元素时。

下面是一个示例,这类问题可以以此为模板,通过适当修改来实现不同的目标。 

int qsort(vector<int>& nums, int l, int r, int k)
    {
        if(l == r) return nums[l];

        //1.随机选择基准数
        int key = getRandom(nums, l, r);
        //2.根据基准数将数组分成三组
        int left = l - 1, right = r + 1, i = l;
        while(i < right)
        {
            if(nums[i] < key) swap(nums[++left], nums[i++]);
            else if(nums[i] == key) i++;
            else swap(nums[--right], nums[i]); 
        }
        //3.分情况讨论
        int c = r - right + 1, b = right - left - 1;
        if(c >= k)
            return qsort(nums, right, r, k);
        else if(b + c >= k) return key;
        else  return qsort(nums, l, left, k - b - c);
    }
    int getRandom(vector<int>& nums, int left, int right)
    {
        int r = rand();
        return nums[r % (right - left) + left];
    }

3. 颜色分类

解法:三指针

排序时数组被分成四个部分,[0, left] 区间都是0,(left, i)区间都是1,[i, right]区间是未排序的部分,[right , n - 1]区间都是2.

排序完成后,i与right相等,数组被分成三个部分[0, left]都是1,(left, i)都是0,[right , n - 1]都是2

class Solution {
public:
    void sortColors(vector<int>& nums) {
        int i = 0, n = nums.size();
        int left = -1, right = n;
        while(i < right)
        {
            if(nums[i] == 0) swap(nums[i++], nums[++left]);
            else if(nums[i] == 1) i++;
            else if(nums[i] == 2) swap(nums[i], nums[--right]);
        }
    }
};

75. 颜色分类 - 力扣(LeetCode)

4.  排序数组

使用将数组分成三部分的思想实现快排,效率会更高

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        srand(time(NULL));
        qsort(nums, 0, nums.size() - 1);
        return nums;
    }
    void qsort(vector<int>& nums, int l, int r)
    {
        if(l >= r) return;

        int key = getRanNum(nums, l, r);//获取随机基准值
        int i = l, left = l - 1, right = r + 1;
        while(i < right)
        {
            if(nums[i] < key) swap(nums[++left], nums[i++]);
            else if(nums[i] == key) i++;
            else swap(nums[--right], nums[i]);
        }

        qsort(nums, l, left);
        qsort(nums, right, r);
    }
    int getRanNum(vector<int>& nums, int left, int right)
    {
        int r = rand();
        return nums[r % (right - left) + left];
    }
};

912. 排序数组 - 力扣(LeetCode)

5. 数组中第k个最大元素

快速选择算法

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        srand(time(NULL));
        return qsort(nums, 0, nums.size() - 1, k);
    }
    int qsort(vector<int>& nums, int l, int r, int k)
    {
        if(l == r) return nums[l];//返回条件

        //1.随机选择基准数
        int key = getRandom(nums, l, r);
        //2.根据基准数将数组分成三组
        int left = l - 1, right = r + 1, i = l;
        while(i < right)
        {
            if(nums[i] < key) swap(nums[++left], nums[i++]);
            else if(nums[i] == key) i++;
            else swap(nums[--right], nums[i]); 
        }
        //3.分情况讨论
        int c = r - right + 1, b = right - left - 1;
        if(c >= k)
            return qsort(nums, right, r, k);
        else if(b + c >= k) return key;
        else  return qsort(nums, l, left, k - b - c);
    }
    int getRandom(vector<int>& nums, int left, int right)
    {
        int r = rand();
        return nums[r % (right - left) + left];
    }
};

215. 数组中的第K个最大元素 - 力扣(LeetCode)

6. 库存管理

法一:排序 O(nlogn)

法二:堆排序 O(nlogk)

法三:快速选择算法 O(n)

class Solution {
public:
    vector<int> inventoryManagement(vector<int>& stock, int cnt) {
        srand(time(NULL));
        qsort(stock, 0, stock.size() - 1, cnt);
        return {stock.begin(), stock.begin() + cnt};
    }
    void qsort(vector<int>& stock,int l, int r, int cnt)
    {
        if(l == r) return;

        //1.随机选择基准数
        int key = getRandom(stock, l, r);
        //2.根据基准数将数组分成三组
        int left = l - 1, right = r + 1, i = l;
        while(i < right)
        {
            if(stock[i] < key) swap(stock[++left], stock[i++]);
            else if(stock[i] == key) i++;
            else swap(stock[--right], stock[i]); 
        }
        //3.分情况讨论
        int a = left - l + 1, b = right - left - 1;
        if(cnt < a) qsort(stock, l, left, cnt);
        else if(cnt <= a + b) return;
        else qsort(stock, right, r, cnt - a - b);
    }
    int getRandom(vector<int>& stock, int left, int right)
    {
        int r = rand();
        return stock[r % (right - left) + left];
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/971928.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

照片模糊怎么变清晰?图生生AI修图-一键清晰放大

当打开手机相册时&#xff0c;那些泛着噪点的合影、细节模糊的风景照、像素化的证件图片&#xff0c;让珍贵时刻蒙上遗憾的面纱。而专业级图像修复工具的门槛&#xff0c;让多数人只能无奈接受这些"不完美的记忆"。AI技术的发展&#xff0c;让普通用户也能轻松拥有专…

Linux 网络与常用操作(适合开发/运维/网络工程师)

目录 OSI 七层协议简介 应用层 传输层 Linux 命令&#xff01;&#xff01;&#xff01; 1. ifconfig 命令 简介 1. 查看网络地址信息 2. 指定开启、或者关闭网卡 3. 修改、设置 IP 地址 4. 修改机器的 MAC 地址信息 5. 永久修改网络设备信息 2. route 路由命令 …

PID控制学习

前言 本篇文章属于PID控制算法的学习笔记&#xff0c;来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记&#xff0c;只能做参考&#xff0c;细节方面建议观看视频&#xff0c;肯定受益匪浅。 PID入门教程-电机控制 倒立摆 持续更新中_哔哩哔哩_bilibili 一…

第1期 定时器实现非阻塞式程序 按键控制LED闪烁模式

第1期 定时器实现非阻塞式程序 按键控制LED闪烁模式 解决按键扫描&#xff0c;松手检测时阻塞的问题实现LED闪烁的非阻塞总结补充&#xff08;为什么不会阻塞&#xff09; 参考江协科技 KEY1和KEY2两者独立控制互不影响 阻塞&#xff1a;如果按下按键不松手&#xff0c;程序就…

【Arxiv 大模型最新进展】PEAR: 零额外推理开销,提升RAG性能!(★AI最前线★)

【Arxiv 大模型最新进展】PEAR: 零额外推理开销&#xff0c;提升RAG性能&#xff01;&#xff08;★AI最前线★&#xff09; &#x1f31f; 嗨&#xff0c;你好&#xff0c;我是 青松 &#xff01; &#x1f308; 自小刺头深草里&#xff0c;而今渐觉出蓬蒿。 NLP Github 项目…

vscode的一些实用操作

1. 焦点切换(比如主要用到使用快捷键在编辑区和终端区进行切换操作) 2. 跳转行号 使用ctrl g,然后输入指定的文件内容&#xff0c;即可跳转到相应位置。 使用ctrl p,然后输入指定的行号&#xff0c;回车即可跳转到相应行号位置。

OAI 平台 4G(LTE)基站 、终端、核心网 端到端部署实践(一)

本系列文章,基于OAI LTE代码搭建端到端运行环境,包含 eNB,EPC,UE三个网元。本小节先介绍系统总体架构,硬件平台及驱动安装方法。 1. Overview 系统总体架构如下图所示。 2 Machine setup 2.1 Machine specs Distributor ID: Ubuntu Description: Ubuntu 18.04.5 LTS…

Linux环境Docker使用代理推拉镜像

闲扯几句 不知不觉已经2月中了&#xff0c;1个半月忙得没写博客&#xff0c;这篇其实很早就想写了&#xff08;可追溯到Docker刚刚无法拉镜像的时候&#xff09;&#xff0c;由于工作和生活上的事比较多又在备考软考架构&#xff0c;拖了好久…… 简单记录下怎么做的&#xf…

基于TI的TDA4高速信号仿真条件的理解 4.6

Application Note 《Jacinto7 AM6x, TDA4x, and DRA8x High-Speed Interface Design Guidelines》 4.6 Reviewing Simulation Results检查仿真结果 The results generated by the channel simulations outlined in the preceding sections are compared against an eye mask s…

unity学习46:反向动力学IK

目录 1 正向动力学和反向动力学 1.1 正向动力学 1.2 反向动力学 1.3 实现目标 2 实现反向动力 2.1 先定义一个目标 2.2 动画层layer&#xff0c;需要加 IK pass 2.3 增加头部朝向代码 2.3.1 专门的IK方法 OnAnimatorIK(int layerIndex){} 2.3.2 增加朝向代码 2.4 …

DeepSeek 和 ChatGPT 在特定任务中的表现:逻辑推理与创意生成

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;Linux网络编程 &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 ​ Linux网络编程笔记&#xff1a; https://blog.cs…

DAY07 Collection、Iterator、泛型、数据结构

学习目标 能够说出集合与数组的区别数组:1.是引用数据类型的一种2.可以存储多个元素3.数组的长度是固定的 int[] arr1 new int[10]; int[] arr2 {1,2,3};4.数组即可以存储基本类型的数据,又可以存储引用数据类型的数据int[],double[],String[],Student[]集合:1.是引用数据类…

ls命令的全面参数解析与详尽使用指南

目录 ls 命令的所有参数及含义 ls -a 命令详解 ls -A 命令详解 ls -b 命令详解 ls -C 命令详解 ls -d 命令详解 ls -f 命令详解 ls -F 命令详解 ls -G 命令详解 ls -h 命令详解 ls -H 命令详解 ls -i 命令详解 ls -I 命令详解 ls -l 命令详解 ls -L 命令详解 l…

【Spring+MyBatis】_图书管理系统(中篇)

【SpringMyBatis】_图书管理系统&#xff08;上篇&#xff09;-CSDN博客文章浏览阅读654次&#xff0c;点赞4次&#xff0c;收藏7次。&#xff08;1&#xff09;当前页的内容records&#xff08;类型为List&#xff09;&#xff1b;参数&#xff1a;userNameadmin&&pas…

动态规划算法篇:枚举的艺术

那么本篇文章就正式进入了动态规划的算法的学习&#xff0c;那么动态规划算法也可谓是算法内容中的一座大山&#xff0c;那么在大厂算法笔试乃至算法比赛中出现的频率也逐渐变高&#xff0c;那么可见学习好动态规划算法的一个重要性&#xff0c;那么对于动态规划最难理解的&…

算法——舞蹈链算法

一&#xff0c;基本概念 算法简介 舞蹈链算法&#xff08;Dancing Links&#xff0c;简称 DLX&#xff09;是一种高效解决精确覆盖问题的算法&#xff0c;实际上是一种数据结构&#xff0c;可以用来实现 X算法&#xff0c;以解决精确覆盖问题。由高德纳&#xff08;Donald E.…

翻转硬币(思维题,巧用bitset)

0翻转硬币 - 蓝桥云课 #include <bits/stdc.h> using namespace std; bitset<200000001> t; int main() {int n;cin>>n;int ans1;t[1]1;int totn-1;for(int i2;i<n;i){if(t[i]) continue;int ji;ans;while(j<n){t[j]!t[j];if(t[j]) tot--;else tot;ji;…

网络安全等级保护测评(等保测评):全面指南与准备要点

等保测评&#xff0c;全称为“网络安全等级保护测评”&#xff0c;是根据《网络安全法》及《网络安全等级保护条例》等法律法规&#xff0c;对信息系统进行安全等级划分&#xff0c;并依据不同等级的安全保护要求&#xff0c;采用科学方法和技术手段&#xff0c;全面评估信息系…

blackbox.ai 一站式AI代理 畅享顶级模型

最近Deepseek火遍大江南北&#xff0c;一夜之间到处都能看到有人在体验AI技术。然而这也带来了一些困难&#xff1a;由于服务器压力过大&#xff0c;ds开始使用了一些限流的措施。 实际上这只是针对免费用户的限制手段&#xff0c;通过API付费方式的用户并没有这样的限制。所以…

ERP对制造业务有何价值?

ERP 的定义 在定义 ERP 之前&#xff0c;我们先从其首字母缩写说起&#xff0c;ERP 代表企业资源规划。我们可以将 ERP 定义为一种企业软件&#xff0c;它帮助组织管理日常业务。从根本上讲&#xff0c;ERP 将客户管理、人力资源、商业智能、财务管理、库存以及供应链功能整合…