1,个人感觉二叉树的实现主要还是如何构造一颗二叉树。构造二叉树函数的设计方法多种多样,本例采用 addNode 方法实现。以下程序通过定义内部类来表示二叉树的结点,然后再实现了二叉树这种数据结构的一些基本操作。

2,说说以下程序的一些不足:

a,56行中的判断树是否为空时,依据根结点的数据域是否为空来判断。而使用不带参数的构造函数构造二叉树时,根结点的不空的,此时说明树已经有了根结点,但是根结点的数据却是空的,此时的树高度为1,但是不能访问树根结点,因为树根结点的数据域没有值。

3,重点讲解下二叉树遍历的几个方法

先序遍历:将先序遍历过程中遇到的结点添加到ArrayList<TreeNode>中。根据先序遍历的递归的性质,调用addAll(Container c)方法完成遍历主要过程。

层序遍历:层序遍历需要使用队列,方法level_Traverse 中定义了ArrayDeque<TreeNode> 类型的队列。

 package tree;

 import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue; public class BinaryTree<E> {
//为什么要用静态内部类?静态内部类中不能访问外部类的非静态成员
public static class TreeNode{
// E data;
Object data;
TreeNode left;
TreeNode right;
public TreeNode(){ }
public TreeNode(Object data){
this.data = data;
}
//构造一个新节点,该节点以left节点为其左孩子,right节点为其右孩子
public TreeNode(Object data, TreeNode left, TreeNode right){
this.data = data;
this.left = left;
this.right = right;
}
} private TreeNode root;//实现二叉树的类的数据域,即根结点来表示二叉树 public BinaryTree(){
this.root = new TreeNode();
}
//以指定的根元素创建一颗二叉树
public BinaryTree(E data){
this.root = new TreeNode(data);
} //为指定的结点添加子结点,为什么要有addNode方法?因为给定一系列的结点,通过调用该方法来构造成一颗树
public TreeNode addNode(TreeNode parent, E data, boolean isLeft){
if(parent == null)
throw new RuntimeException("父节点为空,无法添加子结点");
if(isLeft && parent.left != null)
throw new RuntimeException("节点已经左子节点,添加失败");
if(!isLeft && parent.right != null)
throw new RuntimeException("节点已经有右子节点,添加失败");
TreeNode newNode = new TreeNode(data);
if(isLeft)
parent.left = newNode;
else
parent.right = newNode;
return newNode;
} public boolean empty(){
return root.data == null;//根据根元素判断二叉树是否为空
} public TreeNode root(){
if(empty())
throw new RuntimeException("树空,无法访问根结点");
return root;
} public E parent(TreeNode node){
return null;//采用二叉树链表存储时,访问父结点需要遍历整棵二叉树,因为这里不实现
} //访问指定节点的左结点,返回的是其左孩子的数据域
public E leftChild(TreeNode parent){
if(parent == null)
throw new RuntimeException("空结点不能访问其左孩子");
return parent.left == null ? null : (E)parent.left.data;
}
public E rightChild(TreeNode parent){
if(parent == null)
throw new RuntimeException("空结点不能访问其右孩子");
return parent.right == null ? null : (E)parent.right.data;
} public int deep(){
return deep(root);
}
private int deep(TreeNode node){
if(node == null)
return 0;
else if(node.left == null && node.right == null)
return 1;
else{
int leftDeep = deep(node.left);
int rightDeep = deep(node.right);
int max = leftDeep > rightDeep ? leftDeep : rightDeep;
return max + 1;
}
} /*二叉树的先序遍历,实现思想如下:树是一种非线性结构,树中各个结点的组织方式有多种方式
* 先序,即是一种组织方式。它将结点的非线性变成了按照某种方式组织成的线性结构
*/
//返回一个list,树中结点以先序的方式存放在该list中
public List<TreeNode> preTraverse(){
return preOrderTraverse(root);
}
private List<TreeNode> preOrderTraverse(TreeNode node){
List<TreeNode> list = new ArrayList<TreeNode>();
list.add(node);
if(node.left != null)
list.addAll(preOrderTraverse(node.left));//递归的奇妙之处
if(node.right != null)
list.addAll(preOrderTraverse(node.right));
return list;
} //中序遍历
public List<TreeNode> inTraverse(){
return inOrderTraverse(root);
}
private List<TreeNode> inOrderTraverse(TreeNode node){
List<TreeNode> list = new ArrayList<TreeNode>();
if(node.left != null)
list.addAll(inOrderTraverse(node.left));
list.add(node);
if(node.right != null)
list.addAll(inOrderTraverse(node.right));
return list;
} //后序遍历
public List<TreeNode> postTraverse(){
return post_Traverse(root);
}
private List<TreeNode> post_Traverse(TreeNode node){
List<TreeNode> list = new ArrayList<TreeNode>();
if(node.left != null)
list.addAll(post_Traverse(node.left));
if(node.right != null)
list.addAll(post_Traverse(node.right));
list.add(node);
return list;
} //层序遍历
public List<TreeNode> levelTraverse(){
return level_Traverse(root);
}
private List<TreeNode> level_Traverse(TreeNode node){
Queue<TreeNode> queue = new ArrayDeque<TreeNode>();
List<TreeNode> list = new ArrayList<TreeNode>();//按层序遍历定义的顺序将树中结点依次添加到数组列表中
if(root != null)//先将根结点入队列
queue.offer(root);
while(!queue.isEmpty())//队列不空时,说明遍历还未结束
{
list.add(queue.peek());//将队头元素添加到数组列表中
TreeNode p = queue.poll();//队头元素出队列
if(p.left != null)
queue.offer(p.left);//队头元素的左孩子入队列
if(p.right != null)
queue.offer(p.right);//队头元素的右孩子入队列
}
return list;
}
}

