二叉查找树的实现

1. 原理

  二叉查找树,又称为二叉排序树、二叉搜索树。对于树中每一个节点X,它的左子树中所有项的值小于X中的项,而它的右子树中所有项的值大于X中的项。二叉查找树的平均深度为O(log N),搜索元素的时间复杂度也是O(log N)。是两种库集合类TreeSet、TreeMap实现的基础。

2. public API

void makeEmpty( )      --> 置空
boolean isEmpty( )     --> 判空
AnyType findMin( )     --> 寻找最小值
AnyType findMax( )     --> 寻找最大值
boolean contains( x ) --> 是否存在元素x
void insert( x )       --> 插入元素x
void remove( x )       --> 删除元素x
void printTree( )     --> 遍历二叉树

3. 核心思想图解:递归

!寻找最小值

此处用递归实现:

!寻找最大值

此处用非递归实现,也可以用递归实现:

!是否存在元素x

从root开始往下找,找到含有项X的节点,则此操作返回true,没有找到则返回false。

!插入元素x

从root开始往下找到合适的插入位置,然后插入。

!删除元素x

从root开始往下找到元素x,找到则删除,并且处理好后续工作。

4. BinarySearchTree代码实现

类中,大量使用方法来调用递归方法的技巧,很好地体现了面向对象的封装性。
 /**
* @author: wenhx
* @date: Created in 2019/10/8 19:41 (之前)
* @description: 二叉查找树的实现
*/
public class BinarySearchTree<AnyType extends Comparable<? super AnyType>> {

/**
* 树的根节点
*/
private BinaryNode<AnyType> root;

/**
* 定义树的节点(内部类)
*/
private static class BinaryNode<AnyType> {

AnyType element; // 元素值
BinaryNode<AnyType> left; // 左孩子
BinaryNode<AnyType> right; // 右孩子

// 节点的构造器:初始化一个树的节点
BinaryNode(AnyType theElement) {
this(theElement, null, null);
}

BinaryNode(AnyType theElement, BinaryNode<AnyType> lt, BinaryNode<AnyType> rt) {
element = theElement;
left = lt;
right = rt;
}
}

/**
* 二叉排序树的构造器:初始化根节点
*/
public BinarySearchTree() {
root = null;
}

/**
* 置空
*/
public void makeEmpty() {
root = null;
}

/**
* 判空
*/
public boolean isEmpty() {
return root == null;
}

/**
* 寻找最小值
*/
public AnyType findMin() {
if (isEmpty()) {
throw new RuntimeException();
}
return findMin(root).element;
}

/**
* 寻找最大值
*/
public AnyType findMax() {
if (isEmpty()) {
throw new RuntimeException();
}
return findMax(root).element;
}


/**
* 是否存在元素x
*/
public boolean contains(AnyType x) {
return contains(x, root);
}

/**
* 插入元素x
*/
public void insert(AnyType x) {
root = insert(x, root);
}

/**
* 删除元素x
*/
public void remove(AnyType x) {
root = remove(x, root);
}

/**
* 遍历此二叉树
*/
public void printTree() {
if (isEmpty()) {
System.out.println("Empty tree");
} else {
printTree(root);
}
}

/**
* 寻找最小值(内部方法):此处用递归实现
*/
private BinaryNode<AnyType> findMin(BinaryNode<AnyType> t) {
if (t == null) {
return null;
} else if (t.left == null) {
return t;
}
return findMin(t.left);
}

/**
* 寻找最大值(内部方法):此处用非递归实现
*/
private BinaryNode<AnyType> findMax(BinaryNode<AnyType> t) {
if (t != null) {
while (t.right != null) {
t = t.right;
}
}
return t;
}

/**
* 是否存在元素x(内部方法)
*/
private boolean contains(AnyType x, BinaryNode<AnyType> t) {
/**
* 跳出递归的条件
*/
if (t == null) {
return false;
}

/**
* 如果x小于节点值,则递归到左孩子;
* 如果x大于节点值,则递归到右孩子;
* 如果x等于节点值,则找到。
*/
int compareResult = x.compareTo(t.element);

if (compareResult < 0) {
return contains(x, t.left);
} else if (compareResult > 0) {
return contains(x, t.right);
} else {
return true;
}

}

/**
* 插入元素x(内部方法)
*/
private BinaryNode<AnyType> insert(AnyType x, BinaryNode<AnyType> t) {
/**
* 跳出递归的条件
*/
if (t == null) {
return new BinaryNode<>(x, null, null);
}

/**
* 如果x小于节点值,则递归到左孩子;
* 如果x大于节点值,则递归到右孩子;
* 如果x等于节点值,则说明已有元素x,无需操作。
*/
int compareResult = x.compareTo(t.element);

if (compareResult < 0) {
t.left = insert(x, t.left);
} else if (compareResult > 0) {
t.right = insert(x, t.right);
} else {
}
return t;

}

/**
* 删除元素x(内部方法)
*/
private BinaryNode<AnyType> remove(AnyType x, BinaryNode<AnyType> t) {
/**
* 跳出递归的条件
*/
if (t == null) {
return t; // Item not found; do nothing
}

/**
* 如果x小于节点值,则递归到左孩子;
* 如果x大于节点值,则递归到右孩子;
* 如果x等于节点值,则要删除此节点。
*/
int compareResult = x.compareTo(t.element);

if (compareResult < 0) {
t.left = remove(x, t.left);
} else if (compareResult > 0) {
t.right = remove(x, t.right);
} else if (t.left != null && t.right != null) {
// 要删除的节点有两个孩子(可选用右孩子最小元素/左孩子最大元素上调)
t.element = findMin(t.right).element;
t.right = remove(t.element, t.right);
} else {
// 要删除的节点有一个孩子或者没有孩子
t = (t.left != null) ? t.left : t.right;
}
return t;
}

/**
* 遍历此二叉树(内部方法)
*/
private void printTree(BinaryNode<AnyType> t) {
// 中序遍历-->即递增顺序
if (t != null) {
printTree(t.left);
System.out.println(t.element);
printTree(t.right);
}
}

/**
* 求树的深度(内部方法)
*/
private int height(BinaryNode<AnyType> t) {
if (t == null) {
return -1;
} else {
return 1 + Math.max(height(t.left), height(t.right));
}
}

/**
* 主方法用来测试
*/
public static void main(String[] args) {
BinarySearchTree<Integer> t = new BinarySearchTree<>();
t.insert(6);
t.insert(3);
t.insert(9);
t.insert(2);
t.insert(5);
t.insert(8);
t.insert(10);
t.printTree();
t.insert(4);
}
}

