JAVA数据结构之二叉树
用树作为存储数据的结构兼具像数组一样查询速度快和像链表一样具有很快的插入和删除数据项的优点
我们用圆点表示节点,连接圆的直线表示边如下图所示就表示了一颗树,接下来我们讨论的二叉树即每个节点最多只有两个子节点的树称作是二叉树。除了二叉树还有多路树,比如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类中的查找的方法
- public Node find ( int key ){
- Node current = root;
- while(current.iData != key){
- if(key < current.iData){
- current = current.leftChild;
- }else{
- current = current.rightChild;
- }
- if(current == null){ //说明此时没有找到对应的节点
- return null;
- }
- }
- return current; //循环执行结束跳出循环,说明找到此关键字节点,返回节点
- }
这里我们可以总结出在树中查找节点的效率,首先取决于关键字所在树的层数,像我们图中给出的树最多5层,即查找最多进行5次比较,节点数最多为31准确来说所需要的时间复杂度为O(log2N)
二叉树插入节点
接下来讨论在树中插入一个节点:插入的方法和查找很像,只不过插入在最后一步遇到null不是立即返回null,而需要在返回之前插入节点
- public void insert( int id,double dd){
- Node newNode = new Node; //创建新的节点
- newNode.iData = id;
- newNode.dData = dd;
- if(root == null){
- root = newNode;
- }else{
- Node current = root;
- Node parent; //引入parent是为了记录新节点插入的位置,不然当找到插入的地方会去其插入的父节点的位置
- while(true){
- parent = current;
- if(id< current.iData){
- current = current.leftChild;
- if(current == null){ //说明此时没有找到对应的节点,将新节点连入左子节点
- parrent.leftChild = newNode;
- return;
- }
- }else{
- current = current.rightChild;
- if(current == null){ //说明此时没有找到对应的节点,将新节点连入右子节点
- parrent.rightChild= newNode;
- return;
- }
- }
- }
- }
- }
遍历二叉树
接下来我们介绍遍历一个二叉树:我们常用的遍历树的方法有三种:前序,中序,后序。二叉树中常用的遍历方式是中序遍历,这里我们遍历的方法只需要做三件事情,1.调用自身来遍历节点的左子树,2.访问这个节点,3.调用自身来遍历节点的右子树,下面是java代码
- public void inOrder(Node localRoot){ //使用递归的方式来遍历一颗树
- if(localRoot != null){
- inOrder(localRoot.leftChild); //遍历左子树
- System.out.print(localRoot.iData+" "); //访问自身数据
- inOrder(localRoot.rightChild); //遍历右子树
- }
- }


前序遍历步骤 :1.访问这个节点,2.调用自身来遍历节点的左子树,3.调用自身来遍历节点的右子树
后序遍历步骤 :1.调用自身来遍历节点的左子树,2.调用自身来遍历节点的右子树,3.访问这个节点
查找二叉搜索树中的最大最小值:最小值一直往树的最左边往下查找即可得到最小值,相反向右可得到最大值。
- public Node minimum(){ //查找二叉搜索树中的最小值
- Node current,last;
- current = root;
- while(current != null){
- last = current;
- current = current.leftChild; //将这里换成Right即可查询的到最大值
- }
- return last;
- }
删除二叉树中的节点
接下来介绍二叉树如何删除一个节点,要删除二叉树的节点我们需要考虑到三种删除的状态:
1.该节点是叶节点,是叶节点的情况删除很简单,只需要将父节点对应的子节点改为null即可,如图
2.节点有一个子节点,删除该节点,只需要将需要删除的节点的唯一一个子节点连接到需要删除的节点的父节点之上,如图
3.有两个子节点,若有两个子节点,则需要找到该删除节点的中序后继节点来替换当前删除的节点(找后继节点的算法简单来说就是先向该节点右边找到子节点,然后一直往左边找到最小值即可得到该节点的后继节点)



接下来写出完整的删除节点的java代码
- public boolean delete(int key){
- Node current = root;
- Node parent = root;
- boolean isLeftChild = true;
- while(current.iData != key){
- parent = current;
- if(key < current.iData){
- isLeftChild = true;
- current = current.leftChild;
- }else{
- isLeftChild = false;
- current = current.rightChild;
- }
- if(current == null){
- return; //没有找到需要删除的数据项,直接返回
- }
- }
- //1.如果删除的节点是叶子结点,直接删除
- if(current.leftChild == null && current.rightChild == null){
- if(current == root){
- root = null;
- }else if(isLeftChild){
- parent.leftChild = null;
- }else{
- parent.rightChild = null;
- }
- }else if(current.rightChild == null){ //删除的节点只有左子节点
- if(current == root){
- root = current.leftChild;
- }else if(isLeftChild){
- parent.leftChild = current.leftChild;
- }else{
- parent.rightChild = current.leftChild ;
- }
- }else if(current.leftChild == null){ //删除的节点只有右子节点
- if(current == root){
- root = current.leftChild;
- }else if(isLeftChild){
- parent.leftChild = current.rightChild ;
- }else{
- parent.rightChild = current.rightChild ;
- }
- }else{
- Node successor = getSuccessor(current); //查找得到删除节点的后继
- if(current == root){
- root = successor;
- }else if(isLeftChild){
- parent.leftChild = successor;
- }else{
- parent.rightChild = successor;
- }
- successor.leftChild = current.leftChild; //最后一步设置删除替换后的左子节点
- }
- }
- //查找后继节点的算法
- private Node getSuccessor(Node delNode){
- Node successorParent = delNode;
- Node successor = delNode;
- Node current = delNode.rightChild;
- While(current!=null){
- successorParent = successor;
- successor = current;
- current = current.leftChild;
- }
- if(successor != delNode.rightChild){
- successorParent.leftChild = successor.rightChild;//将后继节点的父节点的左子节点值设置为后继的右子节点
- successor.rightChild = delNode.rightChild;//将后继节点的右子节点设置成当前删除节点的右子节点(处理后)
- }
- return successor;
- }
二叉树的效率
二叉树的效率:二叉树的效率取决于二叉树的层数(层数即为操作时最多的比较次数),下表给出了一个二叉满树的节点数和层数的关系,我们可以设第一列节点数为N层数为L,那么
N = 2L-1 <=> L = (log2N+1)
这里我们能换算成大O表示的时间复杂度为O(logN)。同样层数的不满的树的用时是要小于满树的时间的,树对于常用的数据存储操作有很高的效率,遍历不如其他的操作快。

