用树作为存储数据的结构兼具像数组一样查询速度快和像链表一样具有很快的插入和删除数据项的优点

  我们用圆点表示节点,连接圆的直线表示边如下图所示就表示了一颗树,接下来我们讨论的二叉树即每个节点最多只有两个子节点的树称作是二叉树。除了二叉树还有多路树,比如2-3-4树和外部存储就属于多路树

  二叉搜索树:一个节点的左子节点关键字小于这个节点,右子节点关键字大于或等于这个父节点,

  在java中我们要设计一个树可以只用下面的代码

class Node{   //树节点类         class Person{  //封装树节点的数据  class Tree{     //相当于树的根节点

  Person person;               int iData;              private Node root;

  Node leftChild;              double dData;              //包含一些操作树的方法

  Node rightChild;               }                }

}                 

二叉树查找元素

  下图展示了在搜索二叉树中查找关键值为57的节点的查找流程图

由上图我们可以写出上面的们Tree类中的查找的方法

  1. public Node find ( int key ){
  2.   Node current = root;
  3.   while(current.iData != key){
  4.     if(key < current.iData){
  5.       current = current.leftChild;
  6.     }else{
  7.       current = current.rightChild;
  8.     }
  9.     if(current == null){  //说明此时没有找到对应的节点
  10.       return null;
  11.     }  
  12.   }
  13.   return current;     //循环执行结束跳出循环,说明找到此关键字节点,返回节点
  14. }

  这里我们可以总结出在树中查找节点的效率,首先取决于关键字所在树的层数,像我们图中给出的树最多5层,即查找最多进行5次比较,节点数最多为31准确来说所需要的时间复杂度为O(log2N)

二叉树插入节点

  接下来讨论在树中插入一个节点:插入的方法和查找很像,只不过插入在最后一步遇到null不是立即返回null,而需要在返回之前插入节点

  1. public void insert( int id,double dd){
  2.   Node newNode = new Node;  //创建新的节点
  3.   newNode.iData = id;
  4.   newNode.dData = dd;
  5.   if(root == null){
  6.     root = newNode;
  7.   }else{
  8.     Node current = root;
  9.     Node parent;      //引入parent是为了记录新节点插入的位置,不然当找到插入的地方会去其插入的父节点的位置
  10.     while(true){
  11.       parent = current;
  12.       if(id< current.iData){
  13.         current = current.leftChild;
  14.         if(current == null){  //说明此时没有找到对应的节点,将新节点连入左子节点
  15.           parrent.leftChild = newNode;
  16.           return;
  17.         } 
  18.       }else{
  19.         current = current.rightChild;
  20.         if(current == null){  //说明此时没有找到对应的节点,将新节点连入右子节点
  21.           parrent.rightChild= newNode;
  22.           return;
  23.         } 
  24.       }
  25.     }
  26.   }
  27. }

遍历二叉树  

  接下来我们介绍遍历一个二叉树:我们常用的遍历树的方法有三种:前序,中序,后序。二叉树中常用的遍历方式是中序遍历,这里我们遍历的方法只需要做三件事情,1.调用自身来遍历节点的左子树,2.访问这个节点,3.调用自身来遍历节点的右子树,下面是java代码

  1. public void inOrder(Node localRoot){            //使用递归的方式来遍历一颗树
  2.   if(localRoot != null){
  3.     inOrder(localRoot.leftChild);           //遍历左子树
  4.     System.out.print(localRoot.iData+" ");   //访问自身数据
  5.     inOrder(localRoot.rightChild);           //遍历右子树
  6.   }
  7. }

  前序遍历步骤 :1.访问这个节点,2.调用自身来遍历节点的左子树,3.调用自身来遍历节点的右子树

  后序遍历步骤 :1.调用自身来遍历节点的左子树,2.调用自身来遍历节点的右子树,3.访问这个节点

  查找二叉搜索树中的最大最小值:最小值一直往树的最左边往下查找即可得到最小值,相反向右可得到最大值。

  1. public Node minimum(){            //查找二叉搜索树中的最小值
  2.   Node current,last;
  3.   current = root;
  4.   while(current != null){
  5. last = current;
  6. current = current.leftChild;  //将这里换成Right即可查询的到最大值
  7. }
  8. return last;
  9. }

