树的简介及Java实现
一、树的基本知识
树是一种数据结构,它是由n(n>=1)个有限结点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:每个结点有零个或多个子结点;没有父结点的结点称为根结点;每一个非根结点有且只有一个父结点;除了根结点外,每个子结点可以分为多个不相交的子树;
 import java.util.List;
 public class TreeNode<E> {
     public E key;// data
     public TreeNode<E> parent;// parent
     public List<TreeNode<E>> children;// children
     public TreeNode(E key, TreeNode<E> parent) {
         this.key = key;
         this.parent = parent;
     }
     public TreeNode(E key) {
         this.key = key;
     }
     @Override
     public String toString() {
         return "BSTNode [key=" + key + "]";
     }
 }
2、树的接口类:
 import java.util.List;
 public interface ITree<E> {
   /**
    * 节点数
    * @return
    */
   int getSize();
   /**
    * 获取根节点
    * @return
    */
   TreeNode<E> getRoot();
   /**
    * 获取x的父节点
    * @param x
    * @return
    */
   TreeNode<E> getParent(TreeNode<E> x);
   /**
    * 获取第一个儿子
    * @param x
    * @return
    */
   TreeNode<E> getFirstChild(TreeNode<E> x);
   /**
    * 获取x的下一个兄弟
    * @param x
    * @return
    */
   TreeNode<E> getNextSibling(TreeNode<E> x);
   /**
    * 子树高度
    * @param x
    * @return
    */
   int getHeight(TreeNode<E> x);
   /**
    * 插入子节点
    * @param x
    * @param child
    */
   void insertChild(TreeNode<E> x, TreeNode<E> child);
   /**
    * 删除第i个子节点
    * @param x
    * @param i
    */
   void deleteChild(TreeNode<E> x, int i);
   /**
    * 先序遍历
    * @param x
    * @return
    */
   List<TreeNode<E>> preOrder(TreeNode<E> x);
   /**
    * 后续遍历
    * @param x
    * @return
    */
   List<TreeNode<E>> postOrder(TreeNode<E> x);
   /**
    * 层次遍历
    * @param x
    * @return
    */
   List<List<TreeNode<E>>> levelOrder(TreeNode<E> x);
   List<List<TreeNode<E>>> levelOrder();
 }
