当前位置: 首页 > news >正文

【算法】——分治思想与快速排序的实践应用

前言:

本篇文章会先介绍一下快速排序算法,然后重点是快速排序在一些算法题中的应用,在使用当中感受快速排序的魅力。(本篇文章主要使用C++语言)

一、什么是快速排序?

1. 简单介绍

首先它是一种优化的排序算法。常规的排序通常是O(n^2)的时间复杂度,而快速排序的时间复杂度是O(n*lgn),这样一来在数据量大的情况下就可以节省大量时间。

2. 如何实现

分治思想是快速排序算法的核心思想。分治即分而治之,将一个很难完成的大任务拆分成一个个很好完成的小任务,然后完成每一个小任务进而间接完成大任务。

快速排序的实现过程可以概括为三个步骤:

1. 选取基准值(从数组中随机选取一个数据作为基准值)

2. 分区(将比基准值小的放到基准前面,比基准值大的放到基准后面)

3. 递归(再对分好区的两边重复1,2,3步,直至不可分为止)

可以借助这张图理解:

先介绍一个分为两个区间,使用hoare方法的实现方式:

1. 这里为了简化,基准值取第一个元素

2. right从右往左走,找比基准值小的数据,left从左往右走,找比基准值大的数据

3. 找到之后交换left和right的数值,再left++, right--,重复第二步

4. 最后再将基准值换到中间

示例代码:

//hoare方法
int _quicksort(int* arr, int left, int right) {//基准值取第一个元素int keyi = left;//先将left+1,使其移到基准值的后一个位置left++;//right从右往左走,找比基准值小的数据,left从左往右走,找比基准值大的数据while (left <= right) {if (arr[right] >= arr[keyi]) {right--;}else if(arr[left] <= arr[keyi]) {left++;}else {Swap(&arr[left], &arr[right]);left++;right--;}}//交换数组第一个数据和 左数组的最后一个数据,实现基准值归位到中间Swap(&arr[keyi], &arr[left - 1]);keyi = left - 1;return keyi;
}void QuickSort(int* arr, int left, int right) {//快速排序借鉴了二叉树的思想,在数组中找一个基准值,然后将小的数据放在基准值左边,大的数据在右边, 然后在对左右数组循环此操作if (left >= right) {return;}int keyi = _quicksort(arr, left, right);QuickSort(arr, left, keyi - 1);QuickSort(arr, keyi + 1, right);
}

接下来介绍分为三个区间的实现方法:

1. 用随机数求一个key

2. 定义left, right, i

3. [0, left]最终表示<key的数据区域, 而[right, n-1]表示最终>key的数据区域

4. i从0开始遍历到n-1,小于key的就和++left交换,大于key的就和--right交换(由于[0, left]是闭区间,所以交换前left需要先+1再交换,来接纳一个新的<key的数,right同理)

由于没有情景看代码比较抽象,所以我们接下来直接配合题目来看代码

二、快速排序使用实例

1. 颜色分类

这道题要求把数组分为红白蓝三色,实际就是将数组按0,1,2的顺序排序。那我们用快速排序就能快速解决,key也不用随机了,直接key = 1

void sortColors(vector<int>& nums) {// 快速排序int left = -1;// 排序后[0, left]的数据都是0int right = nums.size();// 排序后[right, nums.size()-1]的数据都是2int i = 0;// 排序后[left+1, right-1]的数据都是1while(i < right){if(nums[i] < 1){swap(nums[++left], nums[i++]);}else if(nums[i] == 1){++i;}else{// 因为初始右边数据是无序的,所以与right交换时i不++,而是需要再判断一次swap(nums[--right], nums[i]);}}
}

1. left初始化为-1, right初始化为size(), 表明初始情况下左右区间都是空,全是待扫描数据

2. 然后i从0开始遍历,进行以下操作:

2. 排序数组

主程序调用qsor排序即可,不过要注意要加上srand(time(NULL))设置随机数种子

vector<int> sortArray(vector<int>& nums) {srand(time(NULL));qsort(nums, 0, nums.size()-1);return nums;
}

