java二叉搜索树原理与实现

计算机里面的数据结构 树 在计算机存储领域应用作用非常大,我之前也多次强调多磁盘的存取速度是目前计算机飞速发展的一大障碍,计算机革命性的的下一次飞跃就是看硬盘有没有质的飞跃,为什么这么说?因为磁盘是永久性存储设备(在相当长的时间内都可以用),就这一点虽然内存在性能方面优势巨大但是保存信息和数据还是要靠磁盘。
数最成功的要数B+tree和LSM-tree了,在关系型数据库和非关系型数据库(Nosql)可谓是处于主导地位,RocksDB目前在nosql和newsql中都大放光彩,其存储引擎就是LSM-tree,还有hbase,levelDB等。作为树的变种在存储领域不断突破性能的瓶颈。

/**
* 二叉树的节点
* @author www.mojxtang.website
*
*/
public class Node {
/**
* 关键字/索引(识别数据用)
*/
private int id;
/**
* 数据项(可以是任意对象T,也可以表示多个数据项)
*/
private int data;
private Node leftChild;
private Node rightChild;
public Node(int id, int data) {
super();
this.id = id;
this.data = data;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public Node getLeftChild() {
return leftChild;
}
public void setLeftChild(Node leftChild) {
this.leftChild = leftChild;
}
public Node getRightChild() {
return rightChild;
}
public void setRightChild(Node rightChild) {
this.rightChild = rightChild;
}
@Override
public String toString() {
return "Node [id=" + id + ", data=" + data + ", leftChild=" + leftChild + ", rightChild=" + rightChild + "]";
}
}
/**
* 二叉搜索树操作(节点的左边小于节点值,而右边大于节点值)
* @author www.mojxtang.website
*
*/
public class BinaryTree {
/**
* 根节点
*/
private Node root;
/**
* 查找一个节点
* @param key 关键字 ID值
* @return
*/
public Node find(int key) {
Node current = root;
while(current.getId() != key) {
//如果key小于当前节点,就去找左边比当前小的节点
if (current.getId() > key) {
current = current.getLeftChild();
//如果key大于当前节点,就去找右边比当前大的节点
}else if (current.getId() < key) {
current = current.getRightChild();
}
if (current == null) {
return null;
}
}
return current;
}
/**
* 插入节点
* @param id
* @param data
*/
public void insert(int id,int data) {
Node newNode = new Node(id, data);
if (root == null) {
root = newNode;
}else {
//为什么这里要存放current=root和parent=null这两个节点对象?
Node current = root;
Node parent = null;
while (true) {
parent = current;
//如果新节点小于当前节点,我们就去左子节点找
if (id < current.getId()) {//左边
current = current.getLeftChild();
//如果没有左子节点,说明我们找到了,可以将新节点插入到此
if (current == null) {
parent.setLeftChild(newNode);
return;
}
}else {//右边
current = current.getRightChild();
//如果没有右子节点,说明我们找到了,可以将新节点插入到此
if (current == null) {
parent.setRightChild(newNode);
return;
}
}
}
}
}
/**
* 前序---获取节点数据
* @param node
*/
public void preOrder(Node node) {
if (node !=null) {
System.out.println(node.getId()+" - ");
preOrder(node.getLeftChild());
preOrder(node.getRightChild());
}
}
/**
* 中序--获取节点数据
* @param node
*/
public void inOrder(Node node) {
if (node != null) {
inOrder(node.getLeftChild());
System.out.println(node.getId()+" - ");
inOrder(node.getRightChild());
}
}
/**
* 后序--获取节点数据
* @param node
*/
public void aftOrder(Node node) {
if (node != null) {
aftOrder(node.getLeftChild());
aftOrder(node.getRightChild());
System.out.println(node.getId()+" - ");
}
}
/**
* 获取最小节点数据(使劲往左边找)
* @param node
*/
public Node getMinNode() {
Node current = root;
Node minNode = null;
while (current != null) {
minNode = current;
current = current.getLeftChild();
}
return minNode;
}
/**
* 获取最大节点数据(使劲往右边找)
* @param node
*/
public Node getMaxNode() {
Node current = root;
Node maxNode = null;
while (current != null) {
maxNode = current;
current = current.getRightChild();
}
return maxNode;
}
/**
* 删除一个节点(删除节点有两个子节点的时候,要用它的中序后继来代替该节点)
* 算法是:找到被删除节点的右子节点,然后查找这个右子节点下的最后一个左子节点,
* 也就是这颗子树的最小值节点,这就是被删除节点的中序后继节点。
* 三种情况:
* 1.没有子节点
* 2.只有一个子节点
* 3.有两个子节点
* @param key
* @return
*/
public boolean delete(int key) {
//先找到需要删除的节点
Node current = root;
Node parent = root;
boolean isLeftNode = true;
while (current.getId() != key) {//没有找到
parent = current;
if (current.getId() > key) {//当前节点大于key,往左找
isLeftNode = true;
current = current.getLeftChild();
}else if (current.getId() < key) {//当前节点小于key,往右找
isLeftNode = false;
current = current.getRightChild();
}
if (current == null) {
return false;
}
}
//1.没有子节点
if (current.getLeftChild() == null && current.getRightChild() == null) {
this.noChild(parent, current, isLeftNode);
}
//2.只有一个节点
else if (current.getRightChild() == null) {
this.oneLeftNode(parent, current, isLeftNode);
}
else if (current.getLeftChild() == null) {
this.oneRightNode(parent, current, isLeftNode);
}
//3.有两个子节点
else {
//找到中序后继节点
Node successor = this.getSuccessor(current);
if (current == root) {
root = successor;
}else {
if (isLeftNode) {
parent.setLeftChild(successor);
}else {
parent.setRightChild(successor);
}
}
//设置后继节点的左节点
successor.setLeftChild(current.getLeftChild());
}
return true;
}
/**
* 找到要删除节点的中序后继节点
* 算法是:找到被删除节点的右子节点,然后查找这个右子节点下的最后一个左子节点,
* 也就是这颗子树的最小值节点,这就是被删除节点的中序后继节点。
* @param current
* @return
*/
private Node getSuccessor(Node delNode) {
//这里为什么记录三个节点对象?
Node successor = delNode;
Node successorParent = delNode;
Node current = delNode.getRightChild();
//查找最后一个左子节点
while (current != null) {
successorParent = successor;
successor = current;
current = current.getLeftChild();
}
if (successor != delNode.getLeftChild()) {
successorParent.setLeftChild(successor.getRightChild());
successor.setRightChild(delNode.getRightChild());
}
return successor;
}
private void oneRightNode(Node parent,Node current,boolean isLeftNode) {
if (current == root) {
root = current.getRightChild();
}else {
if (isLeftNode) {
parent.setLeftChild(current.getRightChild());
}else {
parent.setRightChild(current.getRightChild());
}
}
}
private void oneLeftNode(Node parent,Node current,boolean isLeftNode) {
if (current == root) {
root = current.getLeftChild();
}else {
//这里为什么设置父节点的左右都设置为current的左节点?
if (isLeftNode) {
parent.setLeftChild(current.getLeftChild());
}else {
parent.setRightChild(current.getLeftChild());
}
}
}
/**
* 没有子节点
* @param parent
* @param current
* @param isLeftNode
*/
private void noChild(Node parent,Node current,boolean isLeftNode) {
//如果是根节点
if (current == root) {
root = null;
}else {
//这里为什么把父节点的左右值空?
if (isLeftNode) {
parent.setLeftChild(null);
}else {
parent.setRightChild(null);
}
}
}
public static void main(String[] args) {
BinaryTree tree = new BinaryTree();
tree.insert(6, 212);
tree.insert(5, 211);
tree.insert(8, 221);
tree.insert(3, 321);
tree.insert(7, 421);
tree.insert(9, 521);
System.out.println(tree.root.toString());
tree.inOrder(tree.find(6));
System.out.println(tree.getMinNode());
System.out.println(tree.getMaxNode());
tree.delete(5);
System.out.println(tree.root.toString());
}
}
二叉搜索树是所有树结构的开始模型,它最明显的特性就是节点的左子节点比该节点大,比该节点的右子节点小,形成的树大家可以想想,我们可以说他“有序”。
大家不妨思考为什么在计算机里面会用这样的数据结构来做索引其实二叉树是没有节点的左右大小之分的,那为什么我们非要把左右节点搞出来个大小呢???
二叉搜索树复杂的就是删除大家看完代码会发现,数据的删除其实就是替换和制空的过程,这个过程有个关键性的操作就是存放临时变量,我在代码块里面备注的几个为什么大家思考思考是不是这个道理。
文章地址:java二叉搜索树原理
java二叉搜索树原理与实现的更多相关文章
- Java二叉搜索树实现
树集合了数组(查找速度快)和链表(插入.删除速度快)的优点 二叉树是一种特殊的树,即:树中的每个节点最多只能有两个子节点 二叉搜索树是一种特殊的二叉树,即:节点的左子节点的值都小于这个节点的值,节点的 ...
- AVL平衡二叉搜索树原理及各项操作编程实现
C语言版 #include<stdio.h> #include "fatal.h" struct AvlNode; typedef struct AvlNode *Po ...
- C++ 二叉搜索树原理及其实现
首先是概念:二叉搜索树又称二叉排序树,它具有以下的性质: 若是左子树不为空,则左子树上所有节点的值小于根节点的值 若是右子树不为空,则右子树上所有结点的值大于根节点的值 二叉搜索树的左右子树也是二叉搜 ...
- Java 二叉搜索树 实现和学习
/** * <html> * <body> * <P> Copyright 1994 JsonInternational</p> * <p> ...
- java 二叉搜索树
java二叉查找树实现: 二叉查找树,上图:比根节点小者在其左边,比根节点大者在其右边. 抽象数据结构,上代码: /** * 二叉查找树数据结构(非线程安全): * 范型类型须实现Comparable ...
- 【算法学习】AVL平衡二叉搜索树原理及各项操作编程实现(C语言)
#include<stdio.h> #include "fatal.h" struct AvlNode; typedef struct AvlNode *Positio ...
- 二叉搜索树详解(Java实现)
1.二叉搜索树定义 二叉搜索树,是指一棵空树或者具有下列性质的二叉树: 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值: 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根 ...
- 【算法与数据结构】二叉搜索树的Java实现
为了更加深入了解二叉搜索树,博主自己用Java写了个二叉搜索树,有兴趣的同学可以一起探讨探讨. 首先,二叉搜索树是啥?它有什么用呢? 二叉搜索树, 也称二叉排序树,它的每个节点的数据结构为1个父节点指 ...
- Java实现二叉搜索树的添加,前序、后序、中序及层序遍历,求树的节点数,求树的最大值、最小值,查找等操作
什么也不说了,直接上代码. 首先是节点类,大家都懂得 /** * 二叉树的节点类 * * @author HeYufan * * @param <T> */ class Node<T ...
随机推荐
- java中集合
一. List集合: 一次只存储一个元素 1.常用的list集合是ArrayList (1)在创建这个集合的对象时, 需要指定这个集合存储的数据类型! 否则这个集合的数据是不安全的. (2)与数组的 ...
- 给 console 添加颜色
简评:使用 %c 声明可以给 console 的输出添加 CSS 样式,日志太多的话,给不同种类的日志设置不同的样式,可以极大的提升阅读体验. 什么是 %c %c: 标识将 CSS 样式应用于 %c ...
- Unicode字符串索引
一.目标 在通讯录中,我们有很多联系人,需要把这些联系人进行索引.对于每一个索引项对应的若干字符串,需要对这些字符串进行排序. 需要解决两个问题: 如何确定某个汉字应该被哪个字符索引? 某个索引项对应 ...
- python --爬虫--爬取百度翻译
import requestsimport json class baidufanyi: def __init__(self, trans_str): self.lang_detect_url = ' ...
- day 10 课后作业
# -*- coding: utf-8 -*-# @Time : 2019/1/2 16:35# @Author : Endless-cloud# @Site : # @File : 课后作业.py# ...
- TSL协议升级导致的问题:caught when processing request: Received fatal alert: protocol_version
近日,公司升级TSL协议,禁用TSL1.0,导致原本好好的https接口,报以下错误: 2019-03-05 15:43:29 [org.apache.commons.httpclient.HttpM ...
- git 远程库和url
我们使用 git remote add origin <url> 来关联远程主机,这个origin就是关联的远程主机名,如果我们想同时关联两个远程主机,我们可以用 git remote a ...
- 不好意思啊,我上周到今天不到10天时间,用纯C语言写了一个小站!想拍砖的就赶紧拿出来拍啊
花10天时间用C语言做了个小站 http://tieba.yunxunmi.com/index.html 简称: 云贴吧 不好意思啊,我上周到今天不到10天时间,用纯C语言写了一个小站!想拍砖的就赶紧 ...
- [Xamarin.iOS] 如何引用Objective-c寫的Class Library (转帖)
這個範例是如何在Xamarin.ios中去使用一個我們自行在Xcode中開發的Objective-c Class Library. 主要會執行的步驟如下 1. 在Xcode 裡面去建立一個Class ...
- (转)错误"因为数据库正在使用,所以无法获得对数据库的独占访问权"的解决方案
引发原因:是因为我在还原数据库的时候,还有其他的用户正在使用数据库,所以就会出现以上提示. 解决方法:1,设置数据库在单用户模式下工作.设置方法:在需要还原的数据库上右击,在右键菜单命令上选择&quo ...