首页 技术 正文
技术 2022年11月11日
0 收藏 603 点赞 2,595 浏览 4673 个字

基础概念  

  二叉树(binary tree)是一棵树,其中每个结点都不能有多于两个儿子。

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

    (1)若左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值;
    (2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
    (3)左、右子树也分别为二叉排序树;

数据结构(Java描述)之二叉树

二叉树的遍历

  二叉树的遍历是指从根节点出发,按照某种次序依次访问二叉树中所有结点,使得每个结点被访问一次且仅被访问一次。二叉树的遍历方式有很多,主要有前序遍历,中序遍历,后序遍历。

前序遍历

  前序遍历的规则是:若二叉树为空,则空操作返回,否则先访问根节点,然后前序遍历左子树,再前序遍历右子树

数据结构(Java描述)之二叉树

中序遍历

  中序遍历的规则是:若树为空,则空操作返回;否则从根节点开始(注意并不是先访问根节点),中序遍历根节点的左子树,然后是访问根节点,最后中序遍历右子树。可以看到,如果是二叉排序树,中序遍历的结果就是个有序序列。

数据结构(Java描述)之二叉树

后序遍历

  后序遍历的规则是:若树为空,则空操作返回;然后先遍历左子树,再遍历右子树,最后访问根结点,在遍历左、右子树时,仍然先遍历左子树,然后遍历右子树,最后遍历根结点。

 数据结构(Java描述)之二叉树

删除结点

  对于二叉排序树的其他操作,比如插入,遍历等,比较容易理解;而删除操作相对复杂。对于要删除的结点,有以下三种情况:

  1.叶子结点;

  2.仅有左子树或右子树的结点

  3.左右子树都有结点

  对于1(要删除结点为叶子结点)直接删除,即直接解除父节点的引用即可,对于第2种情况(要删除的结点仅有一个儿子),只需用子结点替换掉父节点即可;而对于要删除的结点有两个儿子的情况,比较常用处理逻辑为,在其子树中找寻一个结点来替换,而这个结点我们成为中序后继结点。

数据结构(Java描述)之二叉树

  可以看到,我们找到的这个用来替换的结点,可以是删除结点的右子树的最小结点(6),也可以是其左子树的最大结点(4),这样可以保证替换后树的整体结构不用发生变化。为什么称为中序后继结点呢?我们来看下这棵树的中序遍历结果 1-2-3–5–7-8-9。可以很清晰的看到,其实要找的这个结点,可以是结点5的前驱或者后继。

代码实现

 package treeDemo; /**  * Created by chengxiao on 2017/02/12.  */ public class BinaryTree {     //根节点     private Node root;     /**      * 树的结点      */     private static class Node{         //数据域         private long data;         //左子结点         private Node leftChild;         //右子结点         private Node rightChild;         Node(long data){             this.data = data;         }     }     /**      * 插入结点      * @param data      */     public void insert(long data){         Node newNode = new Node(data);         Node currNode = root;         Node parentNode;         //如果是空树         if(root == null){             root = newNode;             return;         }         while(true){             parentNode = currNode;             //向右搜寻             if(data > currNode.data){                 currNode = currNode.rightChild;                 if(currNode == null){                     parentNode.rightChild = newNode;                     return;                 }             }else{                 //向左搜寻                 currNode = currNode.leftChild;                 if(currNode == null){                     parentNode.leftChild = newNode;                     return;                 }             }         }     }     /**      * 前序遍历      * @param currNode      */     public void preOrder(Node currNode){         if(currNode == null){             return;         }         System.out.print(currNode.data+" ");         preOrder(currNode.leftChild);         preOrder(currNode.rightChild);     }     /**      * 中序遍历      * @param currNode      */     public void inOrder(Node currNode){         if(currNode == null){             return;         }         inOrder(currNode.leftChild);         System.out.print(currNode.data+" ");         inOrder(currNode.rightChild);     }     /**      * 查找结点      * @param data      * @return      */     public Node find(long data){         Node currNode = root;         while(currNode!=null){             if(data>currNode.data){                 currNode = currNode.rightChild;             }else if(data<currNode.data){                 currNode = currNode.leftChild;             }else{                 return currNode;             }         }         return null;     }     /**      * 后序遍历      * @param currNode      */     public void postOrder(Node currNode){         if(currNode == null){             return;         }         postOrder(currNode.leftChild);         postOrder(currNode.rightChild);         System.out.print(currNode.data+" ");     }     /**      * 删除结点 分为3种情况      * 1.叶子结点      * 2.该节点有一个子节点      * 3.该节点有二个子节点      * @param data      */     public boolean delete(long data) throws Exception {         Node curr = root;         //保持一个父节点的引用         Node parent = curr;         //删除为左结点还是右界定啊         boolean isLeft = true;         while(curr != null && curr.data!=data){             parent = curr;             if(data > curr.data){                 curr = curr.rightChild;                 isLeft = false;             }else{                 curr = curr.leftChild;                 isLeft = true;             }         }         if(curr==null){             throw new Exception("要删除的结点不存在");         }         //第一种情况,要删除的结点为叶子结点         if(curr.leftChild == null && curr.rightChild == null){             if(curr == root){                 root = null;                 return true;             }             if(isLeft){                 parent.leftChild = null;             }else{                 parent.rightChild = null;             }         }else if(curr.leftChild == null){             //第二种情况,要删除的结点有一个子节点且是右子结点             if(curr == root){                 root = curr.rightChild;                 return true;             }             if(isLeft){                 parent.leftChild = curr.rightChild;             }else{                 parent.rightChild = curr.rightChild;             }         }else if(curr.rightChild == null){             //第二种情况,要删除的结点有一个子节点且是左子结点             if(curr == root){                 root = curr.leftChild;                 return true;             }             if(isLeft){                 parent.leftChild = curr.leftChild;             }else{                 parent.rightChild = curr.leftChild;             }         }else{             //第三种情况,也是最复杂的一种情况,要删除的结点有两个子节点,需要找寻中序后继结点             Node succeeder = getSucceeder(curr);             if(curr == root){                 root = succeeder;                 return  true;             }             if(isLeft){                 parent.leftChild = succeeder;             }else{                 parent.rightChild = succeeder;             }             //当后继结点为删除结点的右子结点             succeeder.leftChild = curr.leftChild;         }         return true;     }     public Node getSucceeder(Node delNode){         Node succeeder = delNode;         Node parent = delNode;         Node currNode = delNode.rightChild;         //寻找后继结点         while(currNode != null){             parent = succeeder;             succeeder = currNode;             currNode = currNode.leftChild;         }         //如果后继结点不是要删除结点的右子结点         if(succeeder != delNode.rightChild){             parent.leftChild = succeeder.rightChild;             //将后继结点的左右子结点分别指向要删除结点的左右子节点             succeeder.leftChild = delNode.leftChild;             succeeder.rightChild = delNode.rightChild;         }         return succeeder;     }     public static void main(String []args) throws Exception {         BinaryTree binaryTree = new BinaryTree();         //插入操作         binaryTree.insert(5);         binaryTree.insert(2);         binaryTree.insert(8);         binaryTree.insert(1);         binaryTree.insert(3);         binaryTree.insert(6);         binaryTree.insert(10);         //前序遍历         System.out.println("前序遍历:");         binaryTree.preOrder(binaryTree.root);         System.out.println();         //中序遍历         System.out.println("中序遍历:");         binaryTree.inOrder(binaryTree.root);         System.out.println();         //后序遍历         System.out.println("后序遍历:");         binaryTree.postOrder(binaryTree.root);         System.out.println();         //查找结点         Node node = binaryTree.find(10);         System.out.println("找到结点,其值为:"+node.data);         //删除结点         binaryTree.delete(8);         System.out.print("删除结点8,中序遍历:");         binaryTree.preOrder(binaryTree.root);     } }

执行结果

前序遍历:5 2 1 3 8 6 10中序遍历:1 2 3 5 6 8 10后序遍历:1 3 2 6 10 8 5找到结点,其值为:10删除结点8,中序遍历:5 2 1 3 10 6 
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,083
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,558
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,407
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,180
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,817
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,899