(tree)是一种抽象数据类型(ADT),用来模拟具有树状结构性质的数据集合。它是由n(n>0)个有限节点通过连接它们的组成一个具有层次关系的集合

  

  • 节点:上图的圆圈,比如A,B,C等都是表示节点。节点一般代表一些实体,在java面向对象编程中,节点一般代表对象。

  • 边:连接节点的线称为边,边表示节点的关联关系。一般从一个节点到另一个节点的唯一方法就是沿着一条顺着有边的道路前进。在Java当中通常表示引用。

  • 每个节点最多只能有两个子节点的一种形式称为二叉树

一、树的基本概念

  • 路径:顺着节点的边从一个节点走到另一个节点,所经过的节点的顺序排列就称为“路径”。

  • :树顶端的节点称为根。一棵树只有一个根,如果要把一个节点和边的集合称为树,那么从根到其他任何一个节点都必须有且只有一条路径。A是根节点。

  • 父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;B是D的父节点。

  • 子节点:一个节点含有的子树的根节点称为该节点的子节点;D是B的子节点。

  • 兄弟节点:具有相同父节点的节点互称为兄弟节点;比如上图的D和E就互称为兄弟节点。

  • 叶节点:没有子节点的节点称为叶节点,也叫叶子节点,比如上图的H、E、F、G都是叶子节点。

  • 子树:每个节点都可以作为子树的根,它和它所有的子节点、子节点的子节点等都包含在子树中。

  • 节点的层次:从根开始定义,根为第一层,根的子节点为第二层,以此类推。

  • 深度:对于任意节点n,n的深度为从根到n的唯一路径长,根的深度为0;

  • 高度:对于任意节点n,n的高度为从n到一片树叶的最长路径长,所有树叶的高度为0,即最大层数

二、二叉树的遍历

  • 二叉树:每个节点最多只有两个子节点的树

  • 如果二叉树的所有叶子节点都在最后一层,并且节点总数= 2^n -1,n 为层数,则该树为满二叉树

  • 如果二叉树的所有叶子节点都在最后一层或倒数第二层,并且最后一层的叶子节点在左边连续,倒数第二层的叶子节点在右边连续,则称为完全二叉树

  • 二叉树的遍历方式有三种:

    • 前序遍历: 根,左,右

    • 中序遍历: 左,根,右

    • 后序遍历:左,右,根

  • 二叉树的建立和添加 ,这里以二叉排序数为例
public class TreeNodeTest {
public static void main(String[] args) {
int[] arr={5,4,7,9,2,6,3};
TreeNode tree = new TreeNode();
for (int i=0;i<arr.length;i++){
tree.add(new Node(arr[i]));
}
}
}
class TreeNode{
Node root;//根节点
public TreeNode() {
}
public void add(Node node){
if (node==null) return;
if (root==null) {root=node;return;}
else root.add(node);
} public void prefix() {
if (root==null) return;
else root.prefix();
}
}
class Node{
int val; //节点值
Node left;// 左节点
Node right; // 右节点 public Node(int val) {
this.val = val;
} public void add(Node node) {
if (node==null)return;
if (node.val<val) {
if (left==null){left=node;return;}
else left.add(node);}
else {
if(right==null) {right=node;return;}
else right.add(node);
}
}
}

三、递归前、中、后序遍历

  • 前序遍历递归步骤:先输出当前节点,如果左子树不为空,向左递归;如果右子树不为空,向右递归
  • 中序遍历递归步骤:如果左子树不为空,向左递归;输出当前节点;如果右子树不为空,向右递归
  • 后序遍历递归步骤:如果左子树不为空,向左递归;如果右子树不为空,向右递归;输出当前节点  
//TreeNode类下
//前序递归遍历
public void preOrder() {
if (this.root!=null) this.root.preOrder();
else System.out.println("根节点为空");
}
//中序递归遍历
public void infixOrder() {
if (this.root!=null) this.root.infixOrder();
else System.out.println("根节点为空");
}
//后序递归遍历
public void postOrder() {
if (this.root!=null) this.root.postOrder();
else System.out.println("根节点为空");
}
//Node类下 //前序递归遍历
public void preOrder() {
System.out.print(this.val+ " ");
if (this.left!=null) this.left.preOrder();
if (this.right!=null)this.right.preOrder(); }
//中序递归遍历
public void infixOrder() {
if (this.left!=null) this.left.infixOrder();
System.out.print(this.val+ " ");
if (this.right!=null)this.right.infixOrder();
}
//后序递归遍历
public void postOrder() {
if (this.left!=null) this.left.postOrder();
if (this.right!=null)this.right.postOrder();
System.out.print(this.val+ " ");
}

