第四章习题:二叉查找树类实现懒惰删除,注意findMin()和findMax()(递归)

  算是发布的第一篇学习笔记。也不敢保证写的代码一定正确,错了的地方请大家指正,谢谢。

  直接开始吧。先谈谈数据结构,二叉查找树懒惰删除较于一般的二叉查找树,多了一些域:theSize(剩下的节点数)、deletedSize(懒惰删除的节点数)、BinaryNode<AnyType> min,max(用于保留在findMin和findMax方法中递归查询到的flag!=1的最值点);在内部节点类中,多了一个byte型的flag变量(=1则表示被删除)。在这里,也可以使用一个count域,这在有重复项时很常用,初始的count都是1,以后有插入就+1,有删除且count>0就-1.我使用的直接是flag标志变量。

 class myLazyBinarySearchTree<AnyType extends Comparable<? super AnyType>> {
   private BinaryNode<AnyType> root;
private int theSize;// 总节点数
private int deletedSize;// 懒惰删除的节点数
private BinaryNode<AnyType> min = null;
private BinaryNode<AnyType> max = null;   public myLazyBinarySearchTree() {
root = null;
this.deletedSize = 0;
this.theSize = 0;
}   public boolean isEmpty() {
return theSize - deletedSize == 0;
}
}

  其中contains()比较简单,在递归查找中找到后再查看一下节点的flag变量即可;insert例程也一样,如果有是已存在元素,查看其flag变量是否=1。

  下面是比较麻烦的remove()方法,实现方法和之前的LinkedList一样,先是递归删除,未找到直接return,找到了先将节点flag=1,改变theSize和deletedSize,然后比较theSize和deletedSize的值(懒惰删除的数目>=剩下的节点数目),进行标准删除。标准删除从root开始。

  在标准删除中,如果节点不需要删除,直接检查其左右子树。如果检测到需要删除的节点,再检测①若只存在左子树或者右子树,则将子树拼接上来,重新检测该位置节点。②若是叶子节点,直接置Null删除。③若有左子树也右子树,则同理先将右子树找到一个最小的且flag=0的子树,这里又分为两种情况,若右子树不存在这样一个最小节点,则直接将该右子树置null,并重新检测该节点,若找到了则调整标志等。删除实现如下:

 public void remove(AnyType x) {
remove(x, root);// 这里递归删除只能使用void在下面的remove的else中,t随着变化,而懒惰删除中,只有theSize<=deletedSize才变化,所以t时钟指向的root.造成错误。 } private void remove(AnyType x, BinaryNode<AnyType> t) {
if (t == null) {
// 未找到
return;
} int compareResult = x.compareTo(t.element);
if (compareResult < 0) {
remove(x, t.left);
} else if (compareResult > 0) {
remove(x, t.right);
} else {
// 找到了这个节点,标记删除
t.flag = 1;
this.theSize--;
this.deletedSize++;
checkDeletion();// 检测是否进行标准删除
System.out.println("root1:" + this.root.right);
}
} private void checkDeletion() {
if (this.theSize <= this.deletedSize) {
this.root = doRemove(root);
// 更新节点
this.deletedSize = 0;
}
} private BinaryNode<AnyType> doRemove(BinaryNode<AnyType> t) {// 删除树中所有flag=1的节点。使用递归 if (t == null) {
return null;
} if (t.flag == 0) {// 不需要删除的节点,直接进入左右子树
//System.out.println("000");
t.left = doRemove(t.left);
t.right = doRemove(t.right);
} else {
if (t.left == null || t.right == null) {// 叶子节点或者只有一个子树
t = (t.left != null) ? t.left : t.right;
t = doRemove(t);// 检查拼接上来的子树
} else {// ②左右子树都存在
min = null;
findMin(t.right);
if (min == null) {// 右子树上所有节点都被懒惰删除,直接将t的右子树删除,并继续监测t
t.right = null;
t = doRemove(t);
} else {
t.element = min.element;
t.flag = 0;
min.flag = 1;
t = doRemove(t);
} }
}
return t;
}

  在删除需要查找右子树中最小数值节点且其flag=0,即是未被删除的最小节点。在这儿可以参考二叉树中序遍历的实现,可以利用栈后进先出的特点。为了简明易懂,我使用的是递归查找,并使用了一个前面定义的全局变量进行存储最小元。

 private void findMin(BinaryNode<AnyType> t) {
if (t != null) {
findMin(t.left);
if (t.flag == 0 && min == null) {
min = t;
return;
}
findMin(t.right);
}
}

  查找最大值方法类似。在删除的过程中,每次选择右子树最小元素来代替被删除的元素容易造成树的不平衡性(见P91),因而可以考虑进行随机删除,即随机算则右子树的最小元素或者左子树的最大元素,来消除树的偏向。

