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. 【sed】基本用法

    1. 文本处理 sed编辑器根据sed命令处理数据流中的数据:在流编辑器将所有命令与一行数据匹配完后,它会读取下一行数据并重复以下过程: (1) 一次从输入中读取一行数据 (2) 根据所提供的编辑器命 ...

  2. XGBoost原理简介

    XGBoost是GBDT的改进和重要实现,主要在于: 提出稀疏感知(sparsity-aware)算法. 加权分位数快速近似学习算法. 缓存访问模式,数据压缩和分片上的实现上的改进. 加入了Shrin ...

  3. arcgis 面或线要素类上的搜索游标

    import arcpy infc = arcpy.GetParameterAsText(0) # Identify the geometry field # desc = arcpy.Describ ...

  4. ios-Runtime调用私有方法

    有时在代码中会有需要调用私有方法的场景,如不想import太多头文件:想组件设计一些解耦的模块:查看别人模块中未暴露的代码进行分析等. 在 ios 中调用私有方法有很多种方式,主要是通过Runtime ...

  5. 重画GoogleClusterTrace数据

    由于项目计划书写作需要,重画了Qi Zhang, Mohamed Faten Zhani, Raouf Boutaba, Joseph L. Hellerstein, Dynamic Heteroge ...

  6. 抓包工具Fiddler使用

    1.参考博客 https://blog.csdn.net/ychgyyn/article/details/82154433 https://www.cnblogs.com/miantest/p/728 ...

  7. Python安装以及简单使用教程

    以windows版本举例: 1.首先去Pycharm官网,或者直接输入网址:http://www.jetbrains.com/pycharm/download/#section=windows,下载P ...

  8. chrome调试笔记

    F12启动调试 1.右键加载按钮可以清空缓存并重新加载,有时候浏览器有缓存,代码更新不会及时反映出来. 2.performance mointer实时查看performance 点击三个竖着的小点,选 ...

  9. RabbitMQ学习之:(六)Direct Exchange (转贴+我的评论)

    From: http://lostechies.com/derekgreer/2012/04/02/rabbitmq-for-windows-direct-exchanges/ RabbitMQ fo ...

  10. *Scala API - 并发编程