四、非递归前中后序遍历

  • 前序遍历思路:利用一个栈来实现先序遍历

    • 根节点入栈
    • 判断栈是否为空,如果不为空,弹出栈顶元素并打印
    • 如果有右子树,压栈
    • 如果有左子树,压栈
    • 如果栈为空,程序结束
 public void prefix() {
Stack<Node> s= new Stack<>();
s.push(this);
while (!s.isEmpty()){
Node node = s.pop();
System.out.print(node.val+"-->");
if(node.right!=null) s.push(node.right);
if(node.left!=null) s.push(node.left);
}
}
  • 中序遍历思路:利用一个栈来实现先序遍历,左根右

    • 根节点入栈

    • 如果节点不为空,压栈,沿着左子树走一步

    • 如果节点为空,则出栈,打印,沿着右子树走一步

    • 如果栈为空且当前节点为空,则结束

//中序遍历
public void infixOrder() {
//非递归
Stack<Node> s=new Stack<>();
Node node= this;
while (!s.isEmpty()||node!=null){
if (node!=null){
s.push(node);
node=node.left;
}
else {
node=s.pop();
System.out.print(node.val+ " ");
node=node.right;
}
}
}
  • 后序遍历思路:利用2个栈来实现后序遍历

    • 申请两个栈s1,s2,头节点入栈s1

    • 如果栈s1不为空,执行以下操作:弹出一个元素,入栈s2,

    • 如果该节点左孩子不空,入栈s1,如果该节点右孩子不空入栈s1

    • 将栈s2中的节点一次出栈,打印

public void postOrder() {
//非递归
Stack<Node> s1=new Stack<>();
Stack<Node> s2=new Stack<>();
s1.push(this);
while(!s1.isEmpty()){
Node node = s1.pop();
s2.push(node);
if (node.left!=null) s1.push(node.left);
if (node.right!=null) s1.push(node.right);
}
while (!s2.isEmpty())
System.out.print(s2.pop().val+ " "); // 一种栈实现
/*
Stack<Node> s=new Stack<>();
Node node= this;
Node lastnode= null;
while (node!=null){
s.push(node); //将所有左节点入栈
node=node.left;
}
while(!s.isEmpty()){
node=s.pop();
//一个根节点被访问的前提是:无右子树或右子树已被访问过
if (node.right!=null&&node.right!=lastnode){
s.push(node);
node=node.right;
while (node!=null)
{ s.push(node);
node=node.left;}
} else {
System.out.print(node.val+ " ");
lastnode=node;
}
}
*/
}

五、前中序查找

  • 前序查找:

    • 先判断当前节点值是否为查找值,如果是返回当前节点
    • 判断当前节点的左子节点是否为空,如果不为空,左子树递归前序查找
    • 如果左递归返回的值不为空,说明找到,返回该节点
    • 否则判断当前节点是否有右子节点,如果有,右子树递归前序查找
  • 中序查找:
    • 判断当前节点的左子节点是否为空,如果不为空,左子树递归中序查找
    • 如果左递归返回的值不为空,说明找到,返回该节点
    • 否则判断当前节点值是否为查找值,如果是返回当前节点
    • 否则判断当前节点是否有右子节点,如果有,右子树递归中序查找
  • 后序递归查找
    • 判断当前节点的左子节点是否为空,如果不为空,左子树递归后序查找
    • 如果左递归返回的值不为空,说明找到,返回该节点
    • 否则判断当前节点是否有右子节点,如果有,右子树递归后序查找
    • 如果右递归返回的值不为空,说明找到,返回该节点
    • 否则判断当前节点值是否为查找值,如果是返回当前节点
  //前序递归查找
public TreeNode preOrderSearch(int val) {
System.out.println("前序递归查找");
if(this.val==val) {return this;}
TreeNode node = null;
if (this.left!=null){node=this.left.preOrderSearch(val);}
if (node!=null) return node;
//1.左递归前序查找,找到结点,则返回,否继续判断,
//2.当前的结点的右子节点是否为空,如果不空,则继续向右递归前序查找
if (this.right!=null){node=this.right.preOrderSearch(val);}
return node; }
//中序递归查找
public TreeNode infixOrderSearch(int val) {
TreeNode node = null;
//1.左递归前序查找,找到结点,则返回,否继续判断,
if (this.left!=null){node=this.left.infixOrderSearch(val);}
if (node!=null) return node;
System.out.println("中序递归查找");
if(this.val==val) {return this;}
//2.当前的结点的右子节点是否为空,如果不空,则继续向右递归前序查找
if (this.right!=null){node=this.right.infixOrderSearch(val);}
return node;
}
//后序递归查找
public TreeNode postOrderSearch(int val) {
TreeNode node = null;
//1.左递归前序查找,找到结点,则返回,否继续判断,
if (this.left!=null){node=this.left.postOrderSearch(val);}
if (node!=null) return node;
if (this.right!=null){node=this.right.postOrderSearch(val);}
if (node!=null) return node;
System.out.println("后序递归查找");
if(this.val==val) {return this;}
return node;
}

 

  

