最近终于静下心来,自己实现了个二叉排序树,还是很有成就感的。

package tree;

public class TreeNode {

//结点存放的数据

public T data;

//当前结点的父结点

public TreeNode parent;

//当前结点的左孩子

public TreeNode leftChild;

//当前结点的右孩子

public TreeNode rightChild;

public TreeNode(T data,TreeNode parent)

{

this.data = data;

this.leftChild = null;

this.rightChild = null;

this.parent = parent;

}

}

package tree;

/**

* 二叉排序树或者是一棵空树, 或者是一棵具有如下性质的二叉树

* (1)、若左子树不空,则左子树上所有结点的值均小于它的根结点的值;

* (2)、若右子树不空,则右子树上所有结点的值均大于它的根结点的值;

* (3)、左、右子树也分别为二叉排序树;

*/

//二叉排序树的结构通常不是一次生成的,而是在查找过程中动态构建的;

public class BinarySortTree>

{

//根结点指针

public TreeNode rootNode = null;

//二叉树的结点个数

public int nodeCount = 0;

//获取targetData在二叉排序树中对应的结点指针

public TreeNode find(T targetData)

{

TreeNode curNode = this.rootNode;

while (curNode != null)

{

T curNodeData = curNode.data;

if(curNodeData.compareTo(targetData) == 0)

{

return curNode;

}

else if(curNodeData.compareTo(targetData) > 0)

{

curNode = curNode.leftChild;

}

else

{

curNode = curNode.rightChild;

}

}

return null;

}

public TreeNode add(T targetData)

{

TreeNode targetNode= find(targetData);

//已经存在,不用再插入新结点

if(targetNode != null)

{

return targetNode;

}

//没有根结点,需要创建一个根结点,存放数据targetData

if(this.rootNode == null)

{

this.rootNode = new TreeNode(targetData, null);

this.nodeCount = 1;

return this.rootNode;

}

//已经存在根节点的情况,但是没有对应targetData的结点

TreeNode insertPos = findInsertPos(targetData);

TreeNode tempNode = new TreeNode(targetData, insertPos);

this.nodeCount++;

if(targetData.compareTo(insertPos.data) > 0 )

{

insertPos.rightChild = tempNode;

}

else

{

insertPos.leftChild = tempNode;

}

return tempNode;

}

public void delete(T targetData)

{

TreeNode tagNode = find(targetData);

//不存在,直接返回

if( tagNode == null)

{

return;

}

//要删除的结点是叶子结点

if(tagNode.leftChild == null && tagNode.rightChild == null)

{

deleteWhenLeaf(tagNode);

}

//要删除的结点只有左子树,或只有右子树

else if(tagNode.leftChild == null || tagNode.rightChild == null)

{

deleteWhenSingleChild(tagNode);

}

else

{

deleteWhenTwoChild(tagNode);

}

}

//删去叶子结点不破坏整棵树的结构,只需修改其父结点的孩子指针

private void deleteWhenLeaf(TreeNode tagNode)

{

this.nodeCount--;

TreeNode parent = tagNode.parent;

//要删除的是根结点

if(parent == null)

{

this.rootNode = null;

}

else

{

if(parent.leftChild == tagNode)

{

parent.leftChild = null;

}

else

{

parent.rightChild = null;

}

}

}

//若p结点只有左子树PL或右子树PR,此时只要令PL或PR直接成为其双亲结点f的左子树(当*p是左子树)

//或右子树(当*p是右子树)即可

private void deleteWhenSingleChild(TreeNode tagNode)

{

this.nodeCount--;

//当前结点的父亲

TreeNode parent = tagNode.parent;

//当前结点的左孩子

TreeNode left = tagNode.leftChild;

//当前结点的右孩子

TreeNode right = tagNode.rightChild;

if(left != null)

{

left.parent = parent;

}

else

{

right.parent = parent;

}

//要删除的是根结点

if(parent == null)

{

if(left != null)

{

this.rootNode = left;

}

else

{

this.rootNode = right;

}

}

else//删除的结点不是根结点

{

if(left != null)

{

parent.leftChild = left;

}

else

{

parent.rightChild = right;

}

}

}

//tagNode结点的后继结点肯定无左子树;前驱结点肯定没有右子树;

//由于tagNode既有左孩子,又有右孩子,所以前驱和后继都不可能是null

//假如tagNode的前驱是before,则用before代替tagNode位置;

//before的左子树代替before的位置

private void deleteWhenTwoChild(TreeNode tagetNode)

{

this.nodeCount--;

//tagetNode的前驱结点是before

TreeNode before = searchPredecessor(tagetNode);

//1.before的左子树取代结点before的位置

if(before.parent.leftChild == before)

{

before.parent.leftChild = before.leftChild;

}

else

{

before.parent.rightChild = before.leftChild;

}

if(before.leftChild != null)

{

before.leftChild.parent = before.parent;

}

//2.before取代tagetNode的位置

before.parent = tagetNode.parent;

before.leftChild = tagetNode.leftChild;

before.rightChild = tagetNode.rightChild;

//3.改变tagetNode的父结点的孩子指针

if(tagetNode.parent == null)

{

this.rootNode = before;

}

else

{

if(tagetNode.parent.leftChild == tagetNode)

{

tagetNode.parent.leftChild = before;

}

else

{

tagetNode.parent.rightChild = before;

}

}

}

//获取targetData在二叉排序中插入位置

//如果targetData在二叉树中已经存在,则不需要再插入,返回null

public TreeNode findInsertPos(T targetData)

{

//将要插入的位置

TreeNode willInsert = null;

TreeNode curNode = this.rootNode;

while (curNode != null)

{

T curNodeData = curNode.data;

//结点已经存在,插入位置设为null

if(curNodeData.compareTo(targetData) == 0)

{

willInsert = null;

break;

}

else if(curNodeData.compareTo(targetData) >0)

{

willInsert = curNode;

curNode = curNode.leftChild;

}

else

{

willInsert = curNode;

curNode = curNode.rightChild;

}

}

return willInsert;

}

//二叉排序树的中序遍历,查找tagetNode结点的后继结点

//如果没有后继结点,则返回null;

public TreeNode searchSuccessor(TreeNode tagetNode)

{

if(tagetNode == null)

{

return null;

}

//从右子树中寻找后继结点

if(tagetNode.rightChild != null)

{

return searchMinValueNode(tagetNode.rightChild);

}

//从父节点向上寻找后继

else

{

//根结点没有右子树,就没有后继结点

if(tagetNode.parent == null)

{

return null;

}

else

{

TreeNode temp = tagetNode;

while (temp.parent != null)

{

if(temp.parent.leftChild == temp)

{

break;

}

temp = temp.parent;

}

return temp.parent;

}

}

}

//查找某个结点的前驱,如果没有前驱结点,则返回null

public TreeNode searchPredecessor(TreeNode tagetNode)

{

if(tagetNode == null)

{

return null;

}

if(tagetNode.leftChild != null)

{

return searchMaxValueNode(tagetNode.leftChild);

}

else

{

//根结点没有左子树,就没有前驱结点

if(tagetNode.parent == null)

{

return null;

}

else

{

TreeNode temp = tagetNode;

while (temp.parent != null)

{

if(temp.parent.rightChild == temp)

{

break;

}

temp = temp.parent;

}

return temp.parent;

}

}

}

//查找以root为根结点的二叉排序树中,最小的数据值对应的结点

public TreeNode searchMinValueNode(TreeNode root)

{

if(root == null)

{

return null;

}

TreeNode resultNode = root;

while (resultNode.leftChild != null)

{

resultNode = resultNode.leftChild;

}

return resultNode;

}

//查找以root为根结点的二叉排序树中,最大的数据值对应的结点

public TreeNode searchMaxValueNode(TreeNode root)

{

if(root == null)

{

return null;

}

TreeNode resultNode = root;

while (resultNode.rightChild != null)

{

resultNode = resultNode.rightChild;

}

return resultNode;

}

public void inorderTraversal(TreeNode node)

{

if(node == null)

{

return;

}

inorderTraversal(node.leftChild);

System.out.println(node.data);

inorderTraversal(node.rightChild);

}

}

