1.两种特殊的二叉树
- 满二叉树 : 一棵二叉树,如果 每层的结点数都达到最大值,则这棵二叉树就是满二叉树 。也就是说, 如果一棵 二叉树的层数为 K ,且结点总数是2^k-1 ,则它就是满二叉树 。
- 完全二叉树 : 完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为 K 的,有 n个结点的二叉树,当且仅当其每一个结点都与深度为K 的满二叉树中编号从 0 至 n-1 的结点一一对应时称之为完 全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。
2二叉树的性质
- 若规定 根结点的层数为 1 ,则一棵 非空二叉树的第 i层上最多有(2^i-1)(i>0) 个结点
- 若规定只有 根结点的二叉树的深度为 1 ,则 深度为 K的二叉树的最大结点数是(2^k-1)(k>=0)
- 对任何一棵二叉树 , 如果其 叶结点个数为 n0, 度为 2 的非叶结点个数为 n2, 则有 n0 = n2 + 1
- 具有 n 个结点的完全二叉树的深度 k 为log(n+1) 上取整
- 对于具有 n 个结点的完全二叉树 ,如果按照 从上至下从左至右的顺序对所有节点从 0 开始编号 ,则对于 序号为 i 的结点有 :
若 i>0 , 双亲序号: (i-1)/2 ; i=0 , i 为根结点编号 ,无双亲结点
若 2i+1<n ,左孩子序号: 2i+1 ,否则无左孩子
若 2i+2<n ,右孩子序号: 2i+2 ,否则无右孩子
3.二叉树的存储
二叉树的存储结构 分为: 顺序存储 和 类似于链表的链式存储 。
常见是 类似于链表的链式存储。
二叉树的链式存储是通过一个一个的节点引用起来的,常见的表示方式有二叉和三叉表示方式 ,具体如下:
// 孩子表示法
class Node {
int val ; // 数据域
Node left ; // 左孩子的引用,常常代表左孩子为根的整棵左子树
Node right ; // 右孩子的引用,常常代表右孩子为根的整棵右子树
}
// 孩子双亲表示法
class Node {
int val ; // 数据域
Node left ; // 左孩子的引用,常常代表左孩子为根的整棵左子树
Node right ; // 右孩子的引用,常常代表右孩子为根的整棵右子树
Node parent ; // 当前节点的根节点
}
4.创建二叉树
输入一串合法的前序遍历字符串,先创建根节点,不为'#'再递归创建左孩子,如果是就回退到上一个节点,再递归创建左孩子右孩子,连续遇到两个'#'则一个子树创建完成。
代码如下:
class Main {
public static class TreeNode {
Character val;
TreeNode left;
TreeNode right;
TreeNode() {}
TreeNode(Character val) {
this.val = val;
}
TreeNode(Character val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}//内部类(树节点)
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
// while (in.hasNextInt()) { // 注意 while 处理多个 case
String s = in.nextLine();
TreeNode root = createTree(s);//递归创建二叉树
order(root);
// }
}
public static int i = 0;
public static TreeNode createTree(String s) {
TreeNode root = null;
if (s.charAt(i) != '#') {
root = new TreeNode(s.charAt(i));
i++;
root.left = createTree(s);
root.right = createTree(s);
} else {
i++;
}
return root;
}
}
例:
root = [1,null,2,3]
5.二叉树的基本操作
// 获取树中节点的个数
int size(Node root){
if(root==null){
return 0;
}
return size2(root.right)+size2(root.left)+1;
}
// 获取叶子节点的个数
public static int leafSize = 0;
int getLeafNodeCount(Node root){
if(root==null){
return ;
}
if(root.left==null&&root.right==null){
leafSize++;
}
getLeafNodeCount1(root.right);
getLeafNodeCount1(root.left);
}
// 获取第K层节点的个数
int getKLevelNodeCount(Node root,int k){
if(root==null){
return 0;
}
if(k==1){
return 1;
}
return getKLevelNodeCount(root.left,k-1)+
getKLevelNodeCount(root.right,k-1);
}
// 获取二叉树的高度
int getHeight(Node root){
if(root==null){
return 0;
}
int leftL=getHeight(root.left);
int rightL=getHeight(root.right);
// return right>left?right+1:left+1;
return Math.max(rightL,leftL)+1;
}
// 检测值为value的元素是否存在
Node find(Node root, int val){
if(root==null){
return null;
}
if(root.val==val){
return root;
}
TreeNode leftT=find(root.left,val);
if(leftT!=null) {
return leftT;
}
TreeNode rightT=find(root.right,val);
if(rightT!=null){
return rightT;
}
return null;
}
//层序遍历
void levelOrder(Node root){
if(root==null){
return ;
}
Queue<TreeNode> queue=new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()){
TreeNode cur= queue.poll();
System.out.println(cur.val+" ");
if(cur.left!=null){
queue.offer(cur.left);
}
if(cur.right!=null){
queue.offer(cur.right);
}
}
System.out.println();
}
// 判断一棵树是不是完全二叉树
boolean isCompleteTree(Node root){
if(root==null){
return true;
}
int leftL=getHeight(root.left);
int rightL=getHeight(root.right);
if(leftL-rightL>1||rightL-leftL>1){
return false;
}
return isBalanced(root.left)&&isBalanced(root.right);//时间复杂度O(n^2)
//return getHeight2>0 时间复杂度O(n)
}