JAVA实现二叉树(简易版--实现了二叉树的各种遍历)
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实现二叉树(简易版--实现了二叉树的各种遍历)的更多相关文章
- Java 语言实现简易版扫码登录
基本介绍 相信大家对二维码都不陌生,生活中到处充斥着扫码登录的场景,如登录网页版微信.支付宝等.最近学习了一下扫码登录的原理,感觉蛮有趣的,于是自己实现了一个简易版扫码登录的 Demo,以此记录一下学 ...
- 自己实现IOC容器,java代码实现简易版IOC容器,IOC容器实现的步骤分解
一.需求 实现一个简易的IOC容器,管理Bean,从IOC容器的BeanFactory中获取实例,从而取代自己new实例的做法. 二.实现步骤分析 三.具体代码实现 自定义注解类 MyComponen ...
- Java与Scala的两种简易版连接池
Java版简易版连接池: import java.sql.Connection; import java.sql.DriverManager; import java.util.LinkedList; ...
- 【Java】 大话数据结构(9) 树(二叉树、线索二叉树)
本文根据<大话数据结构>一书,对Java版的二叉树.线索二叉树进行了一定程度的实现. 另: 二叉排序树(二叉搜索树) 平衡二叉树(AVL树) 二叉树的性质 性质1:二叉树第i层上的结点数目 ...
- C语言实现二叉树-02版
---恢复内容开始--- 昨天,提交完我们的二叉树项目后,今天早上项目经理早早给我打电话: 他说,小伙子干的不错.但是为什么你上面的insert是recusive的呢? 你难道不知道万一数据量大啦!那 ...
- 数据结构二叉树的java实现,包括二叉树的创建、搜索、删除和遍历
根据自己的学习体会并参考了一些网上的资料,以java写出了二叉树的创建.搜索.删除和遍历等操作,尚未实现的功能有:根据先序和中序遍历,得到后序遍历以及根据后序和中序遍历,得到先序遍历,以及获取栈的深度 ...
- 【Java】 剑指offer(37) 序列化二叉树
本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集 题目 请实现两个函数,分别用来序列化和反序列化二叉树. 思路 一般情况下 ...
- C#二叉树简易实例
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Cons ...
- Java八股文纯享版——篇①:Java基础
注: 1.笔记为个人归纳整理,尽力保证准确性,如有错误,恳请指正 2.写文不易,转载请注明出处 3.本文首发地址 https://blog.leapmie.com/archives/b8fe0da9/ ...
随机推荐
- add (db.collection.add)添加数据
db.collection('cheshi').add({ data: { cheshi:4, } }).then((res) => { console.log(res) })
- git 快捷键
实际上就是弄了个别名 $ git config --global alias.st status $ git config --global alias.ci commit $ git config ...
- PHP的安装,编译,扩展工具
1.基本容易混淆的概念 pecl php的社区贡献扩展库,全称为PHP Extension Community Library, 是php的底层库, 使用C语言编写 pear php的应用扩展库,全称 ...
- Lodop如何设置预览后导出带背景的图,打印不带背景图
Lodop中的ADD_PRINT_SETUP_BKIMG,可以加载上背景图,该背景图在预览的时候可以显示也可以不显示,打印可以打印出来也可以不打印出来.一般套打,都是不打印背景图的,比如一些快递的快递 ...
- linux上搭建nginx
安装包:(按顺序执行过去即可,重复无所谓)c++编译环境 yum install gcc-c++ 安装pcre yum -y install pcre-devel 安装openssl yum -y i ...
- Git储藏与恢复
cd /f cd android git status echo 'shoping' >> 4 //修改内容 git status git stash //git储藏 git status ...
- MT【58】反演圆和极线极点和谐统一
解答:如图 评:1.反演圆及其性质介绍: 评2:此题的源头是1995年全国卷压轴题,这里用极线极点的相关性质也可以处理: 注:用相关点法很容易得到轨迹.
- 【题解】 bzoj2006: [NOI2010]超级钢琴 (ST表+贪心)
题面戳我 Solution 不会,看的题解 Attention 哇痛苦,一直不会打\(ST\)表,我是真的菜啊qwq 预处理 Log[1]=0;two[0]=1; for(int i=2;i<= ...
- Matlab 沿三维任意方向切割CT图的仿真计算
一.数据来源 头部组织的数据.此处直接引用了matlab自带的mri数据.实际场景中,可以通过CT得到的数据进行转换得到 插入异物的数据.此处我假设插入异物为一根细铁丝.模拟为空间中的一条曲线.这个曲 ...
- SDL源码阅读笔记(1) 基本模块
write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie 前言 对于大牛来说,写关于阅读源码的文章都会叫源码剖析或者深入浅出啥的,对于我,自己阅读阅读源码,写 ...