计算机里面的数据结构 树 在计算机存储领域应用作用非常大,我之前也多次强调多磁盘的存取速度是目前计算机飞速发展的一大障碍,计算机革命性的的下一次飞跃就是看硬盘有没有质的飞跃,为什么这么说?因为磁盘是永久性存储设备(在相当长的时间内都可以用),就这一点虽然内存在性能方面优势巨大但是保存信息和数据还是要靠磁盘。

数最成功的要数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二叉搜索树原理

* 二叉搜索树操作(节点的左边小于节点值,而右边大于节点值)
* @author www.mojxtang.website
*
*/
publicclassBinaryTree{
 
/**
* 根节点
*/
privateNode root;
/**
* 查找一个节点
* @param key 关键字 ID值
* @return
*/
publicNode find(intkey){
Node current=root;
while(current.getId()!=key){
//如果key小于当前节点,就去找左边比当前小的节点
if(current.getId()>key){
current=current.getLeftChild();
//如果key大于当前节点,就去找右边比当前大的节点
}elseif(current.getId()<key){
current=current.getRightChild();
}
if(current==null){
returnnull;
}
}
returncurrent;
}
/**
* 插入节点
* @param id
* @param data
*/
publicvoidinsert(intid,intdata){
Node newNode=newNode(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
*/
publicvoidpreOrder(Node node){
if(node!=null){
System.out.println(node.getId()+" - ");
preOrder(node.getLeftChild());
preOrder(node.getRightChild());
}
}
/**
* 中序--获取节点数据
* @param node
*/
publicvoidinOrder(Node node){
if(node!=null){
inOrder(node.getLeftChild());
System.out.println(node.getId()+" - ");
inOrder(node.getRightChild());
}
}
/**
* 后序--获取节点数据
* @param node
*/
publicvoidaftOrder(Node node){
if(node!=null){
aftOrder(node.getLeftChild());
aftOrder(node.getRightChild());
System.out.println(node.getId()+" - ");
}
}
/**
* 获取最小节点数据(使劲往左边找)
* @param node
*/
publicNode getMinNode(){
Node current=root;
Node minNode=null;
while(current!=null){
minNode=current;
current=current.getLeftChild();
}
returnminNode;
}
/**
* 获取最大节点数据(使劲往右边找)
* @param node
*/
publicNode getMaxNode(){
Node current=root;
Node maxNode=null;
while(current!=null){
maxNode=current;
current=current.getRightChild();
}
returnmaxNode;
}
/**
* 删除一个节点(删除节点有两个子节点的时候,要用它的中序后继来代替该节点)
     * 算法是:找到被删除节点的右子节点,然后查找这个右子节点下的最后一个左子节点,
     * 也就是这颗子树的最小值节点,这就是被删除节点的中序后继节点。
     * 三种情况:
     *   1.没有子节点
     *   2.只有一个子节点
     *   3.有两个子节点
* @param key
* @return
*/
publicbooleandelete(intkey){
//先找到需要删除的节点
Node current=root;
Node parent=root;
booleanisLeftNode=true;
while(current.getId()!=key){//没有找到
parent=current;
if(current.getId()>key){//当前节点大于key,往左找
isLeftNode=true;
current=current.getLeftChild();
}elseif(current.getId()<key){//当前节点小于key,往右找
isLeftNode=false;
current=current.getRightChild();
}
if(current==null){
returnfalse;
}
}
 
//1.没有子节点
if(current.getLeftChild()==null&&current.getRightChild()==null){
this.noChild(parent,current,isLeftNode);
}
//2.只有一个节点
elseif(current.getRightChild()==null){
this.oneLeftNode(parent,current,isLeftNode);
}
elseif(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());
 
}
returntrue;
}
/**
* 找到要删除节点的中序后继节点
* 算法是:找到被删除节点的右子节点,然后查找这个右子节点下的最后一个左子节点,
     *    也就是这颗子树的最小值节点,这就是被删除节点的中序后继节点。
* @param current
* @return
*/
privateNode 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());
}
returnsuccessor;
}
privatevoidoneRightNode(Node parent,Node current,booleanisLeftNode){
if(current==root){
root=current.getRightChild();
}else{
if(isLeftNode){
parent.setLeftChild(current.getRightChild());
}else{
parent.setRightChild(current.getRightChild());
}
}
}
privatevoidoneLeftNode(Node parent,Node current,booleanisLeftNode){
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
*/
privatevoidnoChild(Node parent,Node current,booleanisLeftNode){
//如果是根节点
if(current==root){
root=null;
}else{
//这里为什么把父节点的左右值空?
if(isLeftNode){
parent.setLeftChild(null);
}else{
parent.setRightChild(null);
}
}
}
 
publicstaticvoidmain(String[]args){
BinaryTree tree=newBinaryTree();
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二叉搜索树原理与实现的更多相关文章

  1. Java二叉搜索树实现

    树集合了数组(查找速度快)和链表(插入.删除速度快)的优点 二叉树是一种特殊的树,即:树中的每个节点最多只能有两个子节点 二叉搜索树是一种特殊的二叉树,即:节点的左子节点的值都小于这个节点的值,节点的 ...

  2. AVL平衡二叉搜索树原理及各项操作编程实现

    C语言版 #include<stdio.h> #include "fatal.h" struct AvlNode; typedef struct AvlNode *Po ...

  3. C++ 二叉搜索树原理及其实现

    首先是概念:二叉搜索树又称二叉排序树,它具有以下的性质: 若是左子树不为空,则左子树上所有节点的值小于根节点的值 若是右子树不为空,则右子树上所有结点的值大于根节点的值 二叉搜索树的左右子树也是二叉搜 ...

  4. Java 二叉搜索树 实现和学习

    /** * <html> * <body> * <P> Copyright 1994 JsonInternational</p> * <p> ...

  5. java 二叉搜索树

    java二叉查找树实现: 二叉查找树,上图:比根节点小者在其左边,比根节点大者在其右边. 抽象数据结构,上代码: /** * 二叉查找树数据结构(非线程安全): * 范型类型须实现Comparable ...

  6. 【算法学习】AVL平衡二叉搜索树原理及各项操作编程实现(C语言)

    #include<stdio.h> #include "fatal.h" struct AvlNode; typedef struct AvlNode *Positio ...

  7. 二叉搜索树详解(Java实现)

    1.二叉搜索树定义 二叉搜索树,是指一棵空树或者具有下列性质的二叉树: 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值: 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根 ...

  8. 【算法与数据结构】二叉搜索树的Java实现

    为了更加深入了解二叉搜索树,博主自己用Java写了个二叉搜索树,有兴趣的同学可以一起探讨探讨. 首先,二叉搜索树是啥?它有什么用呢? 二叉搜索树, 也称二叉排序树,它的每个节点的数据结构为1个父节点指 ...

  9. Java实现二叉搜索树的添加,前序、后序、中序及层序遍历,求树的节点数,求树的最大值、最小值,查找等操作

    什么也不说了,直接上代码. 首先是节点类,大家都懂得 /** * 二叉树的节点类 * * @author HeYufan * * @param <T> */ class Node<T ...

随机推荐

  1. objectARX创建 PaletteSet 停靠面板示例

    objectARX创建 PaletteSet 停靠面板示例 图文By edata ,转载注明出处 http://www.cnblogs.com/edata 部分代码参考张帆<AutoCAD Ob ...

  2. 0基础浅谈反射型xss(2)

    0x1:回顾前文疑惑“先闭合,在构造” 上一篇,我们说到了xss的一个触发精髓,“先闭合,在构造”,对于前面的先闭合,我们来简单的解释一下:   首先说,为什么要闭合? 因为HTML标签都是成对出现的 ...

  3. php 对比两个数组中的值是否相等

    $a = ['1','2','4','3'];//提交答案 $b = ['2','1','3'];//正确答案 $state = $this->diffArray($b, $a); echo ' ...

  4. [JS] 气球放气效果

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name ...

  5. jquery源码解析:attr,prop,attrHooks,propHooks详解

    我们先来看一下jQuery中有多少个方法是用来操作元素属性的. 首先,看一下实例方法: 然后,看下静态方法(工具方法): 静态方法是内部使用的,我们外面使用的很少,实例方法才是对外的. 接下来,我们来 ...

  6. [RHEL] 配置 LVM 卷

    [RHEL] 配置 LVM 卷 一.Introduction 基础预览 :LVM 认知与扩容操作 高端实战:Linux系统如何迁移至LVM磁盘 之前转过一篇文章 LVM分区在线扩容 ,其原因是我需要给 ...

  7. multiprocessor(下)

    一.数据共享 展望未来,基于消息传递的并发编程是大势所趋即便是使用线程,推荐做法也是将程序设计为大量独立的线程集合,通过消息队列交换数据.这样极大地减少了对使用锁定和其他同步手段的需求,还可以扩展到分 ...

  8. leetcode-219-Contains Duplicate II(使用set来判断长度为k+1的闭区间中有没有重复元素)

    题目描述: Given an array of integers and an integer k, find out whether there are two distinct indices i ...

  9. NSObject 中执行Selector 的相关方法

    1. 对当前Run Loop中Selector Sources的取消 NSObject中的performSelector:withObject:afterDelay:方法将会在当前线程的Run Loo ...

  10. HUE配置文件hue.ini 的sqoop模块详解(图文详解)(分HA集群和非HA集群)

    不多说,直接上干货! 我的集群机器情况是 bigdatamaster(192.168.80.10).bigdataslave1(192.168.80.11)和bigdataslave2(192.168 ...