博客园博主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的实现的质疑的更多相关文章

  1. 二叉堆(三)之 Java的实现

    概要 前面分别通过C和C++实现了二叉堆,本章给出二叉堆的Java版本.还是那句话,它们的原理一样,择其一了解即可. 目录1. 二叉堆的介绍2. 二叉堆的图文解析3. 二叉堆的Java实现(完整源码) ...

  2. 二项堆(三)之 Java的实现

    概要 前面分别通过C和C++实现了二项堆,本章给出二项堆的Java版本.还是那句老话,三种实现的原理一样,择其一了解即可. 目录1. 二项树的介绍2. 二项堆的介绍3. 二项堆的基本操作4. 二项堆的 ...

  3. 二叉堆(一)之 图文解析 和 C语言的实现

    概要 本章介绍二叉堆,二叉堆就是通常我们所说的数据结构中"堆"中的一种.和以往一样,本文会先对二叉堆的理论知识进行简单介绍,然后给出C语言的实现.后续再分别给出C++和Java版本 ...

  4. 二叉堆(二)之 C++的实现

    概要 上一章介绍了堆和二叉堆的基本概念,并通过C语言实现了二叉堆.本章是二叉堆的C++实现. 目录1. 二叉堆的介绍2. 二叉堆的图文解析3. 二叉堆的C++实现(完整源码)4. 二叉堆的C++测试程 ...

  5. 【nodejs原理&源码杂记(8)】Timer模块与基于二叉堆的定时器

    目录 一.概述 二. 数据结构 2.1 链表 2.2 二叉堆 三. 从setTimeout理解Timer模块源码 3.1 timers.js中的定义 3.2 Timeout类定义 3.3 active ...

  6. 数据结构图文解析之:二叉堆详解及C++模板实现

    0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...

  7. 在A*寻路中使用二叉堆

    接上篇:A*寻路初探 GameDev.net 在A*寻路中使用二叉堆 作者:Patrick Lester(2003年4月11日更新) 译者:Panic 2005年3月28日 译者序 这一篇文章,是&q ...

  8. poj 3253 初涉二叉堆 模板题

    这道题很久以前就做过了 当时是百度学习了优先队列 后来发现其实还有个用sort的办法 就是默认sort排序后 a[i]+=a[i-1] 然后sort(a+i,a+i+n) (大概可以这样...答案忘了 ...

  9. PHP利用二叉堆实现TopK-算法的方法详解

    前言 在以往工作或者面试的时候常会碰到一个问题,如何实现海量TopN,就是在一个非常大的结果集里面快速找到最大的前10或前100个数,同时要保证 内存和速度的效率,我们可能第一个想法就是利用排序,然后 ...

随机推荐

  1. 【VS开发】fopen 文本文件与二进制文件区别

    在学习C语言文件操作后,我们都会知道打开文件的函数是fopen,也知道它的第二个参数是 标志字符串.其中,如果字符串中出现'b',则表明是以打开二进制(binary)文件,否则是打开文本文件. 那么什 ...

  2. 实现base标签中有绝对路径

    1.首先在jsp页面中写一段神奇的JAVA代码 <% String path = request.getContextPath(); String basePath = request.getS ...

  3. visualgdb 调试arm

    目录 visualgdb 调试arm 没有ssh的开发板使用telnet 使用telent的gdbserver title: visualgdb 调试arm date: 2019/11/19 10:0 ...

  4. Linux下运行《UNIX环境高级编程》undefined reference to `err_quit 编译出错的处理方法

    错误信息: : undefined reference to `err_quit': undefined reference to `err_sys' 解决方法: 因为err_quit跟err_sys ...

  5. UWP笔记-使用FFmpeg编解码

    在开发UWP媒体应用的时候,使用的MediaElement可以支持主流的格式,不过还是有些格式本地编解码器是不支持的,如.flv..rmvb等,这里讲到的是第三方开源库FFmpeg,可以直接播放更多的 ...

  6. [转帖]windows CIFS sabma协议识

    windows CIFS sabma协议识别 https://www.cnblogs.com/tcicy/p/9992871.html 公司的一个共享服务器就是 win2003的 mount 的时候 ...

  7. python的一些知识点

    1. 内置函数  iter 2. 可迭代对象与迭代器:

  8. Python实现八大排序(基数排序、归并排序、堆排序、简单选择排序、直接插入排序、希尔排序、快速排序、冒泡排序)

    目录 八大排序 基数排序 归并排序 堆排序 简单选择排序 直接插入排序 希尔排序 快速排序 冒泡排序 时间测试 八大排序 大概了解了一下八大排序,发现排序方法的难易程度相差很多,相应的,他们计算同一列 ...

  9. Lua模除运算的大坑

    问题 对负数进行模除运算遇到的坑,Lua的%运算与C++的%有差异 实践 结论 Lua%运算的基本公式 a % b = a - ( ( a // b ) * b ) 1.在C,C++中 %运算符的取整 ...

  10. docker使用的一些需要注意事项

    1.程序需要前台运行 程序必须前台执行,如果是java进程的话  不要有nohup   或者使用service的方式进行后台运行 否则可能会出现频繁启动应用的问题 原因就是docker只能管理运行中的 ...