二叉查找树的懒惰删除(lazy deletion)的更多相关文章

  1. 【Weiss】【第03章】练习3.17:懒惰删除

    [练习3.17] 不同于我们已经给出的删除方法,另一种是使用懒惰删除的方法. 为了删除一个元素,我们只标记上该元素被删除的信息(使用一个附加的位域). 表中被删除和非被删除的元素个数作为数据结构的一部 ...

  2. 二叉查找树(查找、插入、删除)——C语言

    二叉查找树 二叉查找树(BST:Binary Search Tree)是一种特殊的二叉树,它改善了二叉树节点查找的效率.二叉查找树有以下性质: (1)若左子树不空,则左子树上所有节点的值均小于它的根节 ...

  3. 深入浅出数据结构C语言版(12)——平衡二叉查找树之AVL树

    在上一篇博文中我们提到了,如果对普通二叉查找树进行随机的插入.删除,很可能导致树的严重不平衡 所以这一次,我们就来介绍一种最老的.可以实现左右子树"平衡效果"的树(或者说算法),即 ...

  4. JAVA数据结构--二叉查找树

    二叉查找树定义 二叉查找树(英语:Binary Search Tree),也称二叉搜索树.有序二叉树(英语:ordered binary tree),排序二叉树(英语:sorted binary tr ...

  5. 数据结构--Avl树的创建,插入的递归版本和非递归版本,删除等操作

    AVL树本质上还是一棵二叉搜索树,它的特点是: 1.本身首先是一棵二叉搜索树.   2.带有平衡条件:每个结点的左右子树的高度之差的绝对值最多为1(空树的高度为-1).   也就是说,AVL树,本质上 ...

  6. java:数据结构(四)二叉查找树以及树的三种遍历

    @TOC 二叉树模型 二叉树是树的一种应用,一个节点可以有两个孩子:左孩子,右孩子,并且除了根节点以外每个节点都有一个父节点.当然这种简单的二叉树不能解决让树保持平衡状态,例如你一直往树的左边添加元素 ...

  7. 常见基本数据结构——树,二叉树,二叉查找树,AVL树

    常见数据结构——树 处理大量的数据时,链表的线性时间太慢了,不宜使用.在树的数据结构中,其大部分的运行时间平均为O(logN).并且通过对树结构的修改,我们能够保证它的最坏情形下上述的时间界. 树的定 ...

  8. 二叉查找树的Java实现

    为了克服对树结构编程的恐惧感,决心自己实现一遍二叉查找树,以便掌握关于树结构编程的一些技巧和方法.以下是基本思路: [1] 关于容器与封装.封装,是一种非常重要的系统设计思想:无论是面向过程的函数,还 ...

  9. 【查找结构 2】二叉查找树 [BST]

    当所有的静态查找结构添加和删除一个数据的时候,整个结构都需要重建.这对于常常需要在查找过程中动态改变数据而言,是灾难性的.因此人们就必须去寻找高效的动态查找结构,我们在这讨论一个非常常用的动态查找树— ...

随机推荐

  1. BI之SSAS完整实战教程2 -- 开发环境介绍及多维数据集数据源准备

    上一篇我们已经完成所有的准备工作,现在我们就开始动手,通过接下来的三篇文章创建第一个多维数据集. 传统的维度和多维数据集设计方法主要是基于现有的单源数据集. 在现实世界中,当开发商业智能应用程序时,很 ...

  2. Python调用C的SDK出现返回值不符合预期以及Segmentation fault

    1.sdk返回值不是int型 1.1 登录函数调用 def login(ip, port, username, password, device_info, error_code):"&qu ...

  3. Python基础(二),Day2

    常用的数据类型 int 整型 float 浮点 bool 布尔 string 字符串 列表的语法和用法 # 创建一个列表 list = [] #一个空列表 list = ['2323123','asd ...

  4. 每一个成功的程序员的身后都有一个--------Parse

    相信好多同行都用过Parse,而正是因为Parse给我们的开发带来的极大的便利,才有了项目从零开始,到正式上线仅仅用上不到两周的时间,现在Swift还在迅速的发展,很快就会占有大量的市场,现在就就结合 ...

  5. [Xamarin.Android] 自定义控件

    [Xamarin.Android] 自定义控件 前言 软件项目开发的过程中,免不了遇到一些无法使用内建控件就能满足的客户需求,例如:时速表.折线图...等等.这时开发人员可以透过自定义控件的方式,为项 ...

  6. ASP.NET MVC的请求生命周期

    我希望能理解在浏览器输入URL并敲击回车来请求一个ASP.NET MVC网站的页面之后发生的任何事情. 为什么需要关心这些?有两个原因.首先是因为ASP.NET MVC是一个扩展性非常强的框架.例如, ...

  7. 参加:白帽子活动-赠三星(SAMSUNG) PRO....

    参加:白帽子活动-—赠三星(SAMSUNG) PRO.... Everybody~小i在这里提前祝大家国庆假期愉快,咱们期待已久的国庆活动终于开始拉,下面进入正题,恩,很正的题! 活动地址:http: ...

  8. R语言学习笔记:绘制地图

    在R中画地图先从简单的maps包开始. library("maps") 在这个maps包中有一些数据集,用命令data(package=”maps”),可以看到如下数据: cana ...

  9. Python基础(5)--字典

    字典由多个键及与其对应的值构成的对组成(把键值对成为项),每个键和它的值之间用冒号(:)隔开,项之间用逗号(,)隔开,而整个字典由一对大括号括起来.空字典由两个大括号组成:{} 本文地址:http:/ ...

  10. C++函数模板

    函数模板提供了一种函数行为,该函数行为可以用多种不同的类型进行调用,也就是说,函数模板代表一个函数家族,这些函数的元素是未定的,在使用的时候被参数化. 本文地址:http://www.cnblogs. ...