算法导论——分治法、归并排序——伪代码和Java实现

2023-11-12

第二章第三节:分治法

    我们首先先介绍分治法。分治法的思想:将原问题分解为几个规模较小但类似于原问题的子问题,递归地求解这些子问题,然后在合并这些子问题的解来解决原问题的解。

    还是拿扑克牌举例子,假设桌上有两堆牌面朝上的牌(牌面朝上:有值),每堆都已排序,最小的牌在顶上。我们希望把这两堆牌合并成单一的排好序的输出堆,牌面朝下地放在桌上。应该怎么做呢?
    我们的做法是:在牌面朝上的两堆牌的顶上两张牌中选取较小的一张,将该牌从其堆中移开(该堆的顶上将显示一张新牌)并牌面朝下地将该牌放置到输出堆。重复这个步骤直到两堆牌都没有牌。
    下面我们来实现上面所提的思想
    为了避免在某个基本步骤必须检查是否有堆为空。在每个堆的底部放置一张哨兵牌,它包含一个特殊的值(很大的值,使它不可能是较小的牌,除非两个堆都已显露出其哨兵牌。一旦发生这种情况,说明非哨兵牌都已被放置到输出堆),用于简化代码。

伪代码:

MERGE(A,p,q,r)
n1 = q - p + 1
n2 = r - q
//L[1..n1+1] and R[1..n2+1]是新的数组
for i = 1 to n1
	L[i] = A[p + i -1]
for j = 1 to n2
	R[j] = A[q + j]
L[n1 + 1] = ∞
R[n2 + 1] = ∞
i = 1
j = 1
for k = p to r
	if L[i] <= R[j]
		A[k] = L[i]
		i = i + 1
	else 
		A[k] = R[j]
		j = j + 1

Java实现:

public void Merge(int[] A,int p,int q,int r){
        int n1 = q - p + 1;
        int n2 = r - q;

        //L[1..n1+1] and R[1..n2+1]是新的数组
        int[] L = new int[n1 + 1];
        int[] R = new int[n2 + 1];

        for (int i = 0;i < n1;i++){
            L[i] = A[p + i];
        }
        for (int j = 0;j < n2;j++){
            R[j] = A[q + j + 1];
        }

        L[n1] = Integer.MAX_VALUE;
        R[n2] = Integer.MAX_VALUE;

        int i = 0,j = 0;
        for (int k = p;k <= r;k++){
            if (L[i] <= R[j]){
                A[k] = L[i];
                i = i + 1;
            }else{
                A[k] = R[j];
                j = j + 1;
            }
        }
    }

    下面我们来看一下分治法的步骤
    对数组A[2,4,7,1,3,6]调用Merge(A,0,2,5)

初始状态↓
初始状态
    初始完L和R数组之后,现在进入for循环阶段。让L中i所指的值和R数组中j所指的值进行比较,把较小的值放入数组A中k所指的位置。并且让较小的值的索引i或j前进一格(+1)。因为L和R数组已经从小到大排好序了,所以找出来的最小值一定是当前L和R数组的最小值,放入了数组A中也是排好序的,所以让k前进一步,k=k+1,然后执行下一次循环。
第一此循环:i和j初始为0,k=p=0,让L[0]与R[0]进行比较 L[0]>R[0]所以R[0]是较小值,把A[0]替换为R[0]。让j=j+1,i保持不变。k=k+1=1,开启下一次循环。本次循环结果如下图所示:
    A中的灰色位置包含将被覆盖的值,L和R中的灰色位置包含有待于被复制回A的值,A中的黄色位置包含它们的最终值,L和R中的黄色位置包含已被复制回A的值。
第一步

    第二次循环:此时i=0,j=1,k=1,让L[i]和R[j]进行比较,L[0]<R[1],所以L[0]是较小值,把A[k]即A[1]替换为L[0]。让i=i+1,j保存不变。k=k+1=2,开启下一次循环。本次循环结果如下图所示:
第二步
    第三次循环:此时i=1,j=1,k=2,让L[i]和R[j]进行比较,L[1]>R[1],所以R[1]是较小值,把A[2]即A[2]替换为R[1]。让j=j+1,i保存不变。k=k+1=3,开启下一次循环。本次循环结果如下图所示:
第三步
    第四次循环:此时i=1,j=2,k=3,让L[i]和R[j]进行比较,L[1]<R[2],所以L[1]是较小值,把A[k]即A[3]替换为L[1]。让i=i+1,j保存不变。k=k+1=4,开启下一次循环。本次循环结果如下图所示:
