BinarySearchTreeMap的实现

  

 public interface Map<K extends Comparable<K>, V> {
void put(K k, V v); V get(K k); void delete(K k); boolean contains(K k); boolean isEmpty(); int size(); int size(K lo, K hi); K min(); K max(); K floor(K k); K ceiling(K k); // the number of keys less than key
int rank(K k); K select(int k); void deleteMin(); void deleteMax(); // keys in [lo , hi] in sorted order
Iterable<K> keys(K lo, K hi); Iterable<K> keys();
}

Map Interface


  二叉树的定义

  在计算机科学中,二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用于实现二叉查找树和二叉堆。二叉树的左子节点 <  父节点 < 右子节点

  这是typical的二叉树的样子, null 代表子节点为空,从这张图可以看出,左子节点 9 小于 父节点 10 小于 右子节点 

  

     private class Node<K, V> {
private K k;
private V v;
private Node<K, V> left;
private Node<K, V> right;
private int size;
Node(K k, V v) { this.k = k; this.v = v; }
Node(K k, V v, int size) { this.k = k; this.v = v; this.size = size;}
}

Node(节点)对象

        


   二叉树的插入操作

   假设我们依次插入 10 , 9, 15, 5 , 7 这5个元素到二叉树中。see what will happen 这是个动态图

     @Override
public void put(K k, V v) {
root = put(root, k, v); //root 是根节点
} private Node<K, V> put(Node<K, V> node, K k, V v) {
if (node == null) return new Node<>(k, v, 1);
int cmp = node.k.compareTo(k);
if (cmp > 0) { //node的k大一点 放到左边的数中
node.left = put(node.left, k, v);
} else if (cmp < 0) { //node的k小一点 放到右边的数中
node.right = put(node.right, k, v);
} else node.v = v; node.size = size(node.left) + size(node.right) + 1;
return node;
}

put operation (插入)


  二叉树的get 方法

  get方法简单来说就是要找到那个key相同的对象。比如我们要在「10 , 9, 15, 5 , 7 」上图所示中找到 7

  

  

     @Override
public V get(K k) {
return get(root, k);
} private V get(Node<K, V> node, K k) { if (node == null) return null; //not find
else if (node.k.compareTo(k) > 0) { //node的k大一点 放到左边的数中
return get(node.left, k);
} else if (node.k.compareTo(k) < 0) { //node的k小一点 放到右边的数中
return get(node.right, k);
} else { //equal
return node.v;
} }

get operation

  


  二叉树的删除操作

  其实想象一下,当你删除一个node的时候,你需要找一个替代node来代替这个node。

  这里又分3种情况。首先假设你有如下的树结构

  

  1.第一种情况是这个删除的节点的左右节点都是null。

    比如我要删除3节点。其实只要直接把3节点reset 为null 就可以了。变成如下

  

   2.第二种情况是删除的节点的2个子节点中有一个子节点为null

     比如我要删除15。 15 的左节点是12 右节点是 null,所以符合这个情况

       这个时候只需要直接把需要删除的节点 reset 为 非空的子节点就可以了

所以在这里只需要把15的值替代为12

  

  3.第三种情况是删除的节点的2个子节点都不为null,

    这个时候其实可以有2个选择,一个是把删除的节点替换为右子节点为根节点的那个树中最小的节点

    比如我要删除10, 右节点为15(二叉树的删除操作的那个图,不是上面的那个图),15这个节点为根节点的树中总共有2个元素(15和12),12是最小的。所以把需要删除的节点替换为12。删除后如下

  

    另外一种选择是把左节点为根节点的树中最大的值取出来,把需要删除的那个节点替换为这个左节点最大的元素(2个选择没什么区别)

    

     @Override
public void delete(K k) {
delete(root, k);
}
//delete the k in the node tree and reset the size prorperty of this tree and subtrees to correct value
private Node<K, V> delete(Node<K, V> node, K k) {
if (node == null) return null; //没有找到这个node int cmp = node.k.compareTo(k);
if (cmp > 0) {
node.left = delete(node.left, k);
node.size = size(node.left) + size(node.right) + 1;
return node;
} else if (cmp < 0) {
node.right = delete(node.right, k);
node.size = size(node.left) + size(node.right) + 1;
return node;
} else { //hit the key
if (node.right == null) //if the right node is null then just replace this node with left node
return node.left;
else if (node.left == null) // if the left node is null then just replace this node with right node
return node.right;
else {
return deleteMin(node.right); // if both the subnodes are not null replace this node with the smallest node in the right sub node
}
}
} //删除从参数node开始的最小的node
private Node<K, V> deleteMin(Node<K, V> node) {
return delete(node, min(node));
} private Node<K, V> deleteMax(Node<K, V> node) {
return delete(node, max(node));
} @Override
public void deleteMin() {
deleteMin(root);
} @Override
public void deleteMax() {
deleteMax(root);
} @Override
public K min() {
return min(root);
} //get the smallest node in the given node
private K min(Node<K, V> node) {
if (node == null) return null;
for (; node.left != null; node = node.left);
return node.k;
} @Override
public K max() {
return max(root);
}
//get the most max node in the given node
private K max(Node<K, V> node) {
if (node == null) return null;
for (node = root; node.right != null; node = node.right);
return node.k;
}

delete operation 删除操作


   分析

    BinarySearchTree 有一个最大的缺点,就是如果插入的元素是ordered,比如我插入 1 2 3 4 5  6 这样子,元素都会排在一边。这样子查找起来路径很长,效率很低。

    如果插入的元素是随机的,那么所有的get put 操作的时间复杂度应该是 和 log2(N) 成正比的

    具体的实现可以参考这个。https://github.com/Cheemion/algorithms/blob/master/src/com/algorithms/tree/BinarySearchTreeMap.java

    有什么错误的地方欢迎大家指正哈

    

