关于博主skywang123456文章——二叉堆(三)之 Java的实现的质疑
博客园博主skywang123456(以下简称s博主)是一个大牛级的人物,相信很多程序员都拜读过他的博客,我也不例外,并且受益匪浅。但是对于文章二叉堆(三)之 Java的实现我有一些疑惑,写在这里,供有缘人参考。对于而二叉堆的插入,是一个较为简单的方法,这里没有什么问题。但是而二叉堆的删除确是一个稍微复杂一点的操作,事实上,我第一次看这篇博文的时候就感觉有些恍惚不清。一般来说,而二叉堆的删除分为删除堆顶和查找型删除。堆顶删除可以由查找型删除实现,故名思意,直接删除堆顶的数据即可,在二叉堆的实际应用中被广泛使用。而查找型删除首先要查到给定参数的位置,然后删除该元素。而我要指出的问题是博主s使用删除堆顶的代码来代替了查找型删除的代码,而这两个我会举例来说明是不同的。
先来看博主s的删除代码
public int remove(T data) {
// 如果"堆"已空,则返回-1
if(mHeap.isEmpty() == true)
return -1;
// 获取data在数组中的索引
int index = mHeap.indexOf(data);
if (index==-1)
return -1;
int size = mHeap.size();
mHeap.set(index, mHeap.get(size-1));// 用最后元素填补
mHeap.remove(size - 1); // 删除最后的元素
if (mHeap.size() > 1)
filterdown(index, mHeap.size()-1); // 从index号位置开始自上向下调整为最小堆
return 0;
}
protected void filterdown(int start, int end) {
int c = start; // 当前(current)节点的位置
int l = 2*c + 1; // 左(left)孩子的位置
T tmp = mHeap.get(c); // 当前(current)节点的大小
while(l <= end) {
int cmp = mHeap.get(l).compareTo(mHeap.get(l+1));
// "l"是左孩子,"l+1"是右孩子
if(l < end && cmp<0)
l++; // 左右两孩子中选择较大者,即mHeap[l+1]
cmp = tmp.compareTo(mHeap.get(l));
if(cmp >= 0)
break; //调整结束
else {
mHeap.set(c, mHeap.get(l));
c = l;
l = 2*l + 1;
}
}
mHeap.set(c, tmp);
}
不难理解,将查找到的节点使用堆尾数据填充,之后删除堆尾数据,接着从该节点自上往下调整为最小堆。(目测笔误,应该是最大堆)这是典型的删除堆顶的代码。
博主s在文中给了两个删除的例子。第一个是删除堆顶的元素,因为没有根节点,所以当然适合这个代码。

而第二个例子不是删除根节点的数据,但是为什么也可以?这是一个巧合,恰好是符合某些特定的条件。

如图所示,删除节点60,补充40,40小于其子节点50,然后交换。其实有一种情况,即堆尾数据补充之后会大于原先的父节点,我们来看下图这个堆。

