二叉树的实现及其遍历
来源:互联网 发布:微软最小的windows系统 编辑:程序博客网 时间:2024/05/29 05:58
递归搞得我怀疑人生,写个二叉树缓解一下心情......
满二叉树:
包含2^k-1个节点
每层的节点数为2^(k-1)
完全二叉树:
除了最后一层所有层的节点都是满的
具有n个节点的完全二叉树的深度为log2n+1
1、二叉树的顺序存储
使用数组来记录二叉树的所有节点,存储情况如下图所示:
代码如下:
class ArrayBinTree<T> { //使用数组来记录该树的所有节点 private Object[] datas; private int DEFAULT_DEEP = 8; //保存该树的深度 private int deep; private int arraySize; //以默认的深度来创建二叉树 public ArrayBinTree() { this.deep = DEFAULT_DEEP; this.arraySize = (int) Math.pow(2, deep) - 1;//二叉树总节点的个数,是个公司 datas = new Object[arraySize]; } //以指定深度来创建二叉树 public ArrayBinTree(int deep) { this.deep = deep; this.arraySize = (int) Math.pow(2, deep) - 1; datas = new Object[arraySize]; } //以指定深度,指定根节点创建二叉树 public ArrayBinTree(int deep, T data) { this.deep = deep; this.arraySize = (int) Math.pow(2, deep) - 1; datas = new Object[arraySize]; datas[0] = data; } /** * 为指定节点添加子节点。 * @param index 需要添加子节点的父节点的索引 * @param data 新子节点的数据 * @param left 是否为左节点 */ public void add(int index , T data , boolean left){ if (datas[index] == null){ throw new RuntimeException(index + "处节点为空,无法添加子节点"); } if (2 * index + 1 >= arraySize){ throw new RuntimeException("树底层的数组已满,树越界异常"); } //添加某个指定index的左子节点,奇数 if (left){ datas[2 * index + 1] = data; }else{//偶数添加某个指定index的右子节点,奇数 datas[2 * index + 2] = data; } } //判断二叉树是否为空。 public boolean empty(){ //根据根元素来判断二叉树是否为空 return datas[0] == null; } //返回根节点。 public T root(){ return (T)datas[0] ; } //返回指定节点(非根节点)的父节点。 public T parent(int index){ return (T)datas[(index - 1) / 2] ;//整除,不会产生小数,生成节点的逆向 } //返回指定节点(非叶子节点)的左子节点。当左子节点不存在时返回null public T left(int index){ if (2 * index + 1 >= arraySize){ throw new RuntimeException("该节点为叶子节点,无子节点"); } return (T)datas[index * 2 + 1] ; } //返回指定节点(非叶子节点)的右子节点。当右子节点不存在时返回null public T right(int index){ if (2 * index + 2 >= arraySize){ throw new RuntimeException("该节点为叶子节点,无子节点"); } return (T)datas[index * 2 + 2] ; } //返回该二叉树的深度。 public int deep(int index){ return deep; } //返回指定节点的位置。 public int pos(T data){ //该循环实际上就是按广度遍历来搜索每个节点 for (int i = 0 ; i < arraySize ; i++){ if (datas[i].equals(data)){ return i; } } return -1; }}2、二叉树链表存储
为每个节点增加左右两个指针,分别指向该节点的左右两个子节点
(刚才不知道点了什么,屏幕中突然出现了一条提示“ALT+左箭头可后退”,在我还没有理解这句话的时候我的手已经做出了反应,alt+左箭头毫不犹豫的按了下去,结果......真的后退了......我之前打的字粘的代码传的图片都没有了......如果你想清空刚才你写的文章的话这不失为一个好方法,要不然朋友们还是不要轻易尝试了......)
链表存储情况如下图所示:
代码如下:
class LinkBinTree<E> { public static class TreeNode{ Object data; TreeNode left; TreeNode right; public TreeNode(){ } public TreeNode(Object data){ this.data = data; } public TreeNode(Object data , TreeNode left, TreeNode right){ this.data = data; this.left = left; this.right = right; } } private TreeNode root; //以默认的构造器来创建二叉树 public LinkBinTree(){ this.root = new TreeNode(); } //以指定根元素来创建二叉树 public LinkBinTree(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; } return newNode; } //判断二叉树是否为空。 public boolean empty(){ //根据根元素来判断二叉树是否为空 return root.data == null; } //返回根节点。 public TreeNode root(){ if (empty()){ throw new RuntimeException("树为空,无法访问根节点"); } return root; } //返回指定节点(非叶子)的左子节点。当左子节点不存在时返回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; } }}
(终于弄明白了最后一个计算深度的递归方法,画个图庆祝一下......)
3、二叉树的先序、中序、后序遍历
先序(DLR):
(1)访问根节点
(2)先序遍历左子树
(3)先序遍历右子树
中序(LDR):
(1)中序遍历左子树
(2)访问根节点
(3)中序遍历右子树
后序(LRD):
(1)后序遍历左子树
(2)后序遍历右子树
(3)访问根节点
public class Traverse { class TreeNode<T>{ private T data; private TreeNode<T> leftNode; private TreeNode<T> rightNode; public TreeNode(T data,TreeNode<T> leftNode,TreeNode<T> rightNode){ this.data=data; this.leftNode=leftNode; this.rightNode=rightNode; } public T getData(){ return data; } public void setData(T data){ } public TreeNode<T> getLeftNode(){ return leftNode; } public void setLeftNode(TreeNode<T> leftNode){ this.leftNode=leftNode; } public TreeNode<T> getRightNode(){ return rightNode; } public void setRightNode(TreeNode<T> rightNode){ this.rightNode=rightNode; } } public TreeNode<String> init(){ TreeNode<String> D=new TreeNode<String>("D",null,null); TreeNode<String> H=new TreeNode<String>("H",null,null); TreeNode<String> I=new TreeNode<String>("I",null,null); TreeNode<String> J=new TreeNode<String>("J",null,null); TreeNode<String> P=new TreeNode<String>("K",null,null); TreeNode<String> G=new TreeNode<String>("G",P,null); TreeNode<String> F=new TreeNode<String>("F",null,J); TreeNode<String> E=new TreeNode<String>("E",H,I); TreeNode<String> B=new TreeNode<String>("B",D,E); TreeNode<String> C=new TreeNode<String>("C",F,G); TreeNode<String> A=new TreeNode<String>("A",B,C); return A; } public void printNode(TreeNode<String> node){ System.out.println(node.getData()+" ");; } //先序遍历 public void pre_order(TreeNode<String> node){ this.printNode(node);//D if(node.getLeftNode()!=null){//L this.pre_order(node.getLeftNode()); } if(node.getRightNode()!=null){ this.pre_order (node.getRightNode()); } } //中序遍历 public void in_order(TreeNode<String> node){ if(node.getLeftNode()!=null){//L this.in_order(node.getLeftNode()); } this.printNode(node);//D if(node.getRightNode()!=null){//R this.in_order(node.getRightNode()); } } //后序遍历 public void post_order(TreeNode<String> node){ if(node.getLeftNode()!=null){//L this.post_order(node.getLeftNode()); } if(node.getRightNode()!=null){//R this.post_order(node.getRightNode()); } this.printNode(node);//D } public static void main(String[] args) { Traverse Tree=new Traverse(); TreeNode<String> node=Tree.init(); System.out.println("先序遍历DLR的情况"); Tree.pre_order(node); System.out.println("中序LDR遍历的情况"); Tree.in_order(node); System.out.println("后序遍历LRD的情况"); Tree.post_order(node); }}4、广度优先遍历(按层遍历)
实现代码如下:
public void level(TreeNode<String> node){ Queue<TreeNode<String>> queue=new ArrayDeque<TreeNode<String>>(); queue.add(node); while(!queue.isEmpty()){ TreeNode<String> n=queue.poll(); this.printNode(n); if(n.getLeftNode()!=null){ queue.add(n.getLeftNode()); } if(n.getRightNode()!=null){ queue.add(n.getRightNode()); } } }
0 0
- 二叉树的遍历及其Java实现
- 二叉树的实现及其遍历
- c++实现数据结构的二叉树及其遍历二叉树
- 二叉树线索化、遍历的实现及其原理
- 【数据结构】二叉树的构建及其遍历(C++实现)
- 二叉树及其遍历
- 二叉树及其遍历
- 二叉树及其遍历
- 二叉树及其遍历
- 二叉树的存储结构及其遍历
- 二叉搜索树的创建及其遍历
- 二叉树的遍历及其用途
- 二叉树的创建及其遍历
- 二叉查找树的构造及其遍历
- 二叉树的遍历及其应用
- 【C++】 二叉树的基本知识及其遍历
- 二叉树的遍历及其用途
- 二叉树的构建及其遍历算法
- Spring MVC 教程,快速入门,深入分析
- Spring整合web项目原理
- js重点
- 各种距离
- FEKO计算多层介质的反射系数
- 二叉树的实现及其遍历
- Create Intellij Plugin
- Oracle11.2新特性之listagg函数 (行列转换)
- 数字图像变换(1)2017.3.20
- spring框架学习(一)
- oracle uid字段不能用
- ros的navigation之———gmapping应用详解(in ros)
- 最大上升子序列和 poj
- 104. Maximum Depth of Binary Tree