第四步
    第五次循环:此时i=2,j=2,k=4,让L[i]和R[j]进行比较,L[2]>R[2],所以R[2]是较小值,把A[k]即A[4]替换为R[2]。让j=j+1,j保存不变。k=k+1=4,开启下一次循环。本次循环结果如下图所示:第五步
    注意:此时j已经到达了R数组的最后一个数∞,L数组中的每个数都比∞小,即不等式L[i]>R[j]恒成立。所以不管L剩下多少个数,都会按照顺序放置A中,直到i也达到了最后一个数∞,此时k>r,循环已经全部结束。
    第六次循环:此时i=2,j=3,k=5,让L[i]和R[j]进行比较,L[2]<R[3],所以L[2]是较小值,把A[k]即A[5]替换为L[2]。让i=i+1,j保存不变。k=k+1=6,开启下一次循环。本次循环结果如下图所示:第六步
    第七次循环,此时i=2,j=3,k=6,我们的r=5,判断条件k<=r为false,循环结束。

分治法的应用——归并排序

    上面讲到了分治法,分治法有个很大的限制就是L和R是排好序的才可以。但是许多数组都是很乱的顺序。那么怎么解决这个问题呢?试想一下如果L和R数组的大小为1,那么L和R数组肯定是排好序的。对的!我们可以把一个大的数组递归拆分成小的子数组,子数组在递归拆分成更小的子数组。直到递归到的L和R数组的大小为1时,调用MERGE分治法。随着算法自底向上地推进:合并只含1项的序列对形成长度为2的排好序的序列,合并长度为2的序列对形成长度为4的排好序的序列,依次下去,直到长度为n/2的两个序列被合并最终形成长度为n的排好序的序列,数组最终会排序完成。

如下图所示
示意图
    我们可以把上面提到的MERGE作为归并排序算法中的一个子程序来用。
    下面的过程MERGE-SORT(A,p,r)排序子数组A[p…r]中的元素。若p>=r,则该子数组最多有一个元素,所以已经排好序。否则,分解步骤简单地计算一个下标q,将A[p…r]分成两个子数组A[p…q]和A[q+1…r],前者包含⌈n/2⌉个元素,后者包含⌊n/2⌋个元素。
伪代码:

MERGE-SORT(A,p,r)
if p < r
	q = ⌊(p+r)/2⌋
	MERGE-SORT(A,p,q)
	MERGE-SORT(A,q+1,r)
	MERGE(A,p,q,r)

java实现:

public void MergeSort(int[] A,int p,int r) {
        if (p < r){
            int q =(int)Math.floor((p+r)/2);	
            MergeSort(A,p,q);			//将左半边排序
            MergeSort(A,q+1,r);			//将右半边排序
            Merge(A,p,q,r);				//归并结果
        }
}

    下面我们来看一下归并排序在数组A=[5,2,4,7,1,3,2,6]上的操作,随着算法自底向上地推进,待合并的已排好序的各序列的长度不断增加。
对数组应用归并排序

‘-----------------------------------------------------------------’
    分治法的讲解到这里已经结束
    其他算法:算法导论——各章节算法伪代码和java实现

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

