二叉查找树的实现

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. 设置fiddler抓取安卓手机的包

    1.在手机端设置代理,IP地址为fiddler所在电脑IP,端口默认8888 2.在fiddler上打开工具-设置-连接,勾选允许远程计算机连接,点击确定 3.安装证:手机浏览器输入 http://( ...

  2. jquery dialog的一些坑

    jquery dialog工具可以方便的生成一个弹出框,但是在一些需要多个弹出框的应用场景上会有一些bug 具体场景: 当使用过一次模态框之后,使用另外的一个模态框时,已经消失不见的模态框会重新出来 ...

  3. Python Django 支付宝 扫码支付

    安装python-alipay-sdk pip install python-alipay-sdk --upgradepip install crypto 如果是python 2.7安装0.6.4这个 ...

  4. 关于中医的一段对话 [ZZ] -- 思维训练故事

    转载自新浪博客 网址: http://blog.sina.cn/dpool/blog/s/blog_9880df4201015khq.html?type=-1 关于中医的一段对话 2013-01-26 ...

  5. 关于使用宏将csv批量转换成xls的分享

    最近在使用遇到一个问题需要把csv格式的文件转成xls,随便新建一个excel,然后打开,选择“开发工具”,找到下图“宏”,如果跟下图一样的话就需要先启用宏,启用之后可以直接把下面的代码直接复制到代码 ...

  6. Python 周刊第 418 期

    新闻 PyCon US 2020 开始接受财务赞助! https://pycon.blogspot.com/2019/10/financial-aid-launches-for-pycon-us-20 ...

  7. JS-时间相关的函数封装

    1.用JS把时间戳转换为时间,代码如下: //时间戳转换为时间 function timestampToTime(timestamp) { var date = new Date(timestamp) ...

  8. C++入门到理解阶段二基础篇(7)——C++函数

    目录 函数作用 函数定义 函数声明 函数调用 函数值传递 函数常见的样式 函数的分文件书写 函数作用 将经常使用的代码封装起来,减少重复代码 函数定义 C++ 中的函数定义的一般形式如下: retur ...

  9. sql server报【将截断字符串或二进制数据】错误

    会出现这个错误的原因是因为表设置的列长度小于要插入的数据的长度. 可以从下列的6个方面去排查: 1.表设置的列名长度太短. 2.插入的数据太长. 3.有默认值. 4.有触发器. 5 从char数据类型 ...

  10. Cypress 之 常用API

    .visit() 访问一个远程URL.>>详情参考 Cypress 之 cy.visit() cy.visit(url) cy.visit(url, options) cy.visit(o ...