java 二叉排序_java实现二叉排序树相关推荐

  1. 二叉排序树查找的c语言程序,C语言二叉排序(搜索)树实例

    本文实例为大家分享了C语言二叉排序(搜索)树实例代码,供大家参考,具体内容如下 /**1.实现了递归 非递归插入(创建)二叉排序(搜索)树: 分别对应Insert_BinSNode(TBinSNode ...

  2. 掉一根头发,搞定二叉排序(搜索)树

    文章已收录在 数据结构与算法学习仓库 前言 前面介绍学习的大多是线性表相关的内容,把指针搞懂后其实也没有什么难度,规则相对是简单的,后面会讲解一些比较常见的数据结构,用多图的方式让大家更容易吸收. 在 ...

  3. 数据结构与算法—二叉排序(查找)树

    目录 前言 树 二叉树 二叉排序(搜索)树 概念 构造 主要方法 findmax(),findmin() isContains(int x) insert(int x) delete(int x) 完 ...

  4. java二叉查找算法_Java手写二叉搜索树算法

    package com.zyizou.basis.demo.tree; /** * 手写二叉搜索树的逻辑 * * @author zibin */ public class BinarySearchT ...

  5. C语言——查找(折半、分块、二叉排序、哈希法)

    前言 本篇主要介绍查找概念及各类查找方法. 看完本篇,你将了解到: 1.查找问题概述(查找表可进行的操作.时间开销.一些计算方法) 2.顺序表的查找(存储方式.算法时间性能) 3.折半查找(可递归可迭 ...

  6. java 二叉堆_二叉堆(三)之 Java的实现

    概要 前面分别通过C和C++实现了二叉堆,本章给出二叉堆的Java版本.还是那句话,它们的原理一样,择其一了解即可. 二叉堆的介绍 二叉堆是完全二元树或者是近似完全二元树,按照数据的排列方式可以分为两 ...

  7. [剑指offer]面试题第[68-2]题[Leetcode][第236题][JAVA][二叉搜索树的最近公共祖先][递归]

    [问题描述][中等] 235/68-1 搜索二叉树 236/68-2 二叉树 [解答思路] 递归 时间复杂度:O(N) 空间复杂度:O(N) 情况 1. , 2. , 3. , 4. 的展开写法如下. ...

  8. java二次排序_使用java 实现二次排序

    二次排序工具类: import java.io.Serializable; import scala.math.Ordered; /** * @author 作者 E-mail: * @version ...

  9. Java二叉搜索树转循环链表,关于java:二叉搜索树转换为单向链表interview1712

    题目形容 二叉树数据结构TreeNode可用来示意单向链表(其中left置空,right为下一个链表节点).实现一个办法,把二叉搜寻树转换为单向链表,要求仍然合乎二叉搜寻树的性质,转换操作应是旧址的, ...

最新文章

  1. R语言ggplot2可视化:ggplot2可视化水平堆叠条形图、并且在每个堆叠条形图的内部居中添加百分比文本标签信息
  2. String构造方法和字符集编码转换
  3. SQL server与Oracle触发器的创建与使用
  4. 【自动化测试】Python 读取 .ini 格式文件
  5. ABAP中怎样获取随机数
  6. mongodb服务部署
  7. PHP从零开始--数据库
  8. 关于C语言野指针的问题
  9. 将一个16进制数转化为10进制数
  10. java对mysql的简单操作——增加数据
  11. 常见RPM,YUM,DNF指令
  12. python tornado 工程范例
  13. 网站后台发通知页面效果图
  14. SQL语句中AND OR运算符优先级
  15. Mac工具PullTube如何在下载列表中创建重复项
  16. ip纯真数据库查询国家省市名称
  17. 实训4——RFID刷卡开锁
  18. python27是什么文件夹可以删除吗_python如何跳过错误继续运行,同时删除产生错误的文档...
  19. css 里面写响应式布局,CSS3怎么做出响应式布局
  20. 塞班s60v3手电筒sisx_塞班s60v3闪光灯手电筒软件可以发给我吗?谢谢!

热门文章

  1. linux 如何自定义安装路径,Linux下安装mysql并自定义数据的存储路径
  2. memcached简单的使用教程
  3. pygame小游戏(接球小游戏)
  4. 命令行开启一个unity实例和执行其中的脚本方法的使用和注意
  5. 项目管理工具project软件学习(一) - 项目信息设置
  6. (七)准备在云中训练深度伪造模型
  7. NLTK自然语言处理简介
  8. 自清洁集合和自清洁事件
  9. MsSql.RestApi - 构建ASP.NET REST API的最简单方法
  10. odoo10参考系列--视图三(其他高级视图)