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.二叉树遍历的四 ...
随机推荐
- html select美化模拟jquery插件select2.js
代码展示:http://www.51xuediannao.com/demo.php 代码说明: select2.js是一个html select美化模拟类jquery插件,但是select2.js又远 ...
- java-day27
## Bootstrap: 1. 概念: 一个前端开发的框架,Bootstrap,来自 Twitter,是目前很受欢迎的前端框架.Bootstrap 是基于 HTML.CSS.JavaScri ...
- 51-Ubuntu-打包压缩-1-打包压缩简介
打包压缩是日常工作中备份文件的一种方式 在不同操作系统中,常用的打包压缩方式是不同的 Windows 常用 rar Mac 常用 zip Linux 常用 tar.gz
- DDOS到底是什么,怎么预防,看看就明白了
可怕的DDOS怎么预防 分布式拒绝服务(DDoS: distributed denial-of-service)攻击是恶意破坏目标服务器.服务或网络的正常通信量的企图,其方法是用大量Internet通 ...
- kali环境配置
1.配置源及刷新软件列表 建议用官方默认源: # vi /etc/apt/sources.list deb http://http.kali.org/kali kali-rolling main no ...
- [牛客小白月赛18] Forsaken的数列
FHQTreap裸题... 用文艺平衡树的方法,维护区间和然后一直Push_Down就可以了(60行代码暴力AC) //张家奇怎么又AKIOI了呀,怎么CSP也满分啊...怎么清北天天给他打电话啊.. ...
- C++11 auto 与 右值
auto: auto T = xxx; // 产生一个变量,自动推导变量类型. 存在变量拷贝的消耗.auto& T = xxx; // 产生一个变量的引用,自动推导变量类型.减少拷贝的消耗. ...
- Spring框架4大原则和主要功能
Spring框架4大原则: 使用POJO进行轻量级和最小侵入式开发 POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans,是为了避免和EJ ...
- PHP算法之罗马数字转整数
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值I 1V 5X 10L 50C 100D 500M 1000例如, 罗马数字 2 写做 II ,即为两个并列的 1.12 ...
- eclipse 上Svn将项目从分支合并到主干的方法
eclipse svn 分支合并到主干 最近公司产品上线,整个系统架构包含有七八个子系统,并且子系统都是集群部署.所以每次升级维护都要确保尽可能不出问题.因为整个系统刚上线不久,意味着新系统不定期 ...