【算法基础】基础算法(一)--(快速排序、归并排序、二分)

一、快速排序

详情可参考:【数据结构】排序(插入、选择、交换、归并) -- 详解_炫酷的伊莉娜的博客-CSDN博客

下面只作模板介绍和注意事项。 


1、快速排序算法模板

🔺记忆!

void quick_sort(int q[], int l, int r)
{//递归的终止情况if (l >= r) return;//选取分界线。这里选数组中间那个数int i = l - 1, j = r + 1, x = q[l + r >> 1];//划分成左右两个部分while (i < j){do i ++ ; while (q[i] < x);do j -- ; while (q[j] > x);if (i < j) swap(q[i], q[j]);}//对左右部分排序quick_sort(q, l, j), quick_sort(q, j + 1, r);
}

2、边界问题

边界问题只有这两种组合,不能随意搭配,要对称着写。
// 1. x不能取q[l]和q[l+r>>1]; 取q[r]或q[(l+r+1)>>1]
quick_sort(q,l,i-1),quick_sort(q,i,r);// 2. x不能取q[r]和q[(l+r+1)>>1]; 取q[l]或q[l+r>>1]
quick_sort(q,l,j),quick_sort(q,j+1,r);

假设 x = q[l]; quick_sort(q, l, i-1); quick_sort(q, i, r);

取一个样例:q = [1, 2]

那么 l = 0, r = 1;

则 x = q[0] = 1; qucik_sort(q, 0, -1); quick_sort(q, 0, 1);

第一个快排不符合条件,结束。第二个快排进入死循环。

其他边界问题同理,会进入死循环。


3、注意事项

(1)i = l-1, j = r+1;

为什么这里不是 i = l, j = r 呢?

因为后面用的是 do-whlie 循环,先进行循环体里面的内容,再来判断条件。因此 i,j 的初始位置分别位于 l,r 的两侧。

因为两个指针在每次交换完之后都需要向中间移动一位,所以可以每次上来就先移动一次,这样我们就需要把指针的初始值放到外侧。


(2)swap() 函数

如果不直接使用 swap 函数,也可以自己手写一个。

if (i < j)
{int k = q[i];q[i] = q[j];q[j] = k;
}

(3)do-while循环的条件

为什么这里 do-while 循环的条件不能写成 q[i] <= x 和 q[j] >= x?

do-whlie 循环中的条件不能带等号,如果加上等号可能会导致下标增加到 r+1,从而导致数组越界。


(4)if 条件

if (i < j) 能否改成 if (i <= j)?

if (i < j) 条件中可以加上等号,因为 i == j 时表示自己与自己交换,因此没有任何影响。


4、练习 

785. 快速排序 - AcWing题库

786. 第k个数 - AcWing题库


二、归并排序

详情可参考:【数据结构】排序(插入、选择、交换、归并) -- 详解_炫酷的伊莉娜的博客-CSDN博客

下面只作模板介绍和注意事项。 


1、归并排序算法模板

🔺记忆!

void merge_sort(int q[], int l, int r)
{//递归的终止情况if (l >= r) return;//第一步:分成子问题int mid = l + r >> 1;//第二步:递归处理子问题merge_sort(q, l, mid);merge_sort(q, mid + 1, r);//第三步:合并子问题int k = 0, i = l, j = mid + 1;while (i <= mid && j <= r)if (q[i] <= q[j]) tmp[k ++ ] = q[i ++ ];else tmp[k ++ ] = q[j ++ ];while (i <= mid) tmp[k ++ ] = q[i ++ ];while (j <= r) tmp[k ++ ] = q[j ++ ];//第四步:复制回原数组for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
}

2、注意事项

(1)移动

当两个序列当前指针对应的元素相等时,应该移动哪一个?

虽然说移动哪一个指针都可以,但是我们一般会选择移动第一个序列的指针。因为这样可以保持排序的稳定性。即保持序列中相同值在排序之后顺序不变。


(2)划分点的选取

