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. Leetcode题目49.字母异位词分组(中等)

    题目描述: 给定一个字符串数组,将字母异位词组合在一起.字母异位词指字母相同,但排列不同的字符串. 示例: 输入: ["eat", "tea", "t ...

  3. iOS (APP)进程间8中常用通信方式总结

    1 URL Scheme 2 Keychain 3 UIPasteboard 4 UIDocumentInteractionController 5 local socket 6 AirDrop 7 ...

  4. Qt子窗口QMidSubwindow全屏出现的问题总结

    我的需求:想全屏一个子窗口QMidSubwindow,禁止显示最大化最小化和关闭按钮. 我开始尝试的是网上介绍的方法,把结果展现给大家一下,最后再总结: 方法1:QMidSubwindow直接调用sh ...

  5. Linux 查看网卡速率及版本

    查看网卡速率:ethtool 网卡名  如ethtool eth0 查看网卡驱动版本号:ethtool -i 网卡名   如ethtool -i eth0 示例: [root@nt3 ~]# etht ...

  6. 前端知识点回顾——Javascript篇(六)

    fetch 在原生ajax+es6promise的基础上封装的一个语法糖,返回promise对象. fetch(url, initObj) .then(res=>res.json()) .the ...

  7. kubernetes介绍(1)

    一.Kubernetes 介绍: kubernetes起源 Kubernetes (K8s) 是 Google 在 2014 年发布的一个开源项目. 据说 Google 的数据中心里运行着超过 20 ...

  8. Performance Analysis of Logs (PAL) Tool

    Performance Analysis of Logs (PAL) Tool 背景 在众多的独立项目中,我们如何快速了解数据库(SQL Server)服务器的性能,以及数据库的基线情况是怎样的,或者 ...

  9. 自动化部署 jenkins 插件简介

    一.什么是持续集成? (1)Continuous integration(CI) 持续集成是一种软件开发实践,即团队开发成员经常集成他们的工作,通常每个成员至少集成一次,也就意味着每天可能会发生多次集 ...

  10. java中,有关移位运算符的有关讨论

    java中有三种移位运算符 <<      :     左移运算符,num << 1,相当于num乘以2 >>      :     右移运算符,num >& ...