二叉查找树 Java实现
定义:
一棵二叉查找树是一棵二叉树,每个节点都含有一个Comparable的键(以及对应的值)。
每个节点的键都大于左子树中任意节点的键而小于右子树中任意节点的键。
树的术语:
Name | Function |
---|---|
路径 | 顺着连接点的边从一个节点走向另一个节点,所经过的节点的顺序排列就称为路径。 |
根 | 树顶端的节点就称为根,一棵树只有一个根,如果要把一个节点和边的集合定义为树,那么从根到其他任何一个节点都必须有一条路径。 |
父节点 | 每个节点(除了根)都恰好有一条边向上连接到另一个节点,上面的节点就称为下面节点的“父节点”。 |
子节点 | 每个节点都可能有一条或多条边向下连接其他节点,下面的这些节点就称为它的“子节点”。 |
叶节点 | 没有子节点的节点称为“叶子节点”或简称“叶节点”。树只能有一个根,但是可以有很多叶节点。 |
子树 | 每个节点都可以作为子树的根,它和它所有的子节点,子节点的子节点等都含在子树中。 |
访问 | 当程序控制流程到达某个节点的时候,就称为“访问”这个节点,通常是为了在这个节点处执行某种操作,例如查看节点某个数据字段的值或者显示节点。 |
遍历 | 遍历树意味着要遵循某种特定的顺序访问树中的所有节点。 |
层 | 一个节点的层数是指从根开始到这个节点有多少“代”。 |
关键字 | 可以看到,对象中通常会有一个数据域被指定为关键字值。这个值通常用于查询或者其他操作。 |
二叉树 | 如果树中的每个节点最多只能有两个子节点,这样的树就称为“二叉树”。 |
性质:
- 若它的左子树不为空,则左子树上的所有节点的值都小于它的根节点的值;
- 若它的右子树不为空,则右子树上所有节点的值都大于它的根节点的值;
- 其他的左右子树也分别为二叉查找树;
- 二叉查找树是动态查找表,在查找的过程中可见添加和删除相应的元素,在这些操作中需要保持二叉查找树的以上性质。
根据其二叉树的特性,节点类如下:
public class Node {
public int index;//关键字段
public String data;//值
public Node leftNode;//左节点
public Node rightNode;//右节点
@Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
}
其中引用了commons-lang3包中的内容,作为对象进行比较
查找某个节点,相当于二分查找,如果小于当前节点,则走左边,如果大于当前节点,则走右边。当最后叶子节点还没有找到,则没有找到
public Node findNode(int key){
Node current = root;
while(current.index != key){
if(key < current.index){//左节点
current = current.leftNode;
}else{//右节点
current = current.rightNode;
}
if(current == null){
return null;
}
}
return current;
}
插入节点,按照插入的节点都不会出现重复关键字。每一次插入都将变为根节点的子节点,例如根节点关键字为1,接下来插入的节点则变为根节点的右子节点。
public void insertNode(int key,String value){
Node node = new Node();
node.index = key;
node.data = value;
if(root == null){
root = node;
return;
}
//找到插入节点的位置
Node parent = root;
Node current = root;
while(true){
parent = current;
if(key == current.index){
return;
}
if(key < current.index){//左节点
current = current.leftNode;
if(current == null){//当前节点已经是叶子结点了
parent.leftNode = node;
return;
}
}else{
current = current.rightNode;
if(current == null){
parent.rightNode = node;
return;
}
}
}
}
遍历节点,中序遍历.
- 调用自身来遍历节点的左子树
- 访问这个节点
- 掉用自身来遍历节点的右子树
public void inOrder(Node localRoot) {
if (localRoot != null) {
inOrder(localRoot.leftNode);
System.out.println("索引:" + localRoot.index + ",值:" + localRoot.data);
inOrder(localRoot.rightNode);
}
}
删除节点,分三种情况:
- 删除节点没有子节点,那么将父节点的左节点或者是右节点设置为空
- 删除节点只有一个子节点,删除该节点后,该节点的子节点变为父节点的子节点,如果删除节点时父节点的左节点,那么父节点的左节点指向该节点的子节点,反之则右节点指向删除节点的子节点。
- 删除节点有两个字节点,删除了该节点后,则需要选择一个后继节点,并且还不破坏该二叉树的特性(左节点要小于右节点),一般是从删除节点的右节点中找到一个后继节点,而这个节点是右子树的最小值。
public boolean delete(int key) {
Node current = root;
Node parent = root;
boolean isLeftChild = true;
//找到被删除的节点,并标识该节点是否为左节点
while (current.index != key) {
parent = current;
if (key < current.index) {
isLeftChild = true;
current = current.leftNode;
} else {
isLeftChild = false;
current = current.rightNode;
}
if (current == null) {
return false;
}
}
//第一种情况,删除节点为子节点
if (current.leftNode == null && current.rightNode == null) {
if (current == root) {
root = null;
} else {
if (isLeftChild) {
parent.leftNode = null;
} else {
parent.rightNode = null;
}
}
} else if ((current.leftNode != null && current.rightNode == null) || (current.leftNode == null && current.rightNode != null)) {
//第二中情况,删除节点只包含一个子节点,则将子节点移动动当前节点中
if (current.rightNode == null) {//删除的节点的左节点有值,右节点为空
if (root == current) {
root = current.leftNode;
} else {
if (isLeftChild) {
parent.leftNode = current.leftNode;
} else {
parent.rightNode = current.leftNode;
}
}
} else {//删除的节点的右节点有值,左节点为空
if (root == current) {
root = current.rightNode;
} else {
if (isLeftChild) {
parent.leftNode = current.rightNode;
} else {
parent.rightNode = current.rightNode;
}
}
}
} else if (current.leftNode != null && current.rightNode != null) {
//第三种情况,删除节点中有左右两个节点
//找到后继节点
Node processer = processer(current);
if (current == root) {//删除是根节点,则
root = processer;
} else {
if (isLeftChild) {
parent.leftNode = processer;
} else {
parent.rightNode = processer;
}
}
//选中的节点的左节点与删除节点的左节点相连
processer.leftNode = current.leftNode;
}
return true;
}
//找到后继节点
private Node processer(Node delNode) {
Node parent = delNode;
Node success = delNode;
Node current = delNode.rightNode;
while (current != null) {
// 后继节点父节点首先保存后继节点的状态
parent = current;
success = current;
// 后继节点 不断的向左更新
current = current.leftNode;
}
// 假如我们找到的后继节点不直接是 要删除节点的右节点 而是在其右节点那条子树上面最小的一个节点
if (success != delNode.rightNode) {
//后继节点的父节点断开其与后继节点左边的引用,重新连接上后继节点的右子节点(因为后继节点是没有左子节点的,锁以要保存之前树的状态,还要把后继节点的右子节点处理一下,不管 其存在不存在)
parent.leftNode = success.rightNode;
// 这时候后继节点的右边已经空了 上一条语句已经将其给了自己父节点的左子节点 然后让后继节点的右边 连接要删除节点的右子树
success.rightNode = delNode.rightNode;
}
return success;
}
二叉查找树 Java实现的更多相关文章
- 数据结构实现(四)二叉查找树java实现
转载 http://www.cnblogs.com/CherishFX/p/4625382.html 二叉查找树的定义: 二叉查找树或者是一颗空树,或者是一颗具有以下特性的非空二叉树: 1. 若左子树 ...
- 递归的二叉查找树Java实现
package practice; public class TestMain { public static void main(String[] args) { int[] ao = {50,18 ...
- 二叉查找树--java
package com.test.tree; public class BinarySearchTree<T extends Comparable<? super T>> { ...
- LeetCode96_Unique Binary Search Trees(求1到n这些节点能够组成多少种不同的二叉查找树) Java题解
题目: Given n, how many structurally unique BST's (binary search trees) that store values 1...n? For e ...
- Spark案例分析
一.需求:计算网页访问量前三名 import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} /* ...
- 数据结构笔记--二叉查找树概述以及java代码实现
一些概念: 二叉查找树的重要性质:对于树中的每一个节点X,它的左子树任一节点的值均小于X,右子树上任意节点的值均大于X. 二叉查找树是java的TreeSet和TreeMap类实现的基础. 由于树的递 ...
- Java for LintCode 验证二叉查找树
给定一个二叉树,判断它是否是合法的二叉查找树(BST) 一棵BST定义为: 节点的左子树中的值要严格小于该节点的值. 节点的右子树中的值要严格大于该节点的值. 左右子树也必须是二叉查找树. ...
- 二叉查找树的Java实现
为了克服对树结构编程的恐惧感,决心自己实现一遍二叉查找树,以便掌握关于树结构编程的一些技巧和方法.以下是基本思路: [1] 关于容器与封装.封装,是一种非常重要的系统设计思想:无论是面向过程的函数,还 ...
- 二叉查找树(三)之 Java的实现
概要 在前面分别介绍了"二叉查找树的相关理论知识,然后给出了二叉查找树的C和C++实现版本".这一章写一写二叉查找树的Java实现版本. 目录 1. 二叉树查找树2. 二叉查找树的 ...
随机推荐
- PAT甲 1048. Find Coins (25) 2016-09-09 23:15 29人阅读 评论(0) 收藏
1048. Find Coins (25) 时间限制 50 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Eva loves t ...
- 移动 APP 网络优化概述
一般开发一个 APP,会直接调用系统提供的网络请求接口去服务端请求数据,再针对返回的数据进行一些处理,或者使用AFNetworking/OKHttp这样的网络库,管理好请求线程和队列,再自动做一些数据 ...
- Opengl中的gluProject函数认识
1. 从官方说明如下 https://www.opengl.org/sdk/docs/man2/xhtml/gluProject.xml Name gluProject — map object co ...
- hdu 2058 The sum problem(数学题)
一个数学问题:copy了别人的博客 #include<cstdio> #include<cstdlib> #include<cmath> int main() { ...
- AndroidPn服务端部分bug解决方案
目前推送的情况已经大致可以了,可以正常推送.但是要在实际生产中使用,要改进很多地方. 原本的版本,是不会对消息重新发送的.消息如果丢失,或者用户没有在线,消息也不会重新的发送.所以,这些问题都是要解决 ...
- 敏捷项目管理架构(APMF)
研读许秀影博士的<敏捷项目管理:基础知识与应用实务>一书,其中提到传统项目管理与敏捷项目管理的混合管理模式—敏捷项目管理架构(Agile Project Management Framew ...
- TSQL--查找连续登陆用户
--========================================== 需求:有一个用户登陆日志表,记录用户每次登陆时间,然后想查找用户按天连续登陆的情况,找出每次连续登陆的最早时间 ...
- 哎呀,我艹,使用tfs时候,离职人员锁定了代码.
哎呀,我艹,使用tfs时候,离职人员锁定了代码. 而且离职人员电脑已经回收,被格式化了,怎么破? 不管别人是有意,还是无意,总之就是需要搞定了. 1.第一步 首先,找到被锁住的工作区一般在报错信息中可 ...
- 廖雪峰Python学习笔记——类和实例
Class MyList(list): __metaclass__ = ListMetaclass #它表示在创建MyList这个类时,必须通过 ListMetaclass这个元类的LIstMetac ...
- Android Studio - Unable to create Debug Bridge: Unable to start adb server: adb server version (32) doesn't match this client (40)
错误提示:Unable to create Debug Bridge: Unable to start adb server: adb server version (32) doesn't matc ...