为什么划分点为 mid ,而不是 mid-1?

因为 mid = (l+r) >> 1 是向下取整的,可能会取到 l。假设第一个递归范围是 [l,mid-1], 则第二个递归是 [mid,r],这就造成了当 mid 取到 l 时会无限划分,进入死循环。使用 mid 作为划分点不会造成无限划分,原因是两个范围 [l,mid],[mid+1,r],mid 是向下取整,所以不可能取到 r,因此不会出现 [l,r] 的情况,就不会产生无限划分。如果真的想要使用 mid-1 作为划分点,我们只需要让 mid 向上取整即可。即 mid = (l+r+1) >> 1。但实际上并不建议这样去写,因为判断条件会变成 while (i < mid && j <= r) 或者 while (i <= mid-1 && j <= r),这两种写法都不对称,不利于记忆,所以还是建议划分点选择 mid。


3、练习

787. 归并排序 - AcWing题库

788. 逆序对的数量 - AcWing题库


三、二分

1、整数二分算法模板

对  lower_bound  来说,它寻找的就是第一个满足条件  值大于等于  x”  的元素的位置;对  upper_bound  函数来说,它寻找的是第一个满足 “ 值大于 x”  的元素的位置。

🔺记忆! 

bool check(int x) {/* ... */} // 检查x是否满足某种性质// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{while (l < r){int mid = l + r >> 1;if (check(mid)) r = mid; // check()判断mid是否满足性质else l = mid + 1;//左加右减}return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{while (l < r){int mid = l + r + 1 >> 1;//如果下方else后面是l则这里加1if (check(mid)) l = mid;else r = mid - 1;//左加右减}return l;
}
  • 当我们将区间 [l,r] 划分成 [l,mid] 和 [mid+1,r] 时,其更新操作是 r = mid 或者 l = mid + 1;,计算 mid 时不需要加 1。 
  • 当我们将区间 [l,r] 划分成 [l,mid-1] 和 [mid,r] 时,其更新操作是 r = mid - 1 或者 l = mid;,此时为了防止死循环,计算 mid 时需要加 1。

【注意事项】 

(1)模板选取
该如何确定用哪个模板呢? 

取决于 check 的逻辑,如果我们发现需要更新区间为 [l,mid] 或 [mid + 1,r],就用第一个模板。如果我们发现我们需要更新区间为 [l,mid - 1] 或 [mid,r],就用第二个模板。

(2)mid 的选取

当左边界l 和 r 相距一个元素时,就是如果 l = r-1;也就是说 l 和 r 之间只相差 1 时,如果模板 2 中 mid = l + r >> 1; 那么通过向下取整,也就是 mid = (l + l + 1) >> 1; 可以得到 mid = l。假设 check 为 true,那么 l = mid = l; 判断结束后,l 和 r 都没作改变,就会陷入死循环。所以这里使用模板 2 必须得 + 1。


2、浮点数二分算法模板

🔺记忆! 

bool check(double x) {/* ... */} // 检查x是否满足某种性质double bsearch_3(double l, double r)
{const double eps = 1e-6; // eps 表示精度,取决于题目对精度的要求while (r - l > eps){double mid = (l + r) / 2;if (check(mid)) r = mid;else l = mid;}return l;
}

【注意事项】 

(1)精度
除了精度以外,还有其他表示方法吗?

可以写一个 for 循环,迭代 100 次,效果一样。

for (int i=0; i<100; i++)
{double mid = (l + r) / 2;if (check(mid)) r = mid;else l = mid;
}
(2)eps 的选取

如果题目要求保留 4 位小数,eps = 1.e-6。如果保留 5 位小数,eps = 1.e-7。这样可以保留一个经验值,其他情况以此类推。

(3)mid 的选取 
mid = l+r >> 1; 能否改成 mid = (l+r)/2; ?

