二叉树
1. 几种特殊的二叉树
- 满二叉树:一个二叉树,如果每一层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为 k,且结点总数是 2 ^ k - 1,则他就是满二叉树。
- 完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于具有n个结点的二叉树按层序编号,如果每个结点的编号与同样深度的满二叉树中对应编号的结点在二叉树中位置完全相同,则该二叉树称为完全二叉树。
- 二叉搜索树(BSTree):一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
(4)没有键值相等的结点。
对二叉查找树进行中序遍历,即可得到有序的数列。
2. 二叉树的性质
- 若规定根节点的层数是 1,则一颗非空二叉树的第 i 层上最多有2 ^ (i - 1)个结点;
- 若规定只有根节点的二叉树的深度是 1,则深度为 k 的二叉树的最大节点数是2 ^ k - 1;
- 对任何一个二叉树,如果其叶节点个数为 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. 二叉树的基本操作
3.1 二叉树的存储
public class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int val){
this.val = val;
}
@Override
public String toString() {
return String.format("TreeNode{%c}", val);
}
}
3.2 二叉树的遍历
前序遍历
void preOrderTraversal(TreeNode root){
if (root == null){
return;
}
System.out.printf("%c", root.val);
preOrderTraversal(root.left);
preOrderTraversal(root.right);
}
中序遍历
void inOrderTraversal(TreeNode root){
if (root == null){
return;
}
inOrderTraversal(root.left);
System.out.printf("%c", root.val);
inOrderTraversal(root.right);
}
后序遍历
void postOrderTraversal(TreeNode root){
if (root == null){
return;
}
postOrderTraversal(root.left);
postOrderTraversal(root.right);
System.out.printf("%c", root.val);
}
层序遍历
ArrayList<ArrayList<Integer> > LevelOrder(TreeNode root) {
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
if (root == null){
return res;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()){
ArrayList<Integer> list = new ArrayList<>();
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
list.add(node.val);
}
res.add(list);
}
return res;
}
3.3 求结点个数
遍历思路
static int size = 0;
void getSize1(TreeNode root){
if (root != null){
size++;
getSize1(root.left);
getSize1(root.right);
}
}
子问题思路
int getSize2(TreeNode root){
if (root != null){
int leftSize = getSize2(root.left);
int rightSize = getSize2(root.right);
return 1 + leftSize + rightSize;
}
return 0;
}
3.4 求叶子结点个数
遍历思路
static int leafSize = 0;
void getLeafSize1(TreeNode root){
if (root == null){
return;
}
if (root.left == null && root.right == null){
leafSize++;
}
getLeafSize1(root.left);
getLeafSize1(root.right);
}
子问题思路
int getLeafSize2(TreeNode root){
if (root == null){
return 0;
}
if (root.left == null && root.right == null){
return 1;
}
int leftLeafSize = getLeafSize2(root.left);
int rightLeafSize = getLeafSize2(root.right);
return leftLeafSize + rightLeafSize;
}
3.5 求第 k 层结点个数
int getLevelSize(TreeNode root, int k){
if (root == null){
return 0;
}
if (k == 1){
return 1;
}
int left = getLevelSize(root.left, k - 1);
int right = getLevelSize(root.right, k - 1);
return left + right;
}
3.6 获取二叉树的高度
int getHeight(TreeNode root){
if (root == null){
return 0;
}
int left = getHeight(root.left);
int right = getHeight(root.right);
int m = Math.max(left, right);
return m + 1;
}
3.7 查找 val 所在结点
TreeNode find(TreeNode root, int val){
if (root == null){
return null;
}
if (root.val == val){
return root;
}
TreeNode r = find(root.left, val);
if (r != null){
return r;
}
return find(root.right, val);
}