删除二叉树中的节点   

  接下来介绍二叉树如何删除一个节点,要删除二叉树的节点我们需要考虑到三种删除的状态:

    1.该节点是叶节点,是叶节点的情况删除很简单,只需要将父节点对应的子节点改为null即可,如图

    2.节点有一个子节点,删除该节点,只需要将需要删除的节点的唯一一个子节点连接到需要删除的节点的父节点之上,如图

    3.有两个子节点,若有两个子节点,则需要找到该删除节点的中序后继节点来替换当前删除的节点(找后继节点的算法简单来说就是先向该节点右边找到子节点,然后一直往左边找到最小值即可得到该节点的后继节点)

接下来写出完整的删除节点的java代码

  1. public boolean delete(int key){
  2.   Node current = root;
  3.   Node parent = root;
  4.   boolean isLeftChild = true;
  5.   while(current.iData != key){
  6.     parent = current;
  7.     if(key < current.iData){
  8.       isLeftChild = true;
  9.       current = current.leftChild;
  10.     }else{
  11.       isLeftChild = false;
  12.       current = current.rightChild;
  13.     }
  14.     if(current == null){
  15.       return;    //没有找到需要删除的数据项,直接返回
  16.     }
  17.   }
  18.   //1.如果删除的节点是叶子结点,直接删除
  19.   if(current.leftChild == null && current.rightChild == null){
  20.     if(current == root){
  21.       root = null;
  22.     }else if(isLeftChild){
  23.       parent.leftChild = null;
  24.     }else{
  25.       parent.rightChild = null;
  26.     }
  27.   }else if(current.rightChild == null){  //删除的节点只有左子节点
  28.     if(current == root){
  29.       root = current.leftChild;
  30.     }else if(isLeftChild){
  31.       parent.leftChild =  current.leftChild;
  32.     }else{
  33.       parent.rightChild =  current.leftChild ;
  34.     }
  35.   }else if(current.leftChild == null){  //删除的节点只有右子节点
  36.     if(current == root){
  37.       root = current.leftChild;
  38.     }else if(isLeftChild){
  39.       parent.leftChild =  current.rightChild ;
  40.     }else{
  41.       parent.rightChild =  current.rightChild ;
  42.     }
  43.   }else{
  44.     Node successor = getSuccessor(current);   //查找得到删除节点的后继
  45.     if(current == root){
  46.       root = successor;
  47.     }else if(isLeftChild){
  48.       parent.leftChild =  successor;
  49.     }else{
  50.       parent.rightChild = successor;
  51.     }
  52.       successor.leftChild = current.leftChild;  //最后一步设置删除替换后的左子节点
  53.   }
  54. }
  55. //查找后继节点的算法
  56. private Node getSuccessor(Node delNode){
  57.   Node successorParent = delNode;
  58.   Node successor  = delNode;
  59.   Node current = delNode.rightChild;
  60.   While(current!=null){
  61.     successorParent = successor;
  62.     successor = current;
  63.     current = current.leftChild;
  64.   }
  65.   if(successor != delNode.rightChild){
  66.     successorParent.leftChild = successor.rightChild;//将后继节点的父节点的左子节点值设置为后继的右子节点
  67.      successor.rightChild = delNode.rightChild;//将后继节点的右子节点设置成当前删除节点的右子节点(处理后)
  68.   }
  69.   return successor;
  70. }

二叉树的效率

二叉树的效率:二叉树的效率取决于二叉树的层数(层数即为操作时最多的比较次数),下表给出了一个二叉满树的节点数和层数的关系,我们可以设第一列节点数为N层数为L,那么

N = 2L-1   <=> L = (log2N+1)

这里我们能换算成大O表示的时间复杂度为O(logN)。同样层数的不满的树的用时是要小于满树的时间的,树对于常用的数据存储操作有很高的效率,遍历不如其他的操作快。