如果我们删除节点2,按照博主s的步骤,将5补充到原有节点2的位置,然后删除原有节点5,这样就变成右图。之后由于没有子节点,因此结束删除操作。可是右边是一个最大堆吗?显然不是!
所以查找型删除应该添加一个步骤,即先判断是否大于父节点(对于最大堆来说),如果大于父节点,则进行向上交换,直到符合最大堆的条件。查找型删除可以参考我这一篇文章二叉堆的介绍和Java实现 。当然我的代码没有过多测试,可能也有没有考虑到的地方,欢迎大家直接勘误。
以上,便是我看完这篇博文的一些质疑和思考,所说的不一定都对。当然,即使博主s真的有失误,也不影响我这么长时间看他博文所获得的进步。
关于博主skywang123456文章——二叉堆(三)之 Java的实现的质疑的更多相关文章
- 二叉堆(三)之 Java的实现
概要 前面分别通过C和C++实现了二叉堆,本章给出二叉堆的Java版本.还是那句话,它们的原理一样,择其一了解即可. 目录1. 二叉堆的介绍2. 二叉堆的图文解析3. 二叉堆的Java实现(完整源码) ...
- 二项堆(三)之 Java的实现
概要 前面分别通过C和C++实现了二项堆,本章给出二项堆的Java版本.还是那句老话,三种实现的原理一样,择其一了解即可. 目录1. 二项树的介绍2. 二项堆的介绍3. 二项堆的基本操作4. 二项堆的 ...
- 二叉堆(一)之 图文解析 和 C语言的实现
概要 本章介绍二叉堆,二叉堆就是通常我们所说的数据结构中"堆"中的一种.和以往一样,本文会先对二叉堆的理论知识进行简单介绍,然后给出C语言的实现.后续再分别给出C++和Java版本 ...
- 二叉堆(二)之 C++的实现
概要 上一章介绍了堆和二叉堆的基本概念,并通过C语言实现了二叉堆.本章是二叉堆的C++实现. 目录1. 二叉堆的介绍2. 二叉堆的图文解析3. 二叉堆的C++实现(完整源码)4. 二叉堆的C++测试程 ...
- 【nodejs原理&源码杂记(8)】Timer模块与基于二叉堆的定时器
目录 一.概述 二. 数据结构 2.1 链表 2.2 二叉堆 三. 从setTimeout理解Timer模块源码 3.1 timers.js中的定义 3.2 Timeout类定义 3.3 active ...
- 数据结构图文解析之:二叉堆详解及C++模板实现
0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...
- 在A*寻路中使用二叉堆
接上篇:A*寻路初探 GameDev.net 在A*寻路中使用二叉堆 作者:Patrick Lester(2003年4月11日更新) 译者:Panic 2005年3月28日 译者序 这一篇文章,是&q ...
- poj 3253 初涉二叉堆 模板题
这道题很久以前就做过了 当时是百度学习了优先队列 后来发现其实还有个用sort的办法 就是默认sort排序后 a[i]+=a[i-1] 然后sort(a+i,a+i+n) (大概可以这样...答案忘了 ...
- PHP利用二叉堆实现TopK-算法的方法详解
前言 在以往工作或者面试的时候常会碰到一个问题,如何实现海量TopN,就是在一个非常大的结果集里面快速找到最大的前10或前100个数,同时要保证 内存和速度的效率,我们可能第一个想法就是利用排序,然后 ...
随机推荐
- 【VS开发】Return与Exit的区别
1. exit用于结束正在运行的整个程序,它将参数返回给OS,把控制权交给操作系统:而return 是退出当前函数,返回函数值,把控制权交给调用函数. 2. exit是系统调用级别,它表示一个进程的结 ...
- Django soft-delete软删除
在django中,实现这个功能很简单,我们采用一个字段用来保存删除的时间.若记录没有被删除,那么设置该值为None,如果被删除,那么设置时间为删除的时间. class BaseSchema(model ...
- Vue(一)环境搭建、创建项目
1.安装node和npm 因为node已经有npm,所以直接安装node,配置环境变量 官网地址:http://nodejs.cn/download/ 2.查看node是否安装成功,输入名nde -v ...
- servlet获取checkbox的值出现选中的值为on。问题所在。。。
<form action="/Http/request06" method="post"> 用户名:<input type="tex ...
- 操作MySQL数据进行记录的随意排序
说到排序,想必大家都知道MySQL中的“ORDER BY”这个关键词吧,使用它可以实现查询数据根据某一字段(或多个字段)的值排序,那么如何实现数据的任意排序操作呢? 其实这里我所说的“随意排序”,本质 ...
- JVM学习(一)Java虚拟机运行时数据区域
一.Java内存区域 1.运行时数据区域 根据<Java 虚拟机规范(Java SE 7 版)>规定,Java 虚拟机所管理的内存包括以下几个运行时数据区域: 1.1 程序计数器 程序计数 ...
- [DEBUG] spring boot在eclipse中用maven打包成jar访问templates报500错误
更新:打war包的话只要把html文件放在resources/templates下即可,根本不需要放外面. 配置application.yml和templates放外面这种做法,打war包确实不行. ...
- 利用Python进行数据分析_Numpy_基础_1
ndarray:多维数组 ndarray 每个数组元素必须是相同类型,每个数组都有shape和dtype对象. shape 表示数组大小 dtype 表示数组数据类型 array 如何创建一个数组? ...
- C库函数:scanf、fscanf、printf、fprintf、sprintf、 snprintf
1. scanf 函数原型 int scanf(const char *format, ...); 功能:从标准输入 stdin 读取格式化输入. 2.fscanf 函数原型 int fscanf( ...
- 代理模式与动态代理之JDK实现和CGlib实现
静态代理 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类. 由业务实现类.业务代理类 两部分组成.业务实现类 负责实现主要的业务方法,业务代理类负责对调用的业务方法作拦截.过滤.预处理, ...