JAVA数据结构之二叉树的更多相关文章
- java数据结构之二叉树的实现
java二叉树的简单实现,可以简单实现深度为n的二叉树的建立,二叉树的前序遍历,中序遍历,后序遍历输出. /** *数据结构之树的实现 *2016/4/29 * **/ package cn.Link ...
- Java数据结构之二叉树的基本介绍与递归遍历
二叉树的基本概念: 正如我们所了解的,树是有很多中形态,但是我们规定,形如每个节点最多只能有两个子节点的一种形如称为二叉树.我们将二叉树中该节点的两个子节点分别称作为:左孩子节点和右孩子节点.该节点称 ...
- java数据结构之二叉树遍历的非递归实现
算法概述递归算法简洁明了.可读性好,但与非递归算法相比要消耗更多的时间和存储空间.为提高效率,我们可采用一种非递归的二叉树遍历算法.非递归的实现要借助栈来实现,因为堆栈的先进后出的结构和递归很相似.对 ...
- java数据结构之二叉树的定义和递归实现
定义最多有两棵子树的有序树,称为二叉树.二叉树是一种特殊的树.递归定义:二叉树是n(n>=0)个有限结点构成的集合.N=0称为空二叉树:n>0的二叉树由一个根结点和两互不相交的,分别称为左 ...
- Java数据结构之树和二叉树(2)
从这里始将要继续进行Java数据结构的相关讲解,Are you ready?Let's go~~ Java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来 ...
- Java数据结构之树和二叉树
从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~ Java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来的 ...
- Java数据结构和算法 - 二叉树
前言 数据结构可划分为线性结构.树型结构和图型结构三大类.前面几篇讨论了数组.栈和队列.链表都是线性结构.树型结构中每个结点只允许有一个直接前驱结点,但允许有一个以上直接后驱结点.树型结构有树和二叉树 ...
- Java数据结构和算法(六)--二叉树
什么是树? 上面图例就是一个树,用圆代表节点,连接圆的直线代表边.树的顶端总有一个节点,通过它连接第二层的节点,然后第二层连向更下一层的节点,以此递推 ,所以树的顶端小,底部大.和现实中的树是相反的, ...
- 【java 数据结构】还不会二叉树?一篇搞定二叉树
二叉树是我们常见的数据结构之一,在学习二叉树之前我们需要知道什么是树,什么是二叉树,本篇主要讲述了二叉树,以及二叉树的遍历. 你能get到的知识点? 1.树的介绍 2.二叉树的介绍 3.二叉树遍历的四 ...
随机推荐
- android sdk 下载 最新版。。4.l
android sdk 下载 如今时间 2014.0709.,,这是最新的 64 位 windows 的 .为不能翻墙的小伙伴们准本
- true - (成功的)什么都不做
总览 (SYNOPSIS) true [忽略命令行参数] true OPTION 描述 (DESCRIPTION) 程序 结束 时, 产生 表示 成功 的 状态码. 下列的 选项 没有 简写 形式. ...
- 通过actionlib控制jaco机械臂
为了安全,先写一个简单控制三个手指的程序: 根据驱动包内kinova_fingers_action.cpp服务器写客户端程序 #include <ros/ros.h> #include & ...
- 笔记:Python列表和元组
列表 列表和字符串之间的转换 >>> li = list('hello') >>> li ['h', 'e', 'l', 'l', 'o'] >>> ...
- ASP.NET MVC 解决账号重复登录问题
解决重复登录 用到了 .net 身份票证 和Global全局处理文件 第一步 登录方法 传入用户名 private void GetOnline(string Name) { Hashtable S ...
- PHP算法之最长公共前缀
### 解题思路 方法太笨重后期优化 循环比较 循环长度利用max(最长字符串的循环) 不满住条件的截取 ### 代码 ```php class Solution { /** * @ ...
- Codeigniter 列出所有控制器和控制器的方法(类似路由列表)
我的思路是: 读取控制器文件夹下的所有 php 文件 获取父级的控制器的方法的不应该出现在每个控制器的路由中,所以需要排除父级控制器的方法 读取 控制器文件夹下的 php文件的类名和方法 下面的代碼是 ...
- gitj基础2
回滚版本 git reset --hard HEAD^ 回滚上一个版本 git reset --hard 版本号(或者版本号前6位) 回滚到指定版本 如果修改版本了,也关 ...
- delphi xe10 文件目录/路径操作 (Andorid、ios)
//获取临时文件路径(支持安卓.IOS) function GeFileName(const AFileName: string): string; begin {$IFDEF ANDROID} Re ...
- sublime上插件的安装与使用
1.插件安装的方式 插件安装方式一:直接安装 下载插件安装包后,把安装包解压到packages目录(菜单->首选项->浏览插件目录)中,完成安装 插件安装方法二:使用package con ...