961全部内容链接
满二叉树:一棵高度为 2h-1 个节点的二叉树,称为满二叉树。就是说,除了最后一层,其他层的节点的度必须都为2。说白了就是把二叉树画满。
二叉排序树:左子树的所有节点的关键字均小于根节点关键字,右子树的所有关键字均大于根节点关键字。且左右子树也是二叉排序树。
平衡二叉树:树上任意一个节点的左右子树的深度之差不大于1
1. 非 空 二 叉 树 上 的 叶 子 结 点 数 等 于 度 为 2 的 结 点 数 加 1 , 即 n 0 = n 2 + 1 2. 非 空 二 叉 树 上 第 k 层 上 至 多 有 2 k − 1 个 节 点 ( k ≥ 1 ) 3. 高 度 为 h 的 二 叉 树 至 多 有 2 h − 1 个 结 点 \begin{aligned} & 1. 非空二叉树上的叶子结点数等于度为2的结点数加1,即 n_0 = n_2+1 \\ & 2. 非空二叉树上第k层上至多有 2^{k-1}个节点 (k\ge 1) \\ & 3. 高度为h的二叉树至多有 2^h -1 个结点 \\ \end{aligned} 1.非空二叉树上的叶子结点数等于度为2的结点数加1,即n0=n2+12.非空二叉树上第k层上至多有2k−1个节点(k≥1)3.高度为h的二叉树至多有2h−1个结点
对完全二叉树,从上到下,从左到右的顺序依次编号 1,2,…n,则有以下关系:
1. 当 i > 1 时 , 其 双 亲 的 编 号 为 ⌊ i / n ⌋ 2. 当 i 为 偶 数 时 , 为 左 孩 子 , 当 i 为 奇 数 时 , 为 右 孩 子 3. 当 i ≤ ⌊ n / 2 ⌋ , 则 节 点 i 为 分 支 节 点 , 否 则 为 叶 子 结 点 4. 高 度 为 ⌊ log 2 n ⌋ + 1 \begin{aligned} & 1. 当i>1时,其双亲的编号为 ~ \lfloor i/n \rfloor \\ & 2. 当i为偶数时,为左孩子,当i为奇数时,为右孩子 \\ & 3. 当 i \le \lfloor n/2 \rfloor ,则节点i为分支节点,否则为叶子结点 \\ & 4. 高度为 \lfloor \log_2n\rfloor +1 \end{aligned} 1.当i>1时,其双亲的编号为 ⌊i/n⌋2.当i为偶数时,为左孩子,当i为奇数时,为右孩子3.当i≤⌊n/2⌋,则节点i为分支节点,否则为叶子结点4.高度为⌊log2n⌋+1
class BinaryNode<AnyType> {
AnyType element;
BinaryNode<AnyType> left;
BinaryNode<AnyType> right;
public BinaryNode(AnyType x) {
this.element = x;
}
}
public static void preOrder(BinaryNode root) {
if (root == null) return;
System.out.print(root.element + " "); // 输出根节点
preOrder(root.left); // 访问左节点
preOrder(root.right); // 访问右节点
}
public static void preOrder(BinaryNode root) {
Stack stack = new Stack(); // 初始化栈
BinaryNode node = root;
while (node != null || stack.size() > 0) {
if (node != null) {
System.out.print(node.element + " "); // 输出根节点
stack.add(node); // 根节点入栈
node = node.left; // 访问根节点左子树
} else {
BinaryNode temp = (BinaryNode)stack.pop(); //左子树为空,其父节点出栈(获取该父节点)
node = temp.right; // 访问其右节点
}
}
}
基本思路:
易错点:
public static void inOrder(BinaryNode root) {
if (root == null) return;
inOrder(root.left); // 访问左节点
System.out.print(root.element + " "); // 输出根节点
inOrder(root.right); // 访问右节点
}
public static void inOrder(BinaryNode root) {
Stack stack = new Stack(); //初始化栈
BinaryNode node = root;
while (node != null || stack.size() > 0) {
if (node != null) {
stack.push(node); // 根节点入栈
node = node.left; // 访问左节点
} else {
BinaryNode tempNode = (BinaryNode) stack.pop(); // 当该节点为空时,弹出该节点的父节点(即该节点的父节点没有左孩子)
System.out.print(tempNode.element + " "); // 输出该节点的父节点
node = tempNode.right; // 访问其右节点
}
}
}
基本思路:
public static void postOrder(BinaryNode root) {
if (root == null) return;
postOrder(root.left); // 访问左节点
postOrder(root.right); // 访问右节点
System.out.print(root.element + " "); // 输出根节点
}
/**
* 1. 从根节点开始,依次往下遍历左孩子,并入栈
* 2. 若左孩子为空,访问栈顶,判断栈顶的右孩子是否为空,若不为空,且没有被访问过,则重复1.
* 3. 若右孩子为空,或被访问过,则栈顶出栈并输出。
*/
public static void postOrder(BinaryNode root) {
Stack stack = new Stack(); // 初始化栈
BinaryNode node = root;
BinaryNode rightNode = null; // 用于判断右节点是否被遍历过
while (node != null || stack.size() > 0) {
if (node != null) {
// 节点不为空,入栈,并访问其左孩子
stack.add(node);
node = node.left;
} else {
BinaryNode topNode = (BinaryNode) stack.peek(); // 读栈顶元素
if (topNode.right != null && topNode.right != rightNode) {
// 栈顶的右孩子不为空且没有被访问过
node = topNode.right; // 访问栈顶右孩子,并入栈
stack.add(node);
node = node.left; // 重复1,访问栈顶右孩子的左孩子
} else {
stack.pop(); // 栈顶的右孩子为空,或被访问过,则栈顶出栈,并输出
System.out.print(topNode.element + " ");
rightNode = topNode; // 记录当前节点,以便于栈顶元素判断右孩子是否被访问过
node = null; // 每次出栈访问完一个节点,就相当于遍历完以该节点为根的子树,需将node重置为null,这样下一轮,就会认为左子树为空,然后去判断右子树去了,否则,左孩子就会不断地入栈出栈,陷入死循环。
}
}
}
}
基本思路:
易错点:
while中的判断思路,这个到考场容易想不起来,容易乱:
public static void levelOrder(BinaryNode root) {
if (root == null) return;
Queue q = new ArrayDeque(); // 初始化队列
q.add(root); // 根节点入队
while (q.size() > 0) {
BinaryNode tempNode = (BinaryNode) q.poll(); // 如果队列不为空,出队并输出
System.out.print(tempNode.element+ " ");
if (tempNode.left != null) q.add(tempNode.left); // 将该节点的左孩子和右孩子依次入队
if (tempNode.right != null) q.add(tempNode.right);
}
}
普通树Java定义
public class TreeNode<AnyType> {
AnyType element;
TreeNode<AnyType> firstChild;
TreeNode<AnyType> nextSibling; // sibling: 兄弟姐妹
public TreeNode (AnyType x) {
this.element = x;
}
}
二叉树转普通树反过来即可
private static void transferToBinaryTree(TreeNode treeNode, BinaryNode binaryNode) {
if (treeNode.firstChild != null) {
binaryNode.left = new BinaryNode(treeNode.firstChild.element);
transferToBinaryTree(treeNode.firstChild, binaryNode.left);
}
if (treeNode.nextSibling != null) {
binaryNode.right = new BinaryNode(treeNode.nextSibling.element);
transferToBinaryTree(treeNode.nextSibling, binaryNode.right);
}
}
/**
* 1. 首先构造根节点。然后开始递归
* 2. 判断firstChild是否为空,若不为空,则链接到二叉树的左孩子,递归进入下一层firstChild,否则到3
* 3. 判断nextSibling(右兄弟)是否为空,若不为空,则链接到二叉树的右孩子,递归进入下一层nextSibling,否则退出到上层递归。
*/
public static BinaryNode transferToBinaryTree(TreeNode treeRoot) {
if (treeRoot == null) return null;
BinaryNode binaryRoot = new BinaryNode(treeRoot.element);
transferToBinaryTree(treeRoot, binaryRoot);
return binaryRoot;
}
todo ,应该不考,有时间再弄
private static void transferToTree(BinaryNode binaryNode, TreeNode treeNode) {
if (binaryNode.left != null) {
treeNode.firstChild = new TreeNode(binaryNode.left.element);
transferToTree(binaryNode.left, treeNode.firstChild);
}
if (binaryNode.right != null) {
treeNode.nextSibling = new TreeNode(binaryNode.right.element);
transferToTree(binaryNode.right, treeNode.nextSibling);
}
}
/**
* 1. 构造普通树的根节点,然后开始递归
* 2. 判断是否有左孩子,若有左孩子,则链接到tree的左节点,然后递归进入下一层,否则进入3
* 3. 判断是否有右孩子,若有右孩子,则链接到tree的nextSibling(右兄弟),然后递归下一层。
*/
public static TreeNode transferToTree(BinaryNode root) {
if (root == null) return null;
TreeNode treeNode = new TreeNode(root.element);
transferToTree(root, treeNode);
return treeNode;
}
todo,应该不考,有时间弄