测试遍历的程序如下:

import java.util.ArrayList;
import java.util.List; public class BinaryTreeTest {
public static void main(String[] args) {
BinaryTree<String> bt = new BinaryTree<String>("根节点");
BinaryTree.TreeNode tn1 = bt.addNode(bt.root(),"第二层左子结点", true);
BinaryTree.TreeNode tn2 = bt.addNode(bt.root(), "第二层右子结点", false);
BinaryTree.TreeNode tn3 = bt.addNode(tn2,"第三层左子结点",true); List<BinaryTree.TreeNode> list1 = new ArrayList<BinaryTree.TreeNode>();
list1 = bt.inTraverse();
System.out.println("inorder traverse");
for(BinaryTree.TreeNode node : list1)
System.out.print(node.data + " "); List<BinaryTree.TreeNode> list2 = new ArrayList<BinaryTree.TreeNode>();
list2 = bt.preTraverse();
System.out.println("\n preorder traverse");
for(BinaryTree.TreeNode node : list2)
System.out.print(node.data + " ");
List<BinaryTree.TreeNode> list3 = new ArrayList<BinaryTree.TreeNode>();
list3 = bt.levelTraverse();
System.out.println("\n level traverse");
for(BinaryTree.TreeNode node : list3)
System.out.println(node.data + " ");
}
}

