面试中的二叉树问题
二叉树中每个节点都有类似下面的定义
struct Node { int data; Node *left, *right; };
树的主要特征是树的每一个节点都可以看成是另外一棵树的根节点。因此任何对树的操作都可以分成三部分完成 1)对根节点的操作,2)对左子树的操作,3)对右子树的操作。根据这三种操作的先后次序,产生了三种不同的遍历方法:前序遍历(123),中序遍历(213),后续遍历(231)。因为树的定义本身就是递归定义的,所以大部分和二叉树有关的问题都可以用递归算法写出来。
Ex 1. 二叉树的最大深度
int depth(Node *root) //二叉树的深度等于1 + max{左子树的深度,右子树的深度} { if(root == 0) return 0; else { int depth1 = depth(root->left); int depth2 = depth(root->right); return depth1 > depth2 ? depth1 + 1 : depth2 + 1; } }
Ex 2. 二叉树中2个节点node1, node2的最小公共祖先节点
在后续遍历中,父节点总是在它的子节点之后遍历。所以node1, node2的最小公共祖先节点就是在遍历完它们之后遇见的第一个祖先节点。为了判断一个节点是否是他们的祖先节点,我们在遍历的时候保存一个计数器。1) 每一个节点的计数 = 左子节点的计数 + 右子节点的计数, 2)如果当前节点是node1或者node2,计数器+1。如果当前节点的计数等于2, 当前节点就是node1和node2的祖先节点。所以我们需要找到在后续遍历中第一个计数为2的节点。
//**ancestor保存找到的最小公共祖先节点,count保存root的计数 void commonAncestorHelper(Node *root, Node *node1, Node *node2, Node **ancestor, int* count) { if(root == 0 || *ancestor != 0) //如果已经找到祖先节点,直接返回 return; int count1 = 0; int count2 = 0; //后续遍历 commonAncestorHelper(root->left, node1, node2, ancestor, &count1); commonAncestorHelper(root->right, node1, node2, ancestor, &count2); if(*ancestor != 0) //如果已经找到祖先节点,直接返回 return; //计算当前节点的计数 *count = count1 + count2; if(root == node1) ++(*count); if(root == node2) ++(*count); if(*count == 2) { *ancestor = root; return; } } Node* commonAncestor(Node *root, Node *node1, Node* node2) { if(root == 0) return 0; int count = 0; Node *ancestor = 0; commonAncestorHelper(root, node1, node2, &ancestor, &count); return ancestor; }