3、MyTree类:
注意这儿层次遍历这个函数,用到的bfs(宽度优先搜索),顾名思义就是遍历完每一层再接着遍历下一层。相比于DFS用的递归而言,那么bfs用到的技巧就是队列,口诀:(队)弹一个,加N个(队)。如果某行有n个节点,从1访问到n时,需要保存1的左右节点,2的左右节点,,,n的左右节点,遍历下行时的顺序是1的左右,2的左右,,,n的左右。这不就是先进(先保存)先出(先访问)吗?算法伪码:1.root进队(每个元素都要进队,别直接访问)2.开始循环:队首出队,其左右节点进队。(当然你也可以左右节点先进队,接着队首出队) 循环条件是队非空。
但若是需要换行打印的话就比较麻烦了,第一行的换行很简单啊,root后直接换行。那么你已经知道了第一行的换行,你就知道了第二行的换行位置啊,毕竟第二行都是第一行的“映射”。所以呢,跟刚才一样,在访问第n行的时候就要保存第n+1行的最右信息,反正n+1行的最右就是从第n行的左节点(第n+1行的最左)开始迭代。那么就需要用到双指针:增加两个TreeNode:last和nlast。last:表示当前遍历层最右结点。nlast:表示下一层最右结点。遍历时,每次将nlast指向插入队列元素,最后一个插入结点时即最右结点。插入左右孩子之后,检测last是否为当前输出结点,若是,则表示需要进行换行,并将last指向下一层的nlast。
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue; public class MyTree<E> implements ITree<E> {
private int size = 0;
private TreeNode root; public MyTree(TreeNode root) {
this.root = root;
size++;
} @Override
public int getSize() {
return size;
} @Override
public TreeNode<E> getRoot() {
return root;
} @Override
public TreeNode<E> getParent(TreeNode<E> x) {
return x.parent;
} @Override
public TreeNode<E> getFirstChild(TreeNode<E> x) {
return x.children.get(0);
} @Override
public TreeNode<E> getNextSibling(TreeNode<E> x) {
List<TreeNode<E>> children = x.parent.children;
int i = children.indexOf(x);
// try {
// return children.get(i + 1);
// } catch (Exception e) {
// return null;
// }
if (i == children.size() - 1) {
return null;
} else {
return children.get(i + 1);
}
} /**
* 获得整棵树的高度
*/
public int getHeight() {
return getHeight(root);
} // dfs 深度优先遍历求高度
@Override
public int getHeight(TreeNode<E> x) {
if (x.children == null) {
return 0;
} else {
int h = 0;
for (int i = 0; i < x.children.size(); i++) {
h = Math.max(h, getHeight(x.children.get(i)));
}
return h + 1;
}
} @Override
public void insertChild(TreeNode<E> p, TreeNode<E> child) {
if (p.children == null) {
p.children = new ArrayList<>();
}
p.children.add(child);
child.parent = p;
size++;
} @Override
public void deleteChild(TreeNode<E> p, int i) {
p.children.remove(i);
size--;
} // 因为这不是二叉树,所以先序等遍历就先不写
@Override
public List<TreeNode<E>> preOrder(TreeNode<E> x) {
return null;
} @Override
public List<TreeNode<E>> postOrder(TreeNode<E> x) {
return null;
} // 层次遍历 bfs 宽度优先搜索 队列 口诀:(队)弹一个,加N个(队)
// 深搜 递归
// 双指针 换行
@Override
public List<List<TreeNode<E>>> levelOrder(TreeNode<E> x) {
List<List<TreeNode<E>>> res = new ArrayList<>();// list的list
Queue<TreeNode<E>> q = new LinkedList<>();
q.add(x);// 初始化
TreeNode<E> last = x;// 标记上一行的最末节点
TreeNode<E> nLast = null;// 标记最新加入队列的节点
List<TreeNode<E>> l = new ArrayList<>();// 第一行的list
res.add(l); while (!q.isEmpty()) {
TreeNode<E> peek = q.peek();
// 把即将弹出的节点的子节点加入队列
if (peek.children != null) {
for (TreeNode<E> n : peek.children) {
q.add(n);
nLast = n;
}
}
l.add(q.poll());// 弹出,加入到当前层列表 if (peek == last && !q.isEmpty()) {// 如果现在弹出的节点是之前标记的最后节点,就要换列表
l = new ArrayList<>();
res.add(l);
last = nLast;
}
}
return res;
} @Override
public List<List<TreeNode<E>>> levelOrder() {
return levelOrder(root);
}
}
树的简介及Java实现的更多相关文章
- 数据结构图文解析之:树的简介及二叉排序树C++模板实现.
		0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ... 
- 相似文档查找算法之 simHash 简介及其 java 实现 - leejun_2005的个人页面 - 开源中国社区
		相似文档查找算法之 simHash 简介及其 java 实现 - leejun_2005的个人页面 - 开源中国社区 相似文档查找算法之 simHash 简介及其 java 实现 
- simHash 简介以及java实现
		http://gemantic.iteye.com/blog/1701101 simHash 简介以及java实现 博客分类: 算法 simHash java 去重 传统的hash 算法只负责将原始 ... 
- 深入浅出数据结构C语言版(10)——树的简介
		到目前为止,我们一直在谈论的数据结构都是"线性结构",不论是普通链表.栈还是队列,其中的每个元素(除了第一个和最后一个)都只有一个前驱(排在前面的元素)和一个后继(排在后面的元素) ... 