随机数生成key的函数:

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

重点来看qsort的实现:

1. l和r是数组是左右边界,当l >= r时结束递归

2. 定义left和right,用于分区,i从l开始遍历

3. 将nums [i] 和key比较,并进行相应的交换操作

4. 对左右两块区域进行递归调用qsort,区间分别是[l, left]和[right, r]

   void qsort(vector<int>& nums, int l, int r){if(l >= r){return;}int left = l-1;int right = r+1;int i = l;int key = getRandom(nums, l, r);while(i < right){if(nums[i] < key){swap(nums[i++], nums[++left]);}else if(nums[i] == key){i++;}else{swap(nums[i], nums[--right]);}}qsort(nums, l, left);qsort(nums, right, r);}

3. 快速选择排序解决topk问题

快速排序可以分区,那么当遇到topk问题时,每次分完区后topk会落在某一段区间内,那么剩下的区间我们就可以舍弃,这样就可以大大提高寻找效率。

随机生成k部分还是一样

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

主函数也差不多

    int findKthLargest(vector<int>& nums, int k) {srand(time(NULL));return qsort(nums, 0, nums.size()-1, k);}

重点看qsort部分:

1. 递归结束条件改为了l == r,结束后直接返回nums[l],这就是我们要求的第k大的数据、

2. 分类讨论时定义c为>key区域的数据个数, b为=key区域的数据个数

3. 情况一:如果c >= k,说明目标数据在第三个区域,那直接舍弃前两个再递归

4. 情况二:如果b + c >= k,说明目标数据在第二个区域,直接返回key

5. 情况三:目标在第一个区域,舍弃后两个区域再递归

    int qsort(vector<int>& nums, int l, int r, int k){if(l == r){return nums[l];}int left = l-1;int right = r+1;int i = l;int key = getRandom(nums, l, r);while(i < right){if(nums[i] < key){swap(nums[i++], nums[++left]);}else if(nums[i] == key){i++;}else{swap(nums[i], nums[--right]);}}// 分类讨论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);}}

总结:

本篇文章介绍了分治与快速排序算法,并用了三道例题来讲解,如果觉得右帮助的话可以点赞收藏加关注支持一下!

http://www.dtcms.com/a/414591.html

相关文章:

  • JavaScript ES5 vs ES6 核心特性对比
  • three.js
  • PyQt和Qt、PyQt和PySide的关系
  • 网站开发工具与技术企业网站空间在哪里
  • 网站开发一个页面多少钱天堂网
  • 为软件“分家”:组件化治理大型工程的艺术
  • Windows 系统部署 阿里团队开源的先进大规模视频生成模型 Wan2.2 教程——基于 EPGF 架构
  • 建站之星建出来的网站如何上传请写出网站建设的步骤
  • 金融门户网站建设搜索引擎优化公司排行
  • 【AI】详解BERT的输出张量pooler_output
  • Leecode hot100 - 39. 组合总和
  • 网站建设方案书 广东开发公司成本部职责岗位职责和流程
  • MySQL笔记10
  • Python快速入门专业版(四十八):Python面向对象之多态:不同对象调用同一方法的不同实现(实战案例)
  • C# HttpListener 服务器上无法访问端口
  • [创业之路-605]:半导体行业供应链
  • SpringAOP面向切面编程
  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段(36):文法運用
  • 郑州做网站茂睿科技全域seo
  • 一阶谓词逻辑及其重要子集对人工智能自然语言处理深层语义分析的影响与启示
  • 平阴县网站建设视频直播网站开发与制作
  • GPTEngineer:AI 驱动的Web应用开发平台
  • STL简介
  • 本地安装Codex,国内直接使用GPT-5-Codex
  • OpenGL ES vs VG-Lite:嵌入式图形渲染引擎对比分析
  • Linux 自定义shell命令解释器
  • 陕西科强建设工程有限公司官方网站重庆企业建站系统模板
  • 【RabbitMQ】原理解析
  • Spring的IoC与DI
  • 做家装的网站有哪些安徽建工集团网站