数据结构(七):二叉树的删除和应用举例
今天这节课,我们讲一下与二叉树相关的最后一个问题,如何从二叉树里删除一个元素。以及举个例子来看怎么使用二叉树。本节课是小密圈《进击的Java新人》第五周的第四节课。
删除结点
第一种情况,如果待删除结点只有一个孩子,那么直接把这一个孩子挂接在待删结点的父亲结点上即可,无论这个孩子是左子树还是右子树都不会有区别。第二种情况,如果待删除结点有两个孩子,那么待删除结点的中序后继一定是在右子树上。而且后继结点最多只会有一个右孩子,一定不会有左孩子。把后继结点中的值拷贝到待删除结点后,就变成了第一种情况,这时再删除后继结点即可。如图2.3所示。(a)中蓝色表示待删除结点,因为它有两个孩子,所以无法将其直接从树中去掉,红色结点为蓝色结点的中序后继;(b)中把后继中的值拷贝到待删除结点中去;(c)只需要将红色结点删除即可。
然后看一下删除的代码。
public void remove(Node<T> n) {
Node<T> p = n.parent;
Node<T> next, child;
// 叶子结点,直接删除即可。要考虑待删除结点是root的情况。
if (n.left == null && n.right == null) {
if (n == root) {
root = null;
return;
}
if (n == p.left)
p.left = null;
else if (n == p.right)
p.right = null;
}
// 内部结点,把它的后继的值拷进来,然后递归删除它的后继。
else if (n.left != null && n.right != null) {
next = successor(n);
n.data = next.data;
remove(next);
}
// 只有一个孩子的结点,把它的孩子交给它的父结点即可。
else {
if (n.left != null)
child = n.left;
else
child = n.right;
if (n == root) {
child.parent = null;
root = child;
return;
}
if (n == p.left) {
child.parent = p;
p.left = child;
}
else {
child.parent = p;
p.right = child;
}
}
}
好了。二叉树的基本操作,我们就介绍完了。接下来,我会介绍一下与二叉树相关的应用,以及与二叉树的性质相关的题目。
四则运算表达式的语法树
学完了二叉树,我们再回过头来看表达式求值。表达式求值,是个大宝库啊,我们通过它挖掘了很多知识。这一次,我们还是用递归下降的方法去处理,只是不再直接求值了,而是把它转化成一棵树。例如,(1+2)*3,我们把它转成下图这个样子:

后序遍历这棵树的结果是12+3*,这就是我们习题中所讲过的逆波兰表达式,也叫后缀表达式,大家还记得吗?实际上,我们在后序遍历这棵树的同时,也可以把表达式的值给求出来。但我们还有更远大的目标(不是星辰大海),我们能把这个翻译成Java字节码,最终变成class文件存起来,然后使用java程序去执行它。这是后话,我们今天先看,怎么得到这棵树,以及如何通过遍历树来计算表达式求值。
实际上,这棵树,就是大名鼎鼎的语法树。所有的编译器都会经过词法分析,文法分析,然后得到语法树,再在语法树上进行各种初步的优化,再由它生成机器码(或者是字节码)。我们以后还经常会和这棵树打交道。
其实,这个过程也很简单,那就是递归下降分析的时候,原来是求值,现在把值转成树上的结点就好了。代码很简单,如果做过前边的习题的同学,看一眼就知道,其实代码并没有发生太多变化,只是从原来的直接求值变成了返回一个二叉树结点。
public class BinaryTreeExpression {
public TokenStream ts;
public static void main(String args[]) {
BinaryTreeExpression e = new BinaryTreeExpression();
BinarySearchTree<Token> bst = new BinarySearchTree<Token>();
bst.root = e.expression();
bst.postOrder(bst.root);
}
public BinaryTreeExpression() {
ts = new ExpressionTokenStream(new BufferedInputStream(System.in));
}
public Node<Token> expression() {
Node<Token> left = term();
try {
if (match(PLUS)) {
Node<Token> root = new Node<>(new Token(Token.TokenType.PLUS, "+"));
root.left = left;
root.right = expression();
return root;
}
else if (match(MINUS)) {
Node<Token> root = new Node<>(new Token(Token.TokenType.MINUS, "-"));
root.left = left;
root.right = expression();
return root;
}
} catch (IOException e) {
e.printStackTrace();
}
return left;
}
private Node<Token> term() {
Node<Token> left = factor();
try {
if (match(MULT)) {
Node<Token> root = new Node<>(new Token(Token.TokenType.MULT, "*"));
root.left = left;
root.right 