二叉树终极教程--BinarySearchTree的更多相关文章

  1. Java 日志框架终极教程

    概述 对于现代的 Java 应用程序来说,只要被部署到真实的生产环境,其日志的重要性就是不言而喻的,很难想象没有任何日志记录功能的应用程序被运行于生产环境中.日志 API 所能提供的功能是多种多样的, ...

  2. windows下面安装Python和pip终极教程

    在大二的时候接触过一段时间的Python,最近又开始玩起了这门语言.总的来说,个 人很喜欢Python的语言风格,但是这门语言对于windows并不算很友好,因为如果是初学者在windows环境下安装 ...

  3. 转: windows下面安装Python和pip终极教程

    原文: http://www.cnblogs.com/yuanzm/p/4089856.html 因为如果是初学者在windows环境下安装,简直是折磨人,会遇到各种蛋疼的情况.本文希望提供傻瓜式的教 ...

  4. MongoDB数据库安装及配置环境终极教程(windows10系统)

    本文是笔者花时间踩坑踩生气了写出来的!转载请注明出处@http://www.cnblogs.com/tim100/!请尊重我的劳动成果!谢谢! 今天,给大家说说在windows10系统下MongoDB ...

  5. APK Multi-Tool强大的APK反编译工具终极教程

    一.APK Multi-Tool介绍    APK Multi-Tool 是APK Manager的升级版,是一个强大的APK反编译工具,集多种功能于一身,是居家必备.做ROM必选的工具!    这是 ...

  6. 终极教程【zhong】

    just for a better future! 资源教程               aiim                   综合类 前端知识体系 前端知识结构 Web前端开发大系概览 We ...

  7. 2020年B2B外贸建站的终极教程

    本文目标:按照本建站教程的顺序操作,能够实现:基于全球份额最大的建站系统“wordpress”,从零搭建一个B2B外贸网站,且建站成本每年小于1000元(如果不计算自己投入的人力成本的话). 模板站点 ...

  8. Docker + Jenkins + Gitlab + Pytest + Allure 接口自动化测试之持续集成实战终极教程

    实战教程篇 前言 这边就不教大家怎么用 pytest 写项目了哦,下面有系列文章能帮助你快速入门 Pytest + Allure 这一篇教程主要是教如何从 0 到 1 搭建自动化测试的持续集成环境 后 ...

  9. Dreamweaver架设网站终极教程

    转自:http://www.cnblogs.com/loveme513/archive/2006/04/03/365969.html 一.定义站点 1. 在任意一个根目录下创建好一个文件夹(我们这里假 ...

随机推荐

  1. Shrio授权验证详解

    所谓授权,就是控制你是否能访问某个资源,比如说,你可以方位page文件夹下的jsp页面,但是不可以访问page文件夹下的admin文件夹下的jsp页面. 在授权中,有三个核心元素:权限,角色,用户. ...

  2. WeQuant交易策略—简单均线

    简单双均线策略(Simple Moving Average) 策略介绍简单双均线策略,通过一短一长(一快一慢)两个回看时间窗口收盘价的简单移动平均绘制两条均线,利用均线的交叉来跟踪价格的趋势.这里说的 ...

  3. WebGL开发入门

    ­­­Getting started with WebGL development WebGL开发入门 What is Unity WebGL? 什么是Unity WebGL? The WebGL b ...

  4. Akka(22): Stream:实时操控:动态管道连接-MergeHub,BroadcastHub and PartitionHub

    在现实中我们会经常遇到这样的场景:有一个固定的数据源Source,我们希望按照程序运行状态来接驳任意数量的下游接收方subscriber.又或者我需要在程序运行时(runtime)把多个数据流向某个固 ...

  5. Java温故而知新-插入排序

    插入排序 插入排序的基本思想是将待排序的元素依次插入序列合适的位置,然后将这个位置后面的元素依次向后移动一位 位置1 2 3 4 5 6 序列5 4 2 1 8 3 设第1位为最初始的基础元素,也就是 ...

  6. [2014-09-18]Entity Framework 6 预热、启动优化

    好久没写博客了,终于憋出了一个大招,现在总结下. 虽然文章题目是针对EF的,但涉及的内容不仅仅是EF. 场景介绍 目前在做的一个项目,行业门户,项目部分站点按域名划分如下: user.xxx.com: ...

  7. 公司python入职培训流程

     时间分为4周,全部自学,仅提供大纲.适用于Web方向:1.Week1:读完<简明Python教程>,适应Python开发环境2.Week2:写个爬虫,需要深入了解re.urllib2.s ...

  8. C# 异步编程1 APM模式异步程序开发

    C#已有10多年历史,单从微软2年一版的更新进度来看活力异常旺盛,C#中的异步编程也经历了多个版本的演化,从今天起着手写一个系列博文,记录一下C#中的异步编程的发展历程.广告一下:喜欢我文章的朋友,请 ...

  9. js学习--变量作用域和作用域链

    作为一名菜鸟的我,每天学点的感觉还是不错的.今天学习闭包的过程中看到作用域与作用域链这两个概念,我觉得作为一名有追求的小白,有必要详细了解下. 变量的作用域 就js变量而言,有全局变量和局部变量.这里 ...

  10. SEO搜索引擎优化(一)

    什么是SEO呢 英文为"Search Engine Optimization",中文名为"搜索引擎优化".SEO是指通过对网站进行站内优化和修复(网站Web结构 ...