JAVA实现二叉树(简易版--实现了二叉树的各种遍历)的更多相关文章

  1. Java 语言实现简易版扫码登录

    基本介绍 相信大家对二维码都不陌生,生活中到处充斥着扫码登录的场景,如登录网页版微信.支付宝等.最近学习了一下扫码登录的原理,感觉蛮有趣的,于是自己实现了一个简易版扫码登录的 Demo,以此记录一下学 ...

  2. 自己实现IOC容器,java代码实现简易版IOC容器,IOC容器实现的步骤分解

    一.需求 实现一个简易的IOC容器,管理Bean,从IOC容器的BeanFactory中获取实例,从而取代自己new实例的做法. 二.实现步骤分析 三.具体代码实现 自定义注解类 MyComponen ...

  3. Java与Scala的两种简易版连接池

    Java版简易版连接池: import java.sql.Connection; import java.sql.DriverManager; import java.util.LinkedList; ...

  4. 【Java】 大话数据结构(9) 树(二叉树、线索二叉树)

    本文根据<大话数据结构>一书,对Java版的二叉树.线索二叉树进行了一定程度的实现. 另: 二叉排序树(二叉搜索树) 平衡二叉树(AVL树) 二叉树的性质 性质1:二叉树第i层上的结点数目 ...

  5. C语言实现二叉树-02版

    ---恢复内容开始--- 昨天,提交完我们的二叉树项目后,今天早上项目经理早早给我打电话: 他说,小伙子干的不错.但是为什么你上面的insert是recusive的呢? 你难道不知道万一数据量大啦!那 ...

  6. 数据结构二叉树的java实现,包括二叉树的创建、搜索、删除和遍历

    根据自己的学习体会并参考了一些网上的资料,以java写出了二叉树的创建.搜索.删除和遍历等操作,尚未实现的功能有:根据先序和中序遍历,得到后序遍历以及根据后序和中序遍历,得到先序遍历,以及获取栈的深度 ...

  7. 【Java】 剑指offer(37) 序列化二叉树

    本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 请实现两个函数,分别用来序列化和反序列化二叉树. 思路 一般情况下 ...

  8. C#二叉树简易实例

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Cons ...

  9. Java八股文纯享版——篇①:Java基础

    注: 1.笔记为个人归纳整理,尽力保证准确性,如有错误,恳请指正 2.写文不易,转载请注明出处 3.本文首发地址 https://blog.leapmie.com/archives/b8fe0da9/ ...

随机推荐

  1. Win10 1803 Spring Creators update Consumer edition的版本记录

    安装时可选择的版本列表 安装完之后的版本: 3. 时间线更新 4. Focus assistant

  2. hive数据查询

    Fetch task 丢弃了mapreduce的作业的繁重任务,查询方便简单 1.第一种方式 2.linux命令行 3.地3中

  3. Java之Array(数组)说明

    代码说明: package array; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** ...

  4. python之tkinter使用-消息弹框

    # messagebox:消息弹框 # 不断点击按钮,切换各种弹窗 import tkinter as tk from tkinter import messagebox from tk_center ...

  5. indicator function指示函数

    指示函数   在集合论中,指示函数是定义在某集合X上的函数,表示其中有哪些元素属于某一子集A. 中文名 指示函数 外文名 indicator function 相关学科 数学.组合数学 其他称呼 特征 ...

  6. mybatis 一对多的注入 指的是连表查询时候 将不同的查询结果以列表存储对象形式 注入进去 多对一指的是 查询多条结果但都是一样的 只需注入一条

    mybatis 一对多的注入 指的是连表查询时候 将不同的查询结果以列表存储对象形式 注入进去 多对一指的是 查询多条结果但都是一样的 只需注入一条

  7. docker --swarm创建一个集群

    如果搭建错误可以强制脱离集群网络: docker swarm leave --force 初始化集群网络管理节点: docker swarm init --advertise-addr 10.101. ...

  8. BZOJ3425[POI2013]Polarization——DP+bitset+分块

    题目描述 Everyone knew it would only be a matter of time. So what? Faced for years on, a peril becomes t ...

  9. BZOJ3653谈笑风生——可持久化线段树+dfs序

    题目描述 设T 为一棵有根树,我们做如下的定义: ? 设a和b为T 中的两个不同节点.如果a是b的祖先,那么称“a比b不知道 高明到哪里去了”. ? 设a 和 b 为 T 中的两个不同节点.如果 a ...

  10. MT【4】坐标平移后齐次化

    简答:通过坐标平移可以将A点移到原点,设BC:mx’+ny’=1,联立坐标变换后的椭圆方程和BC,将$\frac{y}{x}$看成斜率k,得到关于k的一元二次方程,由题意两根之积为-1,可得.