这里的 mid 最好不要写成 l+r >> 1,因为 l+r >> 1 是将 l+r 右移一位,相当于除以 2,但在这里,我们需要计算 (l+r)/2,这个操作会进行向下取整,而右移操作会直接截断小数部分而不是四舍五入,所以可能会对精度产生影响。


3、练习

789. 数的范围 - AcWing题库

790. 数的三次方根 - AcWing题库

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

管道-有名管道

一、有名管道 有名管道与匿名管道的不同&#xff1a; 有名管道提供了一个路径名&#xff0c;并以FIFO的文件形式存在于文件系统中。与匿名管道不同&#xff0c;有名管道可以被不相关的进程使用&#xff0c;只要它们可以访问该路径&#xff0c;就能够通过有名管道进行通信。 FI…

基于SSM的学生事务处理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

MySQL 索引优化实践(单表)

目录 一、前言二、表数据准备三、常见业务无索引查询耗时测试3.1、通过订单ID / 订单编号 查询指定订单3.2、查询订单列表 四、订单常见业务索引优化实践4.1、通过唯一索引和普通索引优化通过订单编号查询订单信息4.2、通过普通联合索引优化订单列表查询4.2.1、分析查询字段的查…

GROMACS Tutorial 5: Protein-Ligand Complex 中文实战教程

GROMACS Tutorial 5: Protein-Ligand Complex 中文实战教程 前言系统环境特别强调一、预处理阶段1.1 蛋白质配体分离以及除水操作1.2 选择力场识别JZ4配体1.2.1 使用在线力场解析1.2.2 使用官方推荐力场CHARMM36解析 1.3 蛋白的top文件准备1.4 配体的top文件准备1.5 使用CgenFF…

【C++】模板初阶 -- 详解

一、泛型编程 // 实现一个通用的交换函数&#xff1a; void Swap(int& left, int& right) {int temp left;left right;right temp; }void Swap(double& left, double& right) {double temp left;left right;right temp; }void Swap(char& left, ch…

高層建築設計和建造:從避難層到設備間和防風防火防水的設計理念,酒店住宅辦公樓都有什麽房間(精簡)

樓層概覽 標準層居住、辦公、商業等功能的樓層。結構和裝修與其他樓層相同&#xff0c;可供人正常居住、工作和活動避難層專門用於人員避難的樓層&#xff0c;通常會相隔數十個標準層&#xff0c;樓梯通常和標準層是錯開的(非公用)&#xff0c;具有更多的通風口。牆體和樓板具…

【Linux】TCP的服务端 + 客户端

文章目录 &#x1f4d6; 前言1. 服务端基本结构1.1 类成员变量&#xff1a;1.2 头文件1.3 初始化&#xff1a;1.3 - 1 全双工与半双工1.3 - 2 inet_aton1.3 - 3 listen 2. 服务端运行接口2.1 accept&#xff1a;2.2 服务接口&#xff1a; 3. 客户端3.1 connect&#xff1a;3.2 …

代谢组学分析平台(二)

GC/MS分析生物样本为何要衍生化处理&#xff1f;有哪些衍生化的方法&#xff1f; GC的流动相为气体&#xff08;通常为高纯氦&#xff09;&#xff0c;这就要求被分析物必须能够气化&#xff0c;而生物样本中很多内源性代谢物都含有极性基团&#xff0c;具有沸点高、不易气化特…

linux 笔记 安装 anaconda

1 找到anaconda 安装包 Free Download | Anaconda 2 在linux环境中安装对应安装包 3 安装完毕后查看是否安装好 发现不行&#xff0c;需要配置环境变量 4 配置环境变量 vim /etc/profile使用这个&#xff0c;发现对应的文件是只读文件 sudo vim /etc/profile在最下面加一…

【数据结构与算法】- 数组

数组 1.1 数组的定义1.2 数组的创建1.3 数组在内存中的情况2.1 初始化数组2.2 插入元素2.3 删除元素2.4 读取元素2.5 遍历数组 1.1 数组的定义 数组中的是在内存中是连续存储的&#xff0c;内存是由一个个内存单元组成的&#xff0c;每一个内存单元都有自己的地址&#xff0c;…