算法导论——分治法、归并排序——伪代码和Java实现 的相关文章

  • Keytool 应用程序在哪里?

    我需要在android中使用mapview控件 但我似乎不明白如何运行keytool 是用eclipse安装的吗 我好像找不到下载链接 Thanks keytool http docs oracle com javase 7 docs te
  • 清理码头 - 删除“不必要”的东西

    我习惯用Jetty http jetty codehaus org jetty 作为我的网络容器 我对我做了什么安装步骤得到原始的焦油球并且清理一些目录和文件从中 我在这里想提出的是 您通常从 Jetty 中删除什么以在生产 登台环境中使用
  • 使用 GWT CellTableBuilder 构建树表

    Is it possible to build a tree table like this http www sencha com examples ExamplePlace basictreegrid with the new Cell
  • 添加动态数量的监听器(Spring JMS)

    我需要添加多个侦听器 如中所述application properties文件 就像下面这样 InTopics Sample QUT4 Sample T05 Sample T01 Sample JT7 注意 这个数字可以多一些 也可以少一些
  • Spring安全“记住我”cookie在第一个请求中不可用

    我无法在登录请求后检索 Spring 记住我 cookie 但它在对受保护页面的下一个请求中工作正常 谁能告诉我怎样才能立即得到它 我在登录请求中设置了记住我的 cookie 但在 Spring 重定向回原始 受保护的 url 后无法检索它
  • 如何在 JSP 中导入类?

    我是一个完全的JSP初学者 我正在尝试使用java util List在 JSP 页面中 我需要做什么才能使用除以下类之外的类java lang 使用以下导入语句进行导入java util List 顺便说一句 要导入多个类 请使用以下格式
  • 如果使用的 JVM 是 x86 或 x64,则以不同的方式解决 Maven 依赖关系?

    我设置了一个 Maven 存储库来托管一些 dll 但我需要我的 Maven 项目根据使用的 JVM 是 x86 还是 x64 下载不同的 dll 例如 在运行 x86 版本 JVM 的计算机上 我需要从存储库下载 ABC dll 作为依赖
  • Java:正则表达式排除空值

    在问题中here https stackoverflow com questions 51359056 java regexp for a separated group of digits 我得到了正则表达式来匹配 1 到 99 之间的一
  • 如何获取 WebElement 的父级[重复]

    这个问题在这里已经有答案了 我试过了 private WebElement getParent final WebElement webElement return webElement findElement By xpath 但我得到
  • 将表值参数与 SQL Server JDBC 结合使用

    任何人都可以提供一些有关如何将表值参数 TVP 与 SQL Server JDBC 一起使用的指导吗 我使用的是微软提供的6 0版本的SQL Server驱动程序 我已经查看了官方文档 https msdn microsoft com en
  • 隐式超级构造函数 Person() 未定义。必须显式调用另一个构造函数?

    我正在开发一个项目 但收到错误 隐式超级构造函数 Person 未定义 必须显式调用另一个构造函数 我不太明白它 这是我的人物课程 public class Person public Person String name double D
  • 列表应该如何转换为具体的实现?

    假设我正在使用一个我不知道源代码的库 它有一个返回列表的方法 如下所示 public List
  • Java 数组的最大维数

    出于好奇 在 Java 中数组可以有多少维 爪哇language不限制维数 但是JavaVM规范将维度数限制为 255 例如 以下代码将无法编译 class Main public static void main String args
  • 计算日期之间的天数差异

    在我的代码中 日期之间的差异是错误的 因为它应该是 38 天而不是 8 天 我该如何修复 package random04diferencadata import java text ParseException import java t
  • Cloudfoundry:如何组合两个运行时

    cloundfoundry 有没有办法结合两个运行时环境 我正在将 NodeJS 应用程序部署到 IBM Bluemix 现在 我还希望能够执行独立的 jar 文件 但应用程序失败 APP 0 bin sh 1 java not found
  • Android Studio 将音乐文件读取为文本文件,如何恢复它?

    gameAlert mp3是我的声音文件 运行应用程序时 它询问我该文件不与任何文件类型关联 请定义关联 我选择TextFile错误地 现在我的音乐文件被读取为文本文件 我如何将其转换回music file protected void o
  • 解析输入,除了 System.in.read() 之外不使用任何东西

    我很难找到具体的细节System in read 有效 也许有人可以帮助我 似乎扫描仪会更好 但我不允许使用它 我被分配了一个任务 我应该以 Boolean Operator Boolean 的形式读取控制台用户输入 例如T F 或 T T
  • 如何在 Quartz 调度程序中每 25 秒运行一次?

    我正在使用 Java 的 Quartz Scheduling API 你能帮我使用 cron 表达式每 25 秒运行一次吗 这只是一个延迟 它不必总是从第 0 秒开始 例如 序列如下 0 00 0 25 0 50 1 15 1 40 2 0
  • JVM:是否可以操作帧堆栈?

    假设我需要执行N同一线程中的任务 这些任务有时可能需要来自外部存储的一些值 我事先不知道哪个任务可能需要这样的值以及何时 获取速度要快得多M价值观是一次性的而不是相同的M值在M查询外部存储 注意我不能指望任务本身进行合作 它们只不过是 ja
  • Android 和 Java 中绘制椭圆的区别

    在Java中由于某种原因Ellipse2D Double使用参数 height width x y 当我创建一个RectF在Android中参数是 left top right bottom 所以我对适应差异有点困惑 如果在 Java 中创