- simHash 简介以及 java 实现
		传统的 hash 算法只负责将原始内容尽量均匀随机地映射为一个签名值,原理上相当于伪随机数产生算法.产生的两个签名,如果相等,说明原始内容在一定概 率 下是相等的:如果不相等,除了说明原始内容不相等外 ... 
- Java密码体系结构简介:Java Cryptography Architecture (JCA) Reference Guide
		来自Java官方的文档,作备忘使用. 简介: Java平台非常强调安全性,包括语言安全,密码学,公钥基础设施,认证,安全通信和访问控制. JCA是平台的一个主要部分,包含一个“提供者”体系结构和一组用 ... 
- Elasticsearch Java client(ES Client 简介、Java REST Client、Java Client、Spring Data Elasticsearch)
		elasticsearch系列七:ES Java客户端-Elasticsearch Java client(ES Client 简介.Java REST Client.Java Client.Spri ... 
- 标准Trie字典树学习二:Java实现方式之一
		特别声明: 博文主要是学习过程中的知识整理,以便之后的查阅回顾.部分内容来源于网络(如有摘录未标注请指出).内容如有差错,也欢迎指正! 系列文章: 1. 标准Trie字典树学习一:原理解析 2.标准T ... 
- 数字证书简介及Java编码实现
		1.数字证书简介 数字证书具备常规加密解密必要的信息,包含签名算法,可用于网络数据加密解密交互,标识网络用户(计算机)身份.数字证书为发布公钥提供了一种简便的途径,其数字证书则成为加密算法以及公钥的载 ... 
随机推荐
- python面试题---收藏的笔记
			第一部分 Python基础篇(80题) 为什么学习Python? 通过什么途径学习的Python? Python和Java.PHP.C.C#.C++等其他语言的对比? 简述解释型和编译型编程语言? P ... 
- SSM框架中写sql在xml文件中
			第一种(用Mapper.xml映射文件中定义了操作数据库sql) 注意点: 1.#{}与${} #{}表示一个占位符,使用占位符可以防止sql注入, ${}通过${}可以将parameterType传 ... 
- JSP随记
			JSP简介: JSP全名为Java Server Pages,中文名叫java服务器页面,其根本是一个简化的Servlet设计,它是由Sun公司倡导.许多公司参与一起建立的一种动态网页技术标准. Se ... 
- PHP消息队列实现及应用
			目前对消息队列并不了解其原理,本篇文章主要是通过慕课网学习归纳的一些笔记,为后续学习打下基础. 众所周知在对网站设计的时候,会遇到给用户“群发短信”,“订单系统有大量的日志”,“秒杀设计”等,服务器没 ... 
- percona-toolkit安装
			https://www.percona.com/downloads/percona-toolkit/LATEST/ #下载wget https://www.percona.com/downloads/ ... 
- 自己动手造拖拉机轮子系列 -(react-loadable)
			最新消息:react官方已支持懒加载https://reactjs.org/docs/code-splitting.html#reactlazy 文章webpack分片chunk加载原理中深入探究了异 ... 
- 浅析布隆过滤器及实现demo
			布隆过滤器 布隆过滤器(Bloom Filter)是一种概率空间高效的数据结构.它与hashmap非常相似,用于检索一个元素是否在一个集合中.它在检索元素是否存在时,能很好地取舍空间使用率与误报比例. ... 
- 阿里云+WordPress搭建个人博客
			搭建过程: 第一步:首先你需要一台阿里云服务器ECS,如果你是学生,可以享受学生价9.5元/月 (阿里云翼计划:https://promotion.aliyun.com/ntms/act/campus ... 
- 1、Linux下部署NetCore应用
			1.根据官方文档配好.NetCore环境 https://www.microsoft.com/net/learn/get-started-with-dotnet-tutorial 2.安装Nginx ... 
- sql预编译&动态语句静态语句
			https://www.cnblogs.com/micrari/p/7112781.html https://www.cnblogs.com/MarsDing/p/9871703.html https ... 
