最近学习树,就写写自己了解的树的特点,我这篇写的是二叉树
树的定义:二叉树是每个结点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。(百度百科的二叉树树的定义)
左右孩子都在(a)
这就是最简单的树,它每个结点和双向链表 的结点相似,只不过链表的前后指针和它上下结点相互指向。而树的结点它只有从父节点指向子结点,但是子节点不能指向父结点。每一个父结点就像两个链表的开端。每一个结点并不是都有孩子。
只有左孩子的结点 (b) 只有右孩子的结点(c)
这里所说的没有左右孩子是它的左右孩子没有储存数据,相当于是null
如果一颗树只有bc其中一种构成它就相当于一个链表了
java语言写的树的结点:
package Tree;
public class TreeNode<T> {
T t;//数据
TreeNode<T> left;//左孩子
TreeNode<T> right;//右孩子
public TreeNode(T t){
this.t=t;
}
}
一颗树便是由abc三种情况所构成
这便是一颗树
树根:树根为一颗树的最高的父结点,它没有父结点,如上图中是的a
叶子结点:没有孩子结点的结点为叶子结点,如上图中h、i、k、l、m。
树的深度:为最深结点到树根的层数;上图树深度为:4
一颗树的最多结点数:2^m-1,m为这个树的深度
一个树的最大叶子树:2^(m-1),m为树的深度
关于二叉树的遍历,二叉树树的遍历有四种分别是
a.先序遍历
b.中序遍历
c.后序遍历
d.按层遍历
先序遍历:
从树根开始遍历,先输出根结点,在输出它的左孩子,其次是右孩子。
上边树前序遍历为:abdhiekcflgm
使用java语言先序遍历:
public void preorder(TreeNode<T> n) {
System.out.println(n.t);
if(n.left!=null) {
preorder(n.left);
}
if(n.right!=null) {
preorder(n.right);
}
}
中序遍历:
从有左孩子开始,先输左孩子,在输出它的父结点,其次是右孩子
上边树中序遍历为:hdibkeaflcgm
使用java语言中序遍历:
public void inorder(TreeNode<T> n) {
if(n.left!=null) {
inorder(n.left);
}
System.out.println(n.t);
if(n.right!=null) {
inorder(n.right);
}
}
后序遍历:
从左孩子开始遍历,先输出左孩子,在输出它的右孩子,其次是父节点
上边树前序遍历为:hidkeblfmgca
java实现后序遍历:
public void postorder(TreeNode<T> n) {
if(n.left!=null) {
postorder(n.left);
}
if(n.right!=null) {
postorder(n.right);
}
System.out.println(n.t);
}
前序、中序和后序三种遍历方式,记忆起来可能混淆,所以有一个比较简单的记法
右肯定在左的右边,然后是哪种遍历就把中加在哪里
比如前序:中左右 中序:左中右 后序:左右中
按层遍历:
可以使用递归的方式,每递归一次输出当前层的所有数据
上面树的遍历为:abcdefghiklm
这里就需要两个队列分别是l1和l2
1.首先将根结点存入l1中
2.把l1中数据输出,把l1中所有数据移入l2中。
3.l2为当前层的检点,将l2中每个结点的左右孩子移入l1中,且把所有的数据移除
4.重复2-3直到,经过3步骤l2中没有数据说明已经遍历完成
java代码实现
ArrayList<TreeNode<T>> l1;//队列1
ArrayList<TreeNode<T>> l2;//队列2
public void layer(TreeNode<T> n) {
//当第一调用时,我们把传入的n存入l1
if(l1.size()<1) {
l1.add(n);
}
//将l1中遍历当前层输出其中的数据
//将该层的数据取出存入l2中
while(l1.size()>0) {
System.out.print(l1.get(0).t+"--");
l2.add(l1.remove(0));
}
System.out.println();
//将l2中每个数据的孩子结点存入l1中
while(l2.size()>0) {
if(l2.get(0).left!=null) {
l1.add(l2.get(0).left);
}
if(l2.get(0).right!=null) {
l1.add(l2.get(0).right);
}
l2.remove(0);
}
//当l1中无数据时,说明这颗树已经遍历完成
if(l1.size()<1) {
return ;
}
layer(n);
}
四种遍历方式的整合代码:
package Tree;
import java.util.ArrayList;
public class Tree<T>{
ArrayList<TreeNode<T>> l1;//队列1
ArrayList<TreeNode<T>> l2;//队列2
public Tree() {
l1=new ArrayList<>();
l2=new ArrayList<>();
}
//先序遍历
public void preorder(TreeNode<T> n) {
System.out.println(n.t);
if(n.left!=null) {
preorder(n.left);
}
if(n.right!=null) {
preorder(n.right);
}
}
//中序遍历
public void inorder(TreeNode<T> n) {
if(n.left!=null) {
inorder(n.left);
}
System.out.println(n.t);
if(n.right!=null) {
inorder(n.right);
}
}
//后序遍历
public void postorder(TreeNode<T> n) {
if(n.left!=null) {
postorder(n.left);
}
if(n.right!=null) {
postorder(n.right);
}
System.out.println(n.t);
}
//按层遍历
public void layer(TreeNode<T> n) {
//当第一调用时,我们把传入的n存入l1
if(l1.size()<1) {
l1.add(n);
}
//将l1中遍历当前层输出其中的数据
//将该层的数据取出存入l2中
while(l1.size()>0) {
System.out.print(l1.get(0).t+"--");
l2.add(l1.remove(0));
}
System.out.println();
//将l2中每个数据的孩子结点存入l1中
while(l2.size()>0) {
if(l2.get(0).left!=null) {
l1.add(l2.get(0).left);
}
if(l2.get(0).right!=null) {
l1.add(l2.get(0).right);
}
l2.remove(0);
}
//当l1中无数据时,说明这颗树已经遍历完成
if(l1.size()<1) {
return ;
}
layer(n);
}
}
如果有不对的地方大家相互请教