java二叉树的遍历(1)的更多相关文章

  1. 毕业了-java二叉树层次遍历算法

    /*************************************** * 时间:2017年6月23日 * author:lcy * 内容:二叉树的层次遍历 * 需要借助队列这个数据结构,直 ...

  2. java 二叉树递归遍历算法

    //递归中序遍历 public void inorder() { System.out.print("binaryTree递归中序遍历:"); inorderTraverseRec ...

  3. java树的遍历

    java二叉树的遍历算法: http://blog.sina.com.cn/s/blog_70600f720100ujnp.html

  4. 【Java】 二叉树的遍历(递归与循环+层序遍历)

    在[Java] 大话数据结构(9) 树(二叉树.线索二叉树)一文中,已经实现了采用递归方法的前.中.后序遍历,本文补充了采用循环的实现方法.以及层序遍历并进行了一个总结. 递归实现 /* * 前序遍历 ...

  5. 二叉树 Java 实现 前序遍历 中序遍历 后序遍历 层级遍历 获取叶节点 宽度 ,高度,队列实现二叉树遍历 求二叉树的最大距离

    数据结构中一直对二叉树不是很了解,今天趁着这个时间整理一下 许多实际问题抽象出来的数据结构往往是二叉树的形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显 ...

  6. 【LeetCode-面试算法经典-Java实现】【107-Binary Tree Level Order Traversal II(二叉树层序遍历II)】

    [107-Binary Tree Level Order Traversal II(二叉树层序遍历II)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 Given a ...

  7. 数据结构Java版之遍历二叉树(六)

    二叉树是我们在程序中用的最多的一种树(个人观点).最简单的一个二叉树是由一个根节点,两个子节点(一左一右成左右孩子节点)组成.二叉树是数组和链表的结合,即包含了数组的快速查找优点,又包含了链表的快速添 ...

  8. Java数据结构——二叉树的遍历(汇总)

    二叉树的遍历分为深度优先遍历(DFS)和广度优先遍历(BFS) DFS遍历主要有: 前序遍历 中序遍历 后序遍历 一.递归实现DFSNode.java: public class Node { pri ...

  9. Java 二叉树遍历右视图-LeetCode199

    题目如下: 题目给出的例子不太好,容易让人误解成不断顺着右节点访问就好了,但是题目意思并不是这样. 换成通俗的意思:按层遍历二叉树,输出每层的最右端结点. 这就明白时一道二叉树层序遍历的问题,用一个队 ...

随机推荐

  1. [Distributed ML] Parameter Server & Ring All-Reduce

    Resource ParameterServer入门和理解[较为详细,涉及到另一个框架:ps-lite] 一文读懂「Parameter Server」的分布式机器学习训练原理 并行计算与机器学习[很有 ...

  2. Jmeter- 笔记1 - 理论知识

    为什么不用loadrunner,lonadrunner免费最大并发用户50,再往上就要买license了. 性能输出结果不是bug 假如调试脚本没有出错,但运行脚本时,可能前期没有问题,但到后期偶尔/ ...

  3. Camera HDR Algorithms

    Camera HDR Algorithms HDRI是High-Dynamic Range(HDR)image的缩写,也就是高动态范围图像.它就是为了解决更好的存储高动态范围图像这个问题而发明出来的. ...

  4. Paddle预训练模型应用工具PaddleHub

    Paddle预训练模型应用工具PaddleHub 本文主要介绍如何使用飞桨预训练模型管理工具PaddleHub,快速体验模型以及实现迁移学习.建议使用GPU环境运行相关程序,可以在启动环境时,如下图所 ...

  5. Jittor框架API

    Jittor框架API 这里是Jittor主模块的API文档,可以通过import jittor来获取该模块. classjittor.ExitHooks exc_handler(exc_type,  ...

  6. 深度学习加速器堆栈Deep Learning Accelerator Stack

    深度学习加速器堆栈Deep Learning Accelerator Stack 通用张量加速器(VTA)是一种开放的.通用的.可定制的深度学习加速器,具有完整的基于TVM的编译器堆栈.设计了VTA来 ...

  7. VB 老旧版本维护系列---读取xml某个节点的值

    读取xml某个节点的值 '定义xml字符串内容地址 Dim xmlFileStr As String = "" '定义所需读取节点的名称 Dim readNodeName As S ...

  8. redis 记一次搭建高可用redis集群过程,问题解决;Node 192.168.184.133:8001 is not configured as a cluster node

    ------------恢复内容开始------------ 步骤 1:每台redis服务器启动之后,需要将这几台redis关联起来, 2: 关联命令启动之后 报错: Node 192.168.184 ...

  9. CentOS 7服务管理

    CentOS 6 使用service 管理指令: service 服务名 [start | stop | restart | reload | status] 但在 CentOS7.0 后 不再使用 ...

  10. 学习响应式编程 Reactor (5) - reactor 转换类操作符(2)

    Reactor 操作符 上篇文章我们将 Flux 和 Mono 的操作符分了 11 类,我们来继续学习转换类操作符的第 2 篇. 转换类操作符 转换类的操作符数量最多,平常过程中也是使用最频繁的. F ...