二叉树(Binary Tree)
概念
二叉树是一种特殊的树,它的每个节点,最多只能有两个孩子,并且二叉树是有序树(孩子的前后关系很重要)。二叉树的所有形态如下:
两种特殊二叉树
满二叉树:一个二叉树,如果每一层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是2^k-1,则它就是满二叉树。
完全二叉树:即添加结点顺序为从左往右、从上往下,删除顺序为从右往左、从下往上的二叉树。
二叉树的性质
- 若规定根结点的层数为1,则一颗非空二叉树的第i层上最多有2^(i-1) (i>0)个结点。
- 若规定只有根结点的二叉树的深度为1,则深度为K的二叉树的最大结点数是2^K - 1 (k >= 0)个。
- 对任何一颗二叉树,如果其叶子结点个数为n0,度为2的非叶子结点个数为n2,则有n0=n2+1。
- 具有n个结点的完全二叉树的深度k为log2^(n+1)向上取整
二叉树的链式表示
如果你懂链表的表示方法,那么对于二叉树的链式表示也就很简单了。
//二叉树的链式表示
class TreeNode{
int value;
TreeNode left;//结点左孩子
TreeNode right;//结点右孩子
public TreeNode(int value){
this.value = value;
}
}
public class MyTreeNode {
public static void main(String[] args) {
//下面用代码分别表示二叉树的五种基本形态
//1.空树
TreeNode root = null;//一个结点都不存在的二叉树
//2.只有根结点的二叉树
root = new TreeNode(1);//只有一个值为1的根结点
//3.只有左孩子(左子树)
root.left = new TreeNode(2);
//4.只有右孩子
//root.right = new TreeNode(3);
//5.两个孩子都有,即3和4
}
}
二叉树的遍历(重点)
小技巧:二叉树的前序遍历、中序遍历和后序遍历对于我个人的记法是按照字面意思排布‘根’、‘左’、‘右’,左右的顺序不会改变,左一定在右的前面,所以主要看根,比方说前序遍历,即将‘根’放在左右的前面,所以是根左右,同理可得中序遍历为左根右,后序遍历为左右根。
前序遍历
前序遍历首先访问根结点,然后遍历左子树,最后遍历右子树,即根左右。接下来用图解演示一下前序遍历过程。
前序遍历结果为:1,2,4,5,3
public static void preTraversal(TreeNode root){
if(root != null) {
//1.首先处理根结点
System.out.println(root.value);
//2.按照前序的方式,递归处理该结点的左子树
preTraversal(root.left);
//3.按照前序的方式,递归处理该结点的右子树
preTraversal(root.right);
}else{
//TODO
}
}
中序遍历
中序遍历首先遍历左子树,然后访问根结点,最后遍历右子树,即左根右。
中序遍历结果为:4,2,5,1,3
public static void inTraversal(TreeNode root){
if(root != null){
//1.中序遍历左子树
inTraversal(root.left);
//2.处理根
System.out.println(root);
//3.中序遍历右子树
inTraversal(root.right);
}else{
//TODO
}
}
后序遍历
后序遍历首先遍历左子树,然后遍历右子树,最后访问根结点,即左右根。
后序遍历结果为:4,5,2,3,1
public static void postTraversal(TreeNode root){
if(root != null){
postTraversal(root.left);
postTraversal(root.right);
System.out.println(root);
}else{
//TODO
}
}
层序遍历
层序遍历即按照层数从左到右遍历结点。
观看上图看似很简单的层序遍历,那么我们该如何实现呢?这里就需要借助队列先进先出的优势来完成。
1.启动阶段,把根结点放入队列
2.开启循环,知道队列为空(isEmpty)
- 从队列中取出队首结点
- 层序遍历该结点(打印)
- 把该结点的左右孩子放入队列中(如果存在)
//层序遍历
public static void levelOrderTraversal(TreeNode root){
if(root == null){
return;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
TreeNode node = queue.remove();
//这个node就是我们层序遍历时经过的结点
System.out.println(node.value);
if(node.left != null){
//node 有左孩子
queue.add(node.left);
}
if(node.right != null){
//node 有右孩子
queue.add(node.left);
}
}
}
注:二叉树的学习,可以在理解基础知识的前提下,多练习LeetCode或牛客习题从而达到深入理解。并且树的遍历一定要掌握,因为大多数题目都是遍历的变形。