JAVA数据结构之二叉树的更多相关文章

  1. java数据结构之二叉树的实现

    java二叉树的简单实现,可以简单实现深度为n的二叉树的建立,二叉树的前序遍历,中序遍历,后序遍历输出. /** *数据结构之树的实现 *2016/4/29 * **/ package cn.Link ...

  2. Java数据结构之二叉树的基本介绍与递归遍历

    二叉树的基本概念: 正如我们所了解的,树是有很多中形态,但是我们规定,形如每个节点最多只能有两个子节点的一种形如称为二叉树.我们将二叉树中该节点的两个子节点分别称作为:左孩子节点和右孩子节点.该节点称 ...

  3. java数据结构之二叉树遍历的非递归实现

    算法概述递归算法简洁明了.可读性好,但与非递归算法相比要消耗更多的时间和存储空间.为提高效率,我们可采用一种非递归的二叉树遍历算法.非递归的实现要借助栈来实现,因为堆栈的先进后出的结构和递归很相似.对 ...

  4. java数据结构之二叉树的定义和递归实现

    定义最多有两棵子树的有序树,称为二叉树.二叉树是一种特殊的树.递归定义:二叉树是n(n>=0)个有限结点构成的集合.N=0称为空二叉树:n>0的二叉树由一个根结点和两互不相交的,分别称为左 ...

  5. Java数据结构之树和二叉树(2)

    从这里始将要继续进行Java数据结构的相关讲解,Are you ready?Let's go~~ Java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来 ...

  6. Java数据结构之树和二叉树

    从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~ Java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来的 ...

  7. Java数据结构和算法 - 二叉树

    前言 数据结构可划分为线性结构.树型结构和图型结构三大类.前面几篇讨论了数组.栈和队列.链表都是线性结构.树型结构中每个结点只允许有一个直接前驱结点,但允许有一个以上直接后驱结点.树型结构有树和二叉树 ...

  8. Java数据结构和算法(六)--二叉树

    什么是树? 上面图例就是一个树,用圆代表节点,连接圆的直线代表边.树的顶端总有一个节点,通过它连接第二层的节点,然后第二层连向更下一层的节点,以此递推 ,所以树的顶端小,底部大.和现实中的树是相反的, ...

  9. 【java 数据结构】还不会二叉树?一篇搞定二叉树

    二叉树是我们常见的数据结构之一,在学习二叉树之前我们需要知道什么是树,什么是二叉树,本篇主要讲述了二叉树,以及二叉树的遍历. 你能get到的知识点? 1.树的介绍 2.二叉树的介绍 3.二叉树遍历的四 ...

随机推荐

  1. Match & Catch CodeForces - 427D 后缀自动机水题

    题意: 给出两个字符串a,b,求一个字符串,这个字符串是a和b的子串, 且只在a,b中出现一次,要求输出这个字符串的最小长度. 题解: 将a串放入后缀自动机中,然后记录一下每个节点对应的子串出现的次数 ...

  2. Mac版本的 Axure rp8 不显示菜单栏

    我之前也是一直在找这个问题,可能mac用的不熟练吧,其实他的菜单栏就近在眼前 你看不见只是因为你的关注点在axure上 往大了看,他的菜单栏显示在你的电脑的菜单栏上,mac的菜单栏基本都是这么显示的, ...

  3. 富文本编辑器 CKeditor 配置使用+上传图片

    参考文献: 富文本编辑器 CKeditor 配置使用 CKEditor与CKFinder的配置(ASP.NET环境),老版本可以参考 CKEditor+CKFinder ASP版在本地电脑中的配置  ...

  4. docker Dockerfile学习---构建redis环境

    1.创建项目目录并下载包及文件 mkdir centos_redis cd centos_redis wget http://download.redis.io/releases/redis-5.0. ...

  5. scip 练习2.20

    (define (same-parity x . z) (define (q? y) (= (remainder y ) )) (define (o? y) (= (remainder y ) )) ...

  6. top.location.href

    window.location.href.location.href是本页面跳转   parent.location.href是上一层页面跳转   top.location.href是最外层的页面跳转 ...

  7. CSS四种定位及应用

    定位(position) 如果,说浮动, 关键在一个 “浮” 字上面, 那么 我们的定位,关键在于一个 “位” 上. PS: 定位是我们CSS算是数一数二难点的了,但是,你务必要学好它,我们CSS离不 ...

  8. 压缩图片大小(Java源码)

    /** * * 直接指定压缩后的宽高: * @param oldFile * 要进行压缩的文件 * @param width * 压缩后的宽度 * @param height * 压缩后的高度 * @ ...

  9. NOI2019赛前两周被吊打记录

    7.1 T1看了半天发现会个暴力FWT,然后突然返发现随便容斥一下就好了 T2猜了个只有13和23的,结果打个表发现伪了,然后标号不只一种连搜索都写错了,也没想过可以轮廓线dp,菜哭了o(╥﹏╥)o ...

  10. Android中的APK,TASK,PROCESS,USERID之间的关系

    开发Android已经有一段时间了,今天接触到底层的东西,所以对于进程,用户的id以及Android中的Task,Apk之间的关系,要做一个研究,下面就是研究结果: apk一般占一个dalvik,一个 ...