说明
树,作为一种非线性结构(一对多),其逻辑结构与存储结构都跟数组不同,不能像数组一样根据索引值的加减来直接访问相邻元素的值。而是需要指针作为媒介,才能间接访问。
先实践后理论,我们先看一道练习题:LeetCode 513题:找出下左树的值1.
如题,给定一个二叉树,找出树中最后一行最下左的结点值
示例
简要分析
要找到并返回最左下子树的值,则我们必须使最左下结点为最后访问的结点。类比一下我们熟悉的三种二叉树遍历方式,则只要使得在每个子树中左侧结点都是最后一个访问的即可,也就是逆序的中序遍历RNL。
RNL的递归实现为(C实现):
void InOrder(struct TreeNode* root){
if(root == NULL) return;
InOrder(root->right);
printf("%d", root->val);
InOrder(root->left);
}
该代码保证了最后一个访问的结点是最左下结点,但是存在的一个问题是当从我们需要返回最左下结点值而非只是打印出来,而且当我们退出迭代函数时其存储在栈的临时变量被销毁不能再访问。这就需要我们用 非递归的方法实现 RNL访问顺序,也就是借助队列这一数据结构来保存临时变量。
代码如下(java实现):
class Solution {
public int findBottomLeft (TreeNode root){
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
root = queue.poll();
if(root.right != null)
queue.add(root.right);
if(root.left != null)
queue.add(root.left);
}
return root.val;
}
}
总结
在解决编程问题时,总是算法先行,再考虑使用特定的数据结构来优化程序效率。此处NRL的递归实现使用队列进行优化,而递归和动态规划的关系也是如此。
任一数学递推式都可以用递归来表示,但有时候会造成内存浪费,导致程序执行效率低,而动态规划就可以理解为优化递归的手段之一2,本内容将在下一篇博客展开。
- LeetCode 513. Find Bottom Left Tree Value ↩
- Mark Allen Weiss, “Data Structures and Algorithm Analysis in C”, 2th Edition. ↩