随机推荐

  • java用枚举代替int常量,让你的系统更安全--用枚举enum替代int常量

    做应用系统时 我们往往假设用户是小白 那么为了保证系统的正常 我们往往会对用户的参数做限制 并且前后端都要对用户的参数做验证 那我们在设计的时候是否可以提前预防这种问题呢 其中的一种方式就是 用枚举enum替代int常量 枚举的好处 做应用
  • sql语句去重distinct、统计(count、sum)

    1 查询数组并去重 用distinct 函数 select distinct 字段名 from 表名 2 count 和 sum 1 count 函数是用于统计数据的条数 select count as count from A where
  • 备战2022蓝桥杯每日一题(1)

    简单的a b 题目描述 收获 scanf函数的返回值 scanf 函数返回值分为3种 1 返回正整数 表示正确输入参数的个数 2 返回整数0 表示用户的输入不匹配 无法正确输入任何值 3 返回 1 表示输入流已经结束 在Windows下 用
  • Android 不自动弹出软键盘

    进入新 Activity界面 想阻止软键盘自动弹出 只要在 AndroidManifest xml 中对应的Activity下设置 android windowSoftInputMode adjustUnspecified stateHid
  • J-A-V-A的知识积累(一)

    1 hashMap的深入分析 https blog csdn net lianhuazy167 article details 66967698 红黑树 https blog csdn net cyp331203 article detai
  • python读写excel时间的处理

    用python读写excel 当读写内容为时间时 会发现时间变成了浮点数 这篇文章记录了对于这种情况的处理 将时间写入excel dateFormat xlwt XFStyle dateFormat num format str yyyy
  • 复试英语面试常见问题整理自用,考研复试英语问题汇总

    更多复试资料获取方式在文末 个人整理 完全免费 更多复试资料获取方式在文末 个人整理 完全免费 Why did you choose our university Firstly it provides high quality compu
  • stm32定时器与定时器中断

    1 定时器种类 注 主要使用通用定时器 2 通用计时器特点描述 说明 四个通道互不影响 3 定时器中断触发条件 4 定时器计数模式 分为向上 向下 向上向下模式 5 通用定时器作用用途 测量输入输出波长度等 说明 每个定时器完全独立没有共享
  • 【夜莺监控方案】10-报警策略-端口报警

    文章目录 1 邮箱配置 2 资源管理 中配置 1 2 创建端口采集 必要 3 配置告警策略 1 邮箱配置 opt n9e server etc script root n9e v5 script ll 总用量 12 rwxr xr x 1
  • 抖音广告助手是干什么的?在文章中为大家总结了4点

    抖音广告助手是干什么的 我们在刷抖音短视频时可能会刷到一个名称为 抖音广告助手 的账号 一些用户可能对于这个账号到底是干什么的存在着一定的疑问 这里首先告诉大家一点的是 这个账号是属于官方的一个账号 那么到底是用来干什么的 在接下来的文章中
  • linux下strace的用法

    strace多个进程 strace ps aux grep ProcGroupName grep v grep awk print p 2 xargs echo strace多个进程id下的所有线程 strace ps T ProcId1
  • DedeCMS搜索文件search.php移动至根目录的方法

    这篇文章主要为大家详细介绍了DedeCMS搜索文件search php移动至根目录的方法 具有一定的参考价值 感兴趣的小伙伴们可以参考一下 有需要的朋友可以收藏方便以后借鉴 织梦默认的搜索页是在根目录下的plus文件夹内的search ph
  • centOS 安装 Android NDK

    原文链接 https www jianshu com p 9ada3fd9c286 侵删 1 文件准备 下载linux版本的ndk 可到android studio中文网下载 2 工具准备 命令 yum y install upzip 或y
  • 如何恢复误删除的注册表信息

    如何恢复误删除的注册表信息 首先我们要打开注册表 不会打开注册表的朋友 请搜索前面我发表过的一篇题为 快速打开注册表方法大全 的文章 在这里我使用最简单的 windows R 键 再输入 regedit 回zhidao车确认即可快速打开 打
  • C++模板重载

    C 模板重载 产生背景 需要多个对不同类型使用同一种算法函数时可以使用模板 但是并非所有的类型都使用同一种算法 为了解决这个问题 产生了模板重载 Tips 1 如同函数的重载一样 模板重载函数的特征标必须不同 2 并非所有的模板参数都必须是
  • 计算机无法访问iTunes,无法连接到iTunes Store解决方法介绍

    相信很多用户在App Store上下载应用的时候会出现提示 无法连接到itunes store 那么出现这个提示是什么问题呢 我们怎么解决呢 小编下面就给大家带来无法连接到iTunes Store解决方法介绍 无法连接到iTunes Sto
  • 华为OD机试 - 素数之积(Java)

    题目描述 RSA加密算法在网络安全世界中无处不在 它利用了极大整数因数分解的困难度 数据越大 安全系数越高 给定一个 32 位正整数 请对其进行因数分解 找出是哪两个素数的乘积 输入描述 一个正整数 num 0 lt num lt 2147
  • gitlab设置分支保护

    1 第一步 找到分支 然后点击setting 然后选择Repository 2 第一步 选择Protected Branches 3 第三步 选择需要被限制的分支 进行权限授权 然后点击protect即可 使用Merge Request时的
  • 小狼毫Rime输入法简单配置指南

    目录 为什么选择它 Rime 一 下载 二 安装 1 官方安装包下载 2 安装选择 3 安装完成 三 配置小狼毫 语言栏设置 1 简体设置 2 输入框配置 3 字符配置 4 英文输入库配置 为什么选择它 Rime 神级输入法 简洁 流畅 无
  • 算法导论——分治法、归并排序——伪代码和Java实现

    第二章第三节 分治法 我们首先先介绍分治法 分治法的思想 将原问题分解为几个规模较小但类似于原问题的子问题 递归地求解这些子问题 然后在合并这些子问题的解来解决原问题的解 还是拿扑克牌举例子 假设桌上有两堆牌面朝上的牌 牌面朝上 有值 每堆