1,Node.java

生成基础二叉树的结构

 package com.cnblogs.mufasa.searchTree;

 /**
* 节点配置父+左+右
*/
public class Node{
Node parent;
Node leftChild;
Node rightChild;
int val;
public Node(Node parent, Node leftChild, Node rightChild,int val) {
super();
this.parent = parent;
this.leftChild = leftChild;
this.rightChild = rightChild;
this.val = val;
} public Node(int val){
this(null,null,null,val);
} public Node(Node node,int val){
this(node,null,null,val);
}
}

图1 Node.java结构

2,SearchBinaryTree.java

在原有二叉树的结构上,进行搜索二叉树的功能扩充:

①数据增加:递归版本插入、迭代版本

②数据删除:

③数据查找:

④数据遍历:前中后

 package com.cnblogs.mufasa.searchTree;

 public class SearchBinaryTree {

     private Node root;
private int size;
public SearchBinaryTree() {
super();
} /**
* 增加节点
* @param val
* @return
*/
public boolean add(int val) {
if(root == null){//初始节点为空
root = new Node(val);
size++;
return true;
}
//初始节点不为空
Node node = getAdapterNode(root, val);
Node newNode = new Node(val);
if(node.val > val){
node.leftChild = newNode;
newNode.parent = node;
}else if(node.val < val){
node.rightChild = newNode;
newNode.parent = node;
}else{
return false;//增加数据和搜索二叉树中原有数据相同不符合基本限定条件
}
size++;
return true;
} /**
* 获取最合适的插入节点
* @param node
* @param val
* @return
*/
private Node getAdapterNode(Node node,int val){
//该节点为空
if(node == null){
return node;
} // 往左子树中插入,但没左子树,则返回
if(node.val > val && node.leftChild == null){
return node;
} // 往右子树中插入,但没右子树,也返回
if(node.val < val && node.rightChild == null){
return node;
} // 该节点是叶子节点,则返回
if(node.leftChild == null && node.rightChild == null){
return node;
} //节点可以继续向下,直接递归调用
if(node.val > val && node.leftChild != null){
return getAdapterNode(node.leftChild, val);
}else if(node.val < val && node.rightChild != null){
return getAdapterNode(node.rightChild, val);
}else{
return node;
}
} /**
* 进行迭代增加元素
* @param val
* @return
*/
public boolean put(int val){
return putVal(root,val);
} /**
*直接循环搜索目标节点进行数据增加
* @param node
* @param val
* @return
*/
private boolean putVal(Node node,int val){
if(node == null){// 初始化根节点
node = new Node(val);
root = node;
size++;
return true;
}
//节点非空
Node temp = node;
Node p;
int t;
/**
* 通过do while循环迭代获取最佳节点,
*/
do{
p = temp;
t = temp.val-val;
if(t > 0){
temp = temp.leftChild;
}else if(t < 0){
temp = temp.rightChild;
}else{
temp.val = val;//增加数据和搜索二叉树中原有数据相同不符合基本限定条件
return false;
}
}while(temp != null); Node newNode = new Node(p, val);
if(t > 0){
p.leftChild = newNode;
}else if(t < 0){
p.rightChild = newNode;
}
size++;
return true;
} /**
* 节点删除
* @param val
* @return
*/
public boolean delete(int val){
Node node = getNode(val);
if(node == null){//没有该节点
return false;
}
Node parent = node.parent;
Node leftChild = node.leftChild;
Node rightChild = node.rightChild; //以下所有子节点为空的情况,则表明删除的节点是【叶节点】
if(leftChild == null && rightChild == null){//没有子节点
if(parent != null){
if(parent.leftChild == node){
parent.leftChild = null;
}else if(parent.rightChild == node){
parent.rightChild = null;
}
}else{//不存在父节点,则表明删除节点为【根节点】,直接返回空
root = null;
}
node = null;
return true; }else if(leftChild == null && rightChild != null){// 只有右节点
if(parent != null && parent.val > val){// 存在父节点,且node位置为父节点的左边
parent.leftChild = rightChild;
}else if(parent != null && parent.val < val){// 存在父节点,且node位置为父节点的右边
parent.rightChild = rightChild;
}else{//父节点不存在!!!
root = rightChild;
}
node = null;
return true; }else if(leftChild != null && rightChild == null){// 只有左节点
if(parent != null && parent.val > val){// 存在父节点,且node位置为父节点的左边
parent.leftChild = leftChild;
}else if(parent != null && parent.val < val){// 存在父节点,且node位置为父节点的右边
parent.rightChild = leftChild;
}else{//父节点不存在!!!
root = leftChild;
}
node = null;
return true; }else if(leftChild != null && rightChild != null){// 两个子节点都存在,相当于直接替换节点
Node successor = getSuccessor(node);// 这种情况,一定存在后继节点
int temp = successor.val;
boolean delete = delete(temp);
if(delete){
node.val = temp;
}
successor = null;
return true;
}
return false;
} /**
*
* @param node
* @return
*/
private Node getSuccessor(Node node){
if(node.rightChild != null){//肯定不为空
Node rightChild = node.rightChild;
while(rightChild.leftChild != null){//不断的向左转向搜索数值
rightChild = rightChild.leftChild;
}
return rightChild;
}
//右节点为空这个不存在啊!!!
Node parent = node.parent;
while(parent != null && (node == parent.rightChild)){
node = parent;
parent = parent.parent;
}
return parent;
} /**
* 搜索节点
* @param val
* @return
*/
public Node getNode(int val){
Node temp = root;
int t;
do{//直接使用循环遍历的方法
t = temp.val-val;
if(t > 0){
temp = temp.leftChild;
}else if(t < 0){
temp = temp.rightChild;
}else{
return temp;
}
}while(temp != null);
return null;
} /**
* 节点删除
* @param val
* @return
*/
public boolean remove(int val){
Node node = getNode(val);
if(node == null){
return false;
} if(node.leftChild == null){// 1、左节点不存在,右节点可能存在,包含两种情况 ,两个节点都不存在和只存在右节点
transplant(node, node.rightChild);
}else if(node.rightChild == null){//2、左孩子存在,右节点不存在
transplant(node, node.leftChild);
}else{// 3、两个节点都存在
Node successor = getSuccessor(node);// 得到node后继节点
if(successor.parent != node){// 后继节点存在node的右子树中。
transplant(successor, successor.rightChild);// 用后继节点的右子节点替换该后继节点
successor.rightChild = node.rightChild;// 将node节点的右子树赋给后继节点的右节点,即类似后继与node节点调换位置
successor.rightChild.parent = successor;// 接着上一步 给接过来的右节点的父引用复制
}
transplant(node, successor);
successor.leftChild = node.leftChild;
successor.leftChild.parent = successor;
}
return true;
}
/**
* 将child节点替换node节点
* @param node 要删除的节点
* @param child node节点的子节点
*/
private void transplant(Node node,Node child){
/**
* 1、先判断 node是否存在父节点
* 1、不存在,则child替换为根节点
* 2、存在,则继续下一步
* 2、判断node节点是父节点的那个孩子(即判断出 node是右节点还是左节点),
* 得出结果后,将child节点替换node节点 ,即若node节点是左节点 则child替换后 也为左节点,否则为右节点
* 3、将node节点的父节点置为child节点的父节点
*/ if(node.parent == null){
this.root = child;
}else if(node.parent.leftChild == node){
node.parent.leftChild = child;
}else if(node.parent.rightChild == node){
node.parent.rightChild = child;
}
if(child != null){
child.parent = node.parent;
}
} public void print(int type){//方法的重载
if(type==0){//前序
printPre(root);
}else if(type==1){
printMid(root);
}else if(type==2){
printEnd(root);
}
} private void printPre(Node root){//前序遍历
if(root != null){
System.out.println(root.val);// 位置在中间,则中序,若在前面,则为先序,否则为后续
printPre(root.leftChild);
printPre(root.rightChild);
}
} private void printMid(Node root){//中序遍历
if(root != null){
printMid(root.leftChild);
System.out.println(root.val);// 位置在中间,则中序,若在前面,则为先序,否则为后续
printMid(root.rightChild);
}
} private void printEnd(Node root){//后序遍历
if(root != null){
printEnd(root.leftChild);
printEnd(root.rightChild);
System.out.println(root.val);// 位置在中间,则中序,若在前面,则为先序,否则为后续
}
} }

