概念:由结点构成的有限集或者空集,或者由一个根结点和两棵不相交的左子树和右子树构成。root结点没有父结点。非根结点的结点有且仅有一个前驱,二叉树中任何结点至多只有两个后继结点,二叉树中结点的子树数目称为该结点的度。没有子节点的结点称为叶结点(度为0的结点),父结点k与子结点k’之前存在<k,k'>的连线称作边。
{k0,k1,...,kn}<k0,k1>,<k1,k2>..经历的所有边的个数称为路径长度 --->结点的层数,根结点层数是0
满二叉树
一棵树的任何结点,或者树叶,或者左右子树均分空。称为满二叉树
完全二叉树
一棵二叉树最多只有最下面两层结点的度可以小于2,并且最下一层的结点都集中在该层最左边的连续位置位置上称为完全二叉树
完全二叉树按照层次编号正好对应数组的层次结构
扩充二叉树
在完全二叉树度为1的位置增加空树叶,树叶位置增加两个空树叶,扩充二叉树是一棵满二叉树。
内部结点,原二叉树结点
外部结点,扩充的空树叶
外部结点树 = 内部结点 + 1
E = I + 2n(E 是外部结点路径,I是内部节点路径,n是内部结点个数)
性质
- 二叉树第i层最多有个结点(i≥0)
- 深度为k的二叉树至多有个结点(k≥0)[层数最大的叶结点层数]
- 任何一棵二叉树,若其终端结点为n0,度为2的结点为n2,则n0=n2+1
- 满二叉树定理:非空满二叉树的树叶数目等于其分支结点数加1
- 满二叉树定理推论:一个非空二叉树的空子树数目等于其结点数加1
- 有n个结点(n>0)完全二叉树高度为,深度为高度-1(高度定义为最大层数加1)
- 对于n个节点的完全二叉树,结点按层次由左到右标号对于任一结点i(0≤i≤n-1)有:
(1)i=0则节点i是二叉树的根节点,若i>0则父结点编号是
(2)2i+1≤n-1时,结点i的左结点是2i+1,否则i没有左结点
2i+1≤n-1时,结点i的右结点是2i+2,否则i没有右结点
(3)i为偶数且0<i<n时,结点i的左兄弟结点是i-1,否则i没有左兄弟
当i为奇数且i+1<n时,结点i的右兄弟是i+1,否则i没有右兄弟
基本结构
class TreeNode{
int val;
TreeNode left;
TreeNode right;
public TreeNode(int val) {
this.val = val;
this.left = null;
this.right = null;
}
public int getVal() {
return val;
}
public void setVal(int val) {
this.val = val;
}
public TreeNode getLeft() {
return left;
}
public void setLeft(TreeNode left) {
this.left = left;
}
public TreeNode getRight() {
return right;
}
public void setRight(TreeNode right) {
this.right = right;
}
}
二叉树遍历
- 前序遍历(tLR,对应前缀表达式【波兰式】)
- 中序遍历(LtR,对应中缀表达式)
- 后序遍历(LRt,对应后缀表达式【波兰逆序式】)
/**
* LRt
* 后缀表达式,波兰逆序式
* ABCD+*+
* @param root
*/
public static void postOrder(TreeNode root) {
if (root != null) {
postOrder(root.left);
postOrder(root.right);
System.out.print(root.val + " ");
}
}
/**
* LtR
* A+B*C+D
* 中缀表达式
* @param root
*/
public static void inOrder(TreeNode root) {
if (root != null) {
inOrder(root.left);
System.out.print(root.val + " ");
inOrder(root.right);
}
}
/**
* A+B*(C+D)
* +A*B+CD
* tLR
* 参与运算符紧跟对象前缀表达式(波兰式)
* @param root
*/
public static void preOder(TreeNode root) {
if (root != null) {
System.out.print(root.val + " ");
preOder(root.left);
preOder(root.right);
}
}
非递归遍历
public static void preOrderWithoutRecursion(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
TreeNode pointer = root;
stack.push(null); //监听哨
while (pointer != null || !stack.isEmpty()) {
//根结点
System.out.print(pointer.val + " ");
//右子树入栈
if (pointer.right != null) {
stack.push(pointer.right);
}
//遍历左子树
if (pointer.left != null) {
pointer = pointer.left;
} else {
//左子树访问完毕访问右子树
pointer = stack.pop();
}
}
}
public static void inOrderWithoutRecursion(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
TreeNode pointer = root;
while (!stack.isEmpty() || pointer != null) {
if (pointer != null) {
stack.push(pointer);
pointer = pointer.left;
} else {
pointer = stack.pop();
System.out.print(pointer.val + " ");
pointer = pointer.right;
}
}
}
public static List<Integer> postOrderWithoutRecursion(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) {
return res;
}
Deque<TreeNode> stack = new LinkedList<>();
TreeNode prev = null;
while (root != null || !stack.isEmpty()) {
while (root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
if (root.right == null || root.right == prev) {
res.add(root.val);
prev = root;
root = null;
} else {
stack.push(root);
root = root.right;
}
}
return res;
}