二叉树的定义
二叉树(binary tree)是结点的有限集合,这个集合或者空,或者由一个根及两个互不相交的称为这个根的左子树或右子树构成.
从定义可以看出,二叉树包括:1.空树 2.只有一个根节点 3.只有左子树 4.只有右子树 5.左右子树都存在 有且仅有这5中表现形式
- 一般树的子树不分次序,而二叉树的子树有左右之分.
- 由于二叉树也是树的一种,所以大部分的树的概念,对二叉树也适用.
- 二叉树的存贮:每个节点只需要两个指针域(左节点,右节点),有的为了操作方便也会 增加指向父级节点的指针,除了指针域以外,还会有一个数据域用来保存当前节点的信息
- 性质1:在二叉树的第i层上至多有2^(i-1)个节点(i >= 1)
- 性质2:深度为k的二叉树至多有2^(k-1)个节点(k >=1)
- 性质3:对于任意一棵二叉树T而言,其叶子节点数目为N0,度为2的节点数目为N2,则有N0 = N2 + 1。
- 性质4:具有n个节点的完全二叉树的深度 。
- 前序遍历:按照“根左右”,先遍历根节点,再遍历左子树 ,再遍历右子树
- 中序遍历:按照“左根右“,先遍历左子树,再遍历根节点,最后遍历右子树
- 后续遍历:按照“左右根”,先遍历左子树,再遍历右子树,最后遍历根节点
- 其中前,后,中指的是每次遍历时候的根节点被遍历的顺序
/** * */ package test2; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; /** * @author lee * */ public class Tree { private Node root; // private List<Node> list = new ArrayList<Node>(); //因为此处涉及到二叉树的层次遍历,所以用到LinkedList,LinkedList实现了queue接口; private LinkedList<Node> list = new LinkedList<Node>(); public Tree() { init(); } /** * 树的初始化,先从叶节点开始,由叶到根 * @author lee 2017年3月11日 上午11:09:26 */ public void init() { Node x=new Node("x",null,null); Node y=new Node("y",null,null); Node d=new Node("d",x,y); Node e=new Node("e",null,null); Node f=new Node("f",null,null); Node c=new Node("c",e,f); Node b=new Node("b",d,null); Node a=new Node("a",b,c); root =a; } //得到遍历结果list public List<Node> getList() { return list; } //定义节点类 private class Node{ private String data; private Node lchild; private Node rchild; public Node(String data,Node lchild,Node rchild) { this.data = data; this.lchild = lchild; this.rchild = rchild; } } /** * 前序遍历,结果储存到list中 * @author lee 2017年3月11日 上午10:27:38 */ public void preOrder1(Node node) { //先将根节点存入list list.add(node); //如果左子树不为空继续往左找,在递归调用方法的时候一直会将子树的根存入list,这就做到了先遍历根节点 if(node.lchild != null) { preOrder1(node.lchild); } //无论走到哪一层,只要当前节点左子树为空,那么就可以在右子树上遍历,保证了根左右的遍历顺序 if(node.rchild != null) { preOrder1(node.rchild); } } //或者可以这样写: public void preOrder2(Node node) { if(node != null) { list.add(node); preOrder2(node.lchild); preOrder2(node.rchild); } } /** * 中序遍历,结果储存到list中 * @author lee 2017年3月11日 上午10:27:38 */ public void inOrder(Node node) { if(node.lchild!=null){ inOrder(node.lchild); } list.add(node); if(node.rchild!=null){ inOrder(node.rchild); } } /** * 后序遍历,结果储存到list中 * @author lee 2017年3月11日 上午10:27:38 */ public void postOrder(Node node) { if(node.lchild!=null){ postOrder(node.lchild); } if(node.rchild!=null){ postOrder(node.rchild); } list.add(node); } /** * 层次遍历: * 根据层次遍历的顺序,每一层都是从左到右的遍历输出,借助于一个队列。 先将根节点入队,当前节点是队头节点,将其出队并访问,如果当前节点的左节点不 为空将左节点入队,如果当前节点的右节点不为空将其入队。所以出队顺序也是从左到右依次出队。 * @author lee 2017年3月11日 下午9:04:22 */ public void levelOrder(Node node) { if(node != null) { list.add(node);//将根节点入队 while(!list.isEmpty()) { Node curr = list.poll();//出队队头元素并访问 System.out.print(curr.data+","); //如果当前节点的左节点不为空入队 if(curr.lchild != null) { list.add(curr.lchild); } //如果当前节点的右节点不为空,把右节点入队 if(curr.rchild != null) { list.add(curr.rchild); } } } } /** * 返回当前数的深度 * 说明: * 1、如果一棵树只有一个结点,它的深度为1。 * 2、如果根结点只有左子树而没有右子树,那么树的深度是其左子树的深度加1; * 3、如果根结点只有右子树而没有左子树,那么树的深度应该是其右子树的深度加1; * 4、如果既有右子树又有左子树,那该树的深度就是其左、右子树深度的较大值再加1。 * * @return */ public int getTreeDepth(Node node) { if(node.lchild == null && node.rchild == null) { return 1; } int left=0,right = 0; if(node.lchild!=null) { left = getTreeDepth(node.lchild); } if(node.rchild!=null) { right = getTreeDepth(node.rchild); } return left>right?left+1:right+1; } /** * @description TODO * @time 2017年3月11日 上午10:09:41 * @author lee * @return void */ public static void main(String[] args) { // TODO Auto-generated method stub Tree tree1 = new Tree(); Tree tree2 = new Tree(); tree1.preOrder1(tree1.root); System.out.print("先序遍历结果: "); for(Node node:tree1.getList()) { System.out.print(node.data+","); } //层次遍历结果输出 System.out.print("\n层次遍历结果: "); tree2.levelOrder(tree2.root); } }