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. dotnet core的下载地址 以及sdk和runtime的 version 简单说明

    1. dotnet core 2.1 的下载地址 https://dotnet.microsoft.com/download/dotnet-core/2.1 2. dotnet core 2.2 的下 ...

  2. php 7.1 openssl_decrypt() 代替 mcrypt_module_open() 方法

    公司开发微信第三方平台,之前用着一直是没有问题的.后来服务器到期进行项目搬迁就怎么也接收不到微信每10分钟的ticketle. 经过调试发现php版本由原来的7.0升到了7.1(该死....为什么没人 ...

  3. React state状态

    <!DOCTYPE html><html><head lang="en"> <meta charset="UTF-8" ...

  4. Python模块笔记

    __name__属性 一个模块被另一个程序第一次引入时,其主程序将运行.如果我们想在模块被引入时,模块中的某一程序块不执行,我们可以用__name__属性来使该程序块仅在该模块自身运行时执行. #!/ ...

  5. Ideal test 不执行main方法了

    参考:idea 导入项目后不能执行main方法 用了ideal之后,发现自己的项目里面没有test文件夹,自己建了一个,发现竟然不能执行main函数, 后来经过点播之后,才知道,光建立文件夹是没用的, ...

  6. CnPack实用功能推荐

    已经使用CnPack好几年了,这个插件太好了,现在离开它我都不会写代码了,现在将使用心得与大家分享一下: 1.代码助手非常好用,只需要输入几个字符后,自动出现提示列表,真是懒人的福音呀. 2.代码高亮 ...

  7. selenium之批量执行测试用例生成HTML结果文件

    使用HTMLTestRunner运行测试套件,自动生成html测试报告: import unittest, HTMLTestRunner, sendmail_html import time, os ...

  8. Luogu4221 WC2018州区划分(状压dp+FWT)

    合法条件为所有划分出的子图均不存在欧拉回路或不连通,也即至少存在一个度数为奇数的点或不连通.显然可以对每个点集预处理是否合法,然后就不用管这个奇怪的条件了. 考虑状压dp.设f[S]为S集合所有划分方 ...

  9. ueditor 使用

    之前在微信上用到富文本编辑器,选用了ueditor 之后又在项目中使用到了,因此打算写下来记录一下. 1  首先去下载ueditor 2  我的是 MVC项目,贴一下:粘贴到Content下 3 然后 ...

  10. Scout YYF I POJ - 3744(概率dp + 矩阵快速幂)

    题意: 一条路上有n个地雷,你从1开始走,单位时间内有p的概率走一步,1-p的概率走两步,问安全通过这条路的概率 解析: 很容易想到 dp[i] = p * dp[i-1] + (1 - p) * d ...