Java中树和树的几种常规遍历方法
其中包含有先序遍历、中序遍历、后序遍历以及广度优先遍历四种遍历树的方法:
package com.ietree.basic.datastructure.tree.binarytree; import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue; /**
* Created by ietree
* 2017/5/1
*/
public class ThreeLinkBinTree<E> { public static class TreeNode { Object data;
TreeNode left;
TreeNode right;
TreeNode parent; public TreeNode() { } public TreeNode(Object data) {
this.data = data;
} public TreeNode(Object data, TreeNode left, TreeNode right, TreeNode parent) {
this.data = data;
this.left = left;
this.right = right;
this.parent = parent;
} } private TreeNode root; // 以默认的构造器创建二叉树
public ThreeLinkBinTree() {
this.root = new TreeNode();
} // 以指定根元素创建二叉树
public ThreeLinkBinTree(E data) {
this.root = new TreeNode(data);
} /**
* 为指定节点添加子节点
*
* @param parent 需要添加子节点的父节点的索引
* @param data 新子节点的数据
* @param isLeft 是否为左节点
* @return 新增的节点
*/
public TreeNode addNode(TreeNode parent, E data, boolean isLeft) { if (parent == null) {
throw new RuntimeException(parent + "节点为null, 无法添加子节点");
}
if (isLeft && parent.left != null) {
throw new RuntimeException(parent + "节点已有左子节点,无法添加左子节点");
}
if (!isLeft && parent.right != null) {
throw new RuntimeException(parent + "节点已有右子节点,无法添加右子节点");
} TreeNode newNode = new TreeNode(data);
if (isLeft) {
// 让父节点的left引用指向新节点
parent.left = newNode;
} else {
// 让父节点的left引用指向新节点
parent.right = newNode;
}
// 让新节点的parent引用到parent节点
newNode.parent = parent;
return newNode;
} // 判断二叉树是否为空
public boolean empty() {
// 根据元素判断二叉树是否为空
return root.data == null;
} // 返回根节点
public TreeNode root() {
if (empty()) {
throw new RuntimeException("树为空,无法访问根节点");
}
return root;
} // 返回指定节点(非根节点)的父节点
public E parent(TreeNode node) {
if (node == null) {
throw new RuntimeException("节点为null,无法访问其父节点");
}
return (E) node.parent.data;
} // 返回指定节点(非叶子)的左子节点,当左子节点不存在时返回null
public E leftChild(TreeNode parent) {
if (parent == null) {
throw new RuntimeException(parent + "节点为null,无法添加子节点");
}
return parent.left == null ? null : (E) parent.left.data;
} // 返回指定节点(非叶子)的右子节点,当右子节点不存在时返回null
public E rightChild(TreeNode parent) {
if (parent == null) {
throw new RuntimeException(parent + "节点为null,无法添加子节点");
}
return parent.right == null ? null : (E) parent.right.data;
} // 返回该二叉树的深度
public int deep() {
// 获取该树的深度
return deep(root);
} // 这是一个递归方法:每一棵子树的深度为其所有子树的最大深度 + 1
private int deep(TreeNode node) {
if (node == null) {
return 0;
}
// 没有子树
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;
// 返回其左右子树中较大的深度 + 1
return max + 1;
}
} // 实现先序遍历
// 1、访问根节点
// 2、递归遍历左子树
// 3、递归遍历右子树
public List<TreeNode> preIterator() {
return preIterator(root);
} private List<TreeNode> preIterator(TreeNode node) { List<TreeNode> list = new ArrayList<TreeNode>();
// 处理根节点
list.add(node); // 递归处理左子树
if (node.left != null) {
list.addAll(preIterator(node.left));
} // 递归处理右子树
if (node.right != null) {
list.addAll(preIterator(node.right));
} return list; } // 实现中序遍历
// 1、递归遍历左子树
// 2、访问根节点
// 3、递归遍历右子树
public List<TreeNode> inIterator() {
return inIterator(root);
} private List<TreeNode> inIterator(TreeNode node) { List<TreeNode> list = new ArrayList<TreeNode>(); // 递归处理左子树
if (node.left != null) {
list.addAll(inIterator(node.left));
} // 处理根节点
list.add(node); // 递归处理右子树
if (node.right != null) {
list.addAll(inIterator(node.right));
} return list; } // 实现后序遍历
// 1、递归遍历左子树
// 2、递归遍历右子树
// 3、访问根节点
public List<TreeNode> postIterator() {
return postIterator(root);
} private List<TreeNode> postIterator(TreeNode node) { List<TreeNode> list = new ArrayList<TreeNode>(); // 递归处理左子树
if (node.left != null) {
list.addAll(postIterator(node.left));
} // 递归处理右子树
if (node.right != null) {
list.addAll(postIterator(node.right));
} // 处理根节点
list.add(node); return list; } // 实现广度优先遍历
// 广度优先遍历又称为按层遍历,整个遍历算法先遍历二叉树的第一层(根节点),再遍历根节点的两个子节点(第二层),以此类推
public List<TreeNode> breadthFirst() { Queue<TreeNode> queue = new ArrayDeque<TreeNode>();
List<TreeNode> list = new ArrayList<TreeNode>();
if (root != null) {
// 将根元素加入“队列”
queue.offer(root);
}
while (!queue.isEmpty()) {
// 将该队列的“队尾”的元素添加到List中
list.add(queue.peek());
TreeNode p = queue.poll();
// 如果左子节点不为null,将它加入“队列”
if (p.left != null) {
queue.offer(p.left);
}
// 如果右子节点不为null,将它加入“队列”
if (p.right != null) {
queue.offer(p.right);
}
}
return list;
} }
Java中树和树的几种常规遍历方法的更多相关文章
- Java中获取键盘输入值的三种方法
Java中获取键盘输入值的三种方法 Java程序开发过程中,需要从键盘获取输入值是常有的事,但Java它偏偏就没有像c语言给我们提供的scanf(),C++给我们提供的cin()获取键盘输入值 ...
- Java中从控制台输入数据的几种常用方法
Java中从控制台输入数据的几种常用方法 一.使用标准输入串System.in //System.in.read()一次只读入一个字节数据,而我们通常要取得一个字符串或一组数字 //System.in ...
- Java中的ReentrantLock和synchronized两种锁定机制的对比
问题:多个访问线程将需要写入到文件中的数据先保存到一个队列里面,然后由专门的 写出线程负责从队列中取出数据并写入到文件中. http://blog.csdn.net/top_code/article/ ...
- Java 集合 ArrayList和LinkedList的几种循环遍历方式及性能对比分析 [ 转载 ]
Java 集合 ArrayList和LinkedList的几种循环遍历方式及性能对比分析 @author Trinea 原文链接:http://www.trinea.cn/android/arrayl ...
- JavaScript 中的12种循环遍历方法
原文:JavaScript 中的12种循环遍历方法 题目:请介绍 JavaScript 中有哪些循环和遍历的方法,说说它们的应用场景和优缺点? 1.for 循环 let arr = [1,2,3];f ...
- java中调用dll文件的两种方法
一中是用JNA方法,另外是用JNative方法,两种都是转载来的, JNA地址:http://blog.csdn.net/shendl/article/details/3589676 JNativ ...
- 【转】Java中super和this的几种用法与区别
1. 子类的构造函数如果要引用super的话,必须把super放在函数的首位. class Base { Base() { System.out.println("Base&qu ...
- Java中的内存泄露的几种可能
Java内存泄漏引起的原因: 内存泄漏是指无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放,从而造成内存空间的浪费称为内存泄漏. 长生命周期的对象持有短生命周期对象的引用就很可能发 ...
- Java中创建实例化对象的几种方式
Java中创建实例化对象有哪些方式? ①最常见的创建对象方法,使用new语句创建一个对象.②通过工厂方法返回对象,例:String s =String.valueOf().(工厂方法涉及到框架)③动用 ...
随机推荐
- finals的使用
//----------------------------------------Finals--------------------------- public class Finals { pu ...
- 01 awk工具的使用
一:登录mysql后查看mysql的连接状态:show status ; 回车 如图所示: |Threads_connected | 1| Threads_running | 1 ...
- 关于VS2013编辑器的问题
如果输出报错 This function or variable may be unsafe. 解决方法 1.用VS2013打开出现错误的代码文件 2.在工程文件名处右击鼠标打开快捷菜单,找到“属性” ...
- 关于spring中注解和xml混合使用
可以混合用.文档有说明: Spring can accommodate both styles and even mix them together. 混合用的话,有个先后顺序,xml配置会覆盖ann ...
- 【BZOJ】1079: [SCOI2008]着色方案(dp+特殊的技巧)
http://www.lydsy.com/JudgeOnline/problem.php?id=1079 只能想到5^15的做法...........................果然我太弱. 其实 ...
- linux下面bin,sbin不理解的查阅
在一下的文件中得到答案, 突然想想自己有点傻,自己有代码,为什么不自己查看一下代码呢 http://blog.csdn.net/ithomer/article/details/9839957
- Amazon(vpc)对等网络
对等连接测试 1.1 东京账户A创建对等连接 注意,双方的vpc网段不能重复,如果重复会造成无法配置路由表 输入双方信息 账户ID和VPC 1.2 东京账户A查看 查看连接信息 显示正在处理接受,需要 ...
- Hibernate_day04--课程安排_Hibernate查询方式_对象导航查询_OID查询
Hibernate_day04 上节内容 今天内容 Hibernate查询方式 对象导航查询 OID查询 HQL查询 查询所有 条件查询 排序查询 分页查询 投影查询 聚集函数使用 QBC查询 查询所 ...
- UnboundLocalError: local variable 'merchantCode' referenced before assignment
问题描述:变量赋值前未定义 定位原因:变量没有结果返回,导致赋值失败
- cocos lua 加密方案
cocos2d使用的是luajit,lua原生编译出来的bytecode和luajit是不兼容的,所以直接用luac法编译出来的bytecode脚本无法在cocos2d中使用. 目前所指的解决方案有2 ...