Linux 安全 - Credentials

文章目录 一、简介1.1 Objects1.2 Object ownership1.3 The objective context1.4 Subjects1.5 The subjective context1.6 Actions1.7 Rules, access control lists and security calculations 二、Types of Credentials2.1 Traditional UNIX credentials2.2 Capabilities2.3 …

【iptables 实战】05 iptables设置网络转发实验

一、网络架构 实验效果&#xff0c;通过机器B的转发功能&#xff0c;将机器A的报文转发到机器C 本实验准备三台机器分别配置如下网络 机器A ip:192.168.56.104 机器C ip:10.1.0.10 机器B 两张网卡&#xff0c;分别的ip是192.168.56.106和10.1.0.11 如图所示 如下图所示 二、…

PPT/PS——设置图片的背景为透明色的方法

方法一 将图片放到PPT内&#xff0c;点击图片&#xff0c;点击格式&#xff0c;删除背景 方法二 PS小白 扣去背景流程PS怎么把背景色改成透明色呢&#xff1f;

18年,51cto老师录视频- Vue.js前端开发基础与项目实战的接口,不能用了

18年&#xff0c;51cto老师录视频的接口&#xff0c;不能用了 获取商品列表 http://api.mm2018.com:8090/api/goods/home 23年&#xff0c;51cto老师录视频的接口&#xff0c;和老师新要的 获取商品列表 http://api.mm2018.com:8095/api/goods/home 请求无参&#xff1a; 响…

C#打包表情图片至Dll文件中供winform中调用

首先参照了这篇文章&#xff1a;C# 图片打包成DLL文件进行调用_png转dll-CSDN博客&#xff0c;感谢大神&#xff01; 想在winform里做个表情选择的界面&#xff0c;如果表情图片直接放在本地的话会造成更改或删除&#xff0c;给程序带来不确定的因素&#xff0c;还是直接把图片…

CSS 简介

你需要具备的知识 在继续学习之前&#xff0c;你需要对下面的知识有基本的了解&#xff1a; HTML / XHTML 什么是 CSS? CSS 指层叠样式表 (Cascading Style Sheets)样式定义如何显示 HTML 元素样式通常存储在样式表中把样式添加到 HTML 4.0 中&#xff0c;是为了解决内容与…

C++模拟题[第一周-T1] 扑克

[第一周-T1] 扑克 题目描述 斗地主是一种使用 A \tt A A 到 K \tt K K 加上大小王的共 54 54 54 张扑克牌来进行的游戏&#xff0c;其中大小王各一张&#xff0c;其它数码牌各四张。在斗地主中&#xff0c;牌的大小关系根据牌的数码表示如下&#xff1a; 3 < 4 < 5 …

npm ,yarn 更换使用国内镜像源,淘宝源

背景 文章首发地址 在平时开发当中&#xff0c;我们经常会使用 Npm&#xff0c;yarn 来构建 web 项目。但是npm默认的源的服务器是在国外的&#xff0c;如果没有梯子的话。下载速度会特别慢。那有没有方法解决呢&#xff1f; 其实是有的&#xff0c;设置国内镜像即可&#x…

c++学习之优先级队列

目录 1.初识优先级队列 库中的实现 使用优先级队列 2.优先级队列的实现 3.仿函数 利用仿函数实现的优先级队列 迭代器区间构造&#xff08;建堆&#xff09; 1.初识优先级队列 如果我们给每个元素都分配一个数字来标记其优先级&#xff0c;不妨设较小的数字具有较…

怎么通过portainer部署一个vue项目

这篇文章分享一下今天通过docker打包vue项目&#xff0c;并使用打包的镜像在portainer上部署运行&#xff0c;参考了vue-cli和docker的官方文档。 首先&#xff0c;阅读vue-cli关于docker部署的说明 vue-cli关于docker部署的说明https://cli.vuejs.org/guide/deployment.html#…