okay,今天就到这啦,一定要掌握这种数据结构哈,真的很重要!!!

用Java实现二叉查找树的更多相关文章

  1. 数据结构:JAVA实现二叉查找树

    数据结构:JAVA实现二叉查找树 写在前面 二叉查找树(搜索树)是一种能将链表插入的灵活性与有序数组查找的高效性结合在一起的一种数据结构. 观察二叉查找树,我们发现任何一个节点大于左子节点且小于其右子 ...

  2. Java实现二叉查找树

    摘要:一个二叉查找树的Java实现.可以学习二叉树处理的递归及非递归技巧. 难度:初级. 为了克服对树结构编程的恐惧感,决心自己实现一遍二叉查找树,以便掌握关于树结构编程的一些技巧和方法.以下是基本思 ...

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

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

  4. 使用java实现二叉查找树的插入,修改和删除方法

    目前使用的是根据key的hashcode来进行排序,并且没有考虑hash碰撞的问题 package com.zhou.tree; import java.util.Comparator; import ...

  5. 二叉查找树(三)之 Java的实现

    概要 在前面分别介绍了"二叉查找树的相关理论知识,然后给出了二叉查找树的C和C++实现版本".这一章写一写二叉查找树的Java实现版本. 目录 1. 二叉树查找树2. 二叉查找树的 ...

  6. 红黑树(五)之 Java的实现

    概要 前面分别介绍红黑树的理论知识.红黑树的C语言和C++的实现.本章介绍红黑树的Java实现,若读者对红黑树的理论知识不熟悉,建立先学习红黑树的理论知识,再来学习本章.还是那句老话,红黑树的C/C+ ...

  7. Java数据结构和算法(四)赫夫曼树

    Java数据结构和算法(四)赫夫曼树 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 赫夫曼树又称为最优二叉树,赫夫曼树的一个 ...

  8. Java数据结构和算法(二)树的基本操作

    Java数据结构和算法(二)树的基本操作 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 一.树的遍历 二叉树遍历分为:前序遍 ...

  9. 红黑树 Java实现

    概要 前面分别介绍红黑树的理论知识.红黑树的C语言和C++的实现.本章介绍红黑树的Java实现,若读者对红黑树的理论知识不熟悉,建立先学习红黑树的理论知识,再来学习本章.还是那句老话,红黑树的C/C+ ...

随机推荐

  1. 获取IP的三种方法

    第一种 取本主机ip地址 public string GetLocalIp() { ///获取本地的IP地址 string AddressIP = string.Empty; foreach (IPA ...

  2. (day69)axios、配置ElementUI、配置jQuery和Bootstrap、Django中的CORS问题

    目录 一.Vue的ajax插件:axios 二.Django中的CORS跨域问题 (一)同源策略 (二)解决方式(cors模块) 三.Vue配置ElementUI 四.Vue配置jQuery和Boot ...

  3. SpringBoot 构建 REST 服务

    摘要 该文章只为了说明如何整合REST服务,并不介绍如何使用,当做笔记吧. MongoDB 以MongoDB为例 maven 依赖 <dependency> <groupId> ...

  4. Egg 企业级应用开发框架的搭建

    在之前的文章中我们介绍了一下基于 nodejs 开发的 koa2 框架,在之前还有 espress 框架,接下来我们再学习一个 Egg.js. Egg.js 中文官网:https://eggjs.or ...

  5. Ruby中星号打包解包操作

    Ruby中可以使用一个星号*和两个星号**完成一些打包.解包操作,它们称为splat操作符: 一个星号:以数组为依据进行打包解包(参考文章) 两个星号:以hash为依据进行打包解包(参考文章) 两个星 ...

  6. maven仓库之第二篇

    1. 什么是maven? 它是一个软件开发的管理工具,主要管理的工作是:依赖管理,项目构建. 2. 使用maven的好处? 能够集中管理jar包,提供一键构建. 3. maven的安装及配置 配置:M ...

  7. PostgreSQL update set from 两表联合更新,注意与其它数据库更新语法有差别

    最近用PostgreSql数据库进行表关联更新时,发现与之前用的Sql Server 和My Sql语法有很大差别,稍微不注意,很容易出错. PostgreSql表更新时,两个表只允许一个表起别名,一 ...

  8. ES6变量的解构赋值(一)数组的解构赋值

    let[a,...arr]=[1,2,3,4];//a==>1 arr==>[2,3,4] let [x, y, ...z] = ['a'];//a==>'a' y==>und ...

  9. 记录Android开发中遇到的坑

    1. 出现错误提示:Intel HAXM is required to run this AVD,VT-x is disabled in BIOS的解决办法. 点击SDK图标,安装Intel x86 ...

  10. 【Nginx】安装&环境配置

    安装依赖包 安装make:yum -y install gcc automake autoconf libtool make 安装g++:yum -y install gcc gcc-c++ 安装pc ...