《Java 数据结构和算法 第二版》
原文
本文用于方便整理和复习,感谢作者分享
特性
二叉树的重要特性
-
1.二叉树的第 n 层上节点数最多 2 n − 1 2^{n-1} 2n−1。
-
2.高度为 k 的二叉树中,最多有 2 k − 1 2^k-1 2k−1 个节点。
-
3.若采用连续储存的方式存放二叉树,则节点下标之间的关系:
若某个节点的下标为 i ,则这个节点的父节点的下标为 i / 2 i / 2 i/2。
若某个节点下标为 i ,且节点的度为2,则这个节点的【左子节点的下标为 2 ∗ i + 1 2 * i + 1 2∗i+1】 ,【右子节点的下标为 2 ∗ i + 2 2 * i + 2 2∗i+2 】。
满二叉树的性质:
-
1.满二叉树的第i层的节点数为 2 n − 1 2^{n-1} 2n−1个。
-
2.深度为 k 的满二叉树必有 2 k − 1 2^k-1 2k−1 个节点 ,叶子数为 2 k − 1 2^{k-1} 2k−1。
-
3.具有n个节点的满二叉树的深度为 l o g 2 ( n + 1 ) log_2(n+1) log2(n+1)。
完全二叉树的性质:
-
1.在完全二叉树中,若某个节点没有左子树,则一定没有有子树。
-
2.若采用连续储存的方式存放二叉树,则节点下标之间的关系(根节点下标为0):
若某个节点的下标为 i ,则这个节点的父节点的下标为 i / 2 i / 2 i/2。
若某个节点下标为 i ,且节点的度为2,则这个节点的【左子节点的下标为 2 ∗ i + 1 2 * i + 1 2∗i+1】 ,
右子节点的下标为 2 ∗ i + 2 2 * i + 2 2∗i+2 。 -
3.除了根节点外,左子树的下标为基数,右子树的下标为偶数。
一、二叉树相关算法 前序、中序、后序遍历(递归,迭代)
概念
1)前序遍历:先遍历根节点,然后遍历左子节点,最后遍历右子节点,简记为“根-左-右”;
2)中序遍历:先遍历左子节点,然后遍历根节点,最后遍历右子节点,简记为“左-根-右”;
3)后序遍历:先遍历左子节点,然后遍历右子节点,最后遍历根节点,简记为“左-右-根”;
public class TreeNode {
int value;
TreeNode left;
TreeNode right;
TreeNode(int value) {
this.value = value;
}
}
1、前序遍历 “根-左-右”
public static void preOrderRe(TreeNode biTree) {//递归实现
System.out.println(biTree.value);
TreeNode leftTree = biTree.left;
if (leftTree != null) {
preOrderRe(leftTree);
}
TreeNode rightTree = biTree.right;
if (rightTree != null) {
preOrderRe(rightTree);
}
}
public static void preOrder(TreeNode biTree) {//迭代实现
Stack<TreeNode> stack = new Stack<TreeNode>();
while (biTree != null || !stack.isEmpty()) {
while (biTree != null) {
System.out.println(biTree.value);
stack.push(biTree);
biTree = biTree.left;
}
if (!stack.isEmpty()) {
biTree = stack.pop();
biTree = biTree.right;
}
}
}
2、中序遍历 “左-根-右”
public static void midOrderRe(TreeNode biTree) {//中序遍历递归实现
if (biTree == null) {
return;
} else {
midOrderRe(biTree.left);
System.out.println(biTree.value);
midOrderRe(biTree.right);
}
}
public static void midOrder(TreeNode biTree) {//中序遍历迭代实现
Stack<TreeNode> stack = new Stack<TreeNode>();
while (biTree != null || !stack.isEmpty()) {
while (biTree != null) {
stack.push(biTree);
biTree = biTree.left;
}
if (!stack.isEmpty()) {
biTree = stack.pop();
System.out.println(biTree.value);
biTree = biTree.right;
}
}
}
3、后序遍历 “左-右-根”
public static void postOrderRe(TreeNode biTree) {//后序遍历递归实现
if (biTree == null) {
return;
} else {
postOrderRe(biTree.left);
postOrderRe(biTree.right);
System.out.println(biTree.value);
}
}
public static void postOrder(TreeNode biTree) {//后序遍历迭代实现
int left = 1;//在辅助栈里表示左节点
int right = 2;//在辅助栈里表示右节点
Stack<TreeNode> stack = new Stack<TreeNode>();
Stack<Integer> stack2 = new Stack<Integer>();//辅助栈,用来判断子节点返回父节点时处于左节点还是右节点。
while (biTree != null || !stack.empty()) {
while (biTree != null) {//将节点压入栈1,并在栈2将节点标记为左节点
stack.push(biTree);
stack2.push(left);
biTree = biTree.left;
}
while (!stack.empty() && stack2.peek() == right) {//如果是从右子节点返回父节点,则任务完成,将两个栈的栈顶弹出
stack2.pop();
System.out.println(stack.pop().value);
}
if (!stack.empty() && stack2.peek() == left) {//如果是从左子节点返回父节点,则将标记改为右子节点
stack2.pop();
stack2.push(right);
biTree = stack.peek().right;
}
}
}
4、层次遍历
1)对于不为空的节点,先把该节点加入到队列中
2)从队列中拿出节点,如果该节点的左右节点不为空,就分别把左右节点加入到队列中
3)重复以上操作直到队列为空
//层次遍历
public static void levelOrder(TreeNode root) {
if(root == null) {
return;
}
//通过 LinkedList 先进先出
LinkedList<TreeNode> list = new LinkedList<TreeNode>();
list.add(root);
TreeNode currentNode;
while(!list.isEmpty()) {
currentNode = list.poll();//poll() 从 LinkedList【头部删除并返回】
System.out.println(currentNode.value);
if(currentNode.left != null) {
list.add(currentNode.left);
}
if(currentNode.right != null) {
list.add(currentNode.right);
}
}
}
二、红黑树 与 BL树 等
1、红黑树,参考Java数据结构部分笔记和资料
2、[BL树](https://blog.csdn.net/jimo_lonely/article/details/82716142)
t是自然数,可以自己定义的。
1)所有叶子节点到根节点的路径长度相同,即具有相同的高度;
2)每个非叶子和非根节点(即内部节点)至少有 t-1 个孩子节点;根至少2个孩子
3)每个节点最多有2t个孩子节点。
4)每个节点内的键都是递增的
5)每个节点的孩子比key的个数多1
/**
* B树中的节点。
*/
private static class BTreeNode<K, V> {
/**
* 节点的项,按键非降序存放,每个节点可以存放多组键值对
* 每个节点内的 key 是递增的
* 每个节点,最多 2t-1 个key
*/
private List<Entry<K, V>> entries;
/**
* 内节点的子节点
* 每个节点,至少有t-1个孩子节点,最多有 2t 个孩子节点;根至少2个孩子
*/
private List<BTreeNode<K, V>> children;
/**
* 是否为叶子节点
*/
private boolean leaf;
/**
* 键的比较函数对象
*/
private Comparator<K> kComparator;
private BTreeNode() {
entries = new ArrayList<>();
children = new ArrayList<>();
leaf = false;
}
...
}
推荐阅读:
《Java 数据结构和算法 第二版》
刷题---->LeetCode