图2 SearchBinaryTree.java结构

3,JavaDemo.java

 package com.cnblogs.mufasa.searchTree;

 public class JavaDemo {
public static void main(String[] args) {
SearchBinaryTree tree=new SearchBinaryTree();
tree.add(5);
tree.add(1);
tree.add(100);
tree.add(50);
tree.add(22);
tree.add(48);
tree.print(2);
}
}

4,特别鸣谢

https://www.cnblogs.com/qm-article/p/9279655.html

数据结构-二叉搜索树Java实现的更多相关文章

  1. Java数据结构——二叉搜索树

    定义二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若 ...

  2. 二叉搜索树Java实现(查找、插入、删除、遍历)

    由于最近想要阅读下 JDK1.8 中 HashMap 的具体实现,但是由于 HashMap 的实现中用到了红黑树,所以我觉得有必要先复习下红黑树的相关知识,所以写下这篇随笔备忘,有不对的地方请指出- ...

  3. 二叉搜索树(Java实现)

    二叉搜索树基本操作 求树中的结点个数 判断节点是否为空 向树中插入新结点key-value 树中是否存在key 返回树中key对应的value值 先序遍历 中序遍历 后续遍历 层序遍历 求树中key最 ...

  4. 数据结构-二叉搜索树(BST binary search tree)

    本文由@呆代待殆原创,转载请注明出处:http://www.cnblogs.com/coffeeSS/ 二叉搜索树简介 顾名思义,二叉搜索树是以一棵二叉树来组织的,这样的一棵树可以用一个链表数据结构来 ...

  5. 数据结构-二叉搜索树的js实现

    一.树的相关概念 1.基本概念 子树 一个子树由一个节点和它的后代构成. 节点的度 节点所拥有的子树的个数. 树的度 树中各节点度的最大值 节点的深度 节点的深度等于祖先节点的数量 树的高度 树的高度 ...

  6. 数据结构☞二叉搜索树BST

    二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它可以是一棵空树,也可以是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它 ...

  7. 基本数据结构 —— 二叉搜索树(C++实现)

    目录 什么是二叉搜索树 二叉搜索树如何储存数值 二叉搜索树的操作 插入一个数值 查询是否包含某个数值 删除某个数值 测试代码 参考资料 什么是二叉搜索树 二叉搜索树(英语:Binary Search ...

  8. leetcode- 将有序数组转换为二叉搜索树(java)

    将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. 示例: 给定有序数组: [-10,-3,0, ...

  9. 数据结构---二叉搜索树BST实现

    1. 二叉查找树 二叉查找树(Binary Search Tree),也称为二叉搜索树.有序二叉树(ordered binary tree)或排序二叉树(sorted binary tree),是指一 ...

随机推荐

  1. CISCO实验记录三:CDP邻居发现

    一.CDP邻居发现要求 1.识别二层连接 2.识别CDP邻居 二.CDP邻居发现操作 1.CDP邻居发现 #interface gigabitEthernet 0/0/0 //启动端口 #no shu ...

  2. Netfilter 之 iptable_filter

    概述 本文主要对filter表的初始化流程,以及钩子函数的规则match流程的源码进行分析: 源码分析 所在钩子点: /* 在LOCAL_IN,FORWARD, LOCAL_OUT钩子点工作 */ # ...

  3. android data binding jetpack VII @BindingAdapter

    android data binding jetpack VIII BindingConversion android data binding jetpack VII @BindingAdapter ...

  4. Elasticsearch的安装入门

    大纲: 一.简介 二.Logstash 三.Redis 四.Elasticsearch 五.Kinaba 一.简介 1.核心组成 ELK由Elasticsearch.Logstash和Kibana三部 ...

  5. openstack基于卷快照恢复卷

    openstack基于卷快照恢复卷 基于P版本,对卷基于快照进行恢复的源码分析 1.特性描述 在pike版本中,openstack官网增加了一个新特性,Cinder volume revert to ...

  6. 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-5.HttpClient4.x工具获取使用

    笔记 5.HttpClient4.x工具获取使用     简介:讲解httpClient4.x相关依赖,并封装基本方法. 1.加入依赖         <dependency>       ...

  7. 一百零五:CMS系统之flask-mail使用和邮箱配置、发送邮件功能

    安装:pip install flask-mail 官方文档:https://pythonhosted.org/Flask-Mail/ 邮箱配置 MAIL_SERVER = 'smtp.qq.com' ...

  8. Ubuntu配置zsh

    安装zsh sudo apt-get install zsh chsh -s /bin/zsh 配置 curl -L https://raw.github.com/robbyrussell/oh-my ...

  9. 微信小程序开发-框架

    小程序开发框架的目标是通过尽可能简单.高效的方式让开发者可以在微信中开发具有原生 APP 体验的服务.框架提供了自己的视图层描述语言 WXML 和 WXSS,以及基于 JavaScript 的逻辑层框 ...

  10. 数据测试001:利用python连接数据库插入excel数据

    数据测试001:利用python连接数据库插入excel数据 最近在做数据测试,主要是做报表系统,需要往数据库插入数据验证服务逻辑,本次介绍如何利用python脚本插入Oracle和Mysql库中: ...