前言
这两天在刷二叉树的深度和平衡二叉树的题,深感觉有点吃力,不是cs专业,还得一点一点地积累学习。在此篇博客里,将好好的学习理解递归函数的运用,以及其在二叉树中的运用。
--------------------------------------
递归
通俗的理解:在我们使用词典的时候,本身可以理解为一个递归。比如我们在查一个英语单词recursion的时候,但是为了更好的理解recursion这个单词,我们去看带有recursion单词的例句A。但是A例句中如果含有一个单词b我不认识,这时候为了更好的扫盲,我们会去查b单词的意思。但是包含b单词的例句C中又有不认识的单词d,我们可能又去查d单词的意思。依次往后,直到最后一个单词的例句我们了全明白了。那么这就是递归到尽头了,然后开始从后往前倒退,逐个查明了每一个单词以及理解了它的例句。最终我们理解了最开始要查的单词recursion这个词的意思。递归将问题不断从大到小,从近到远的过程中,会有一个终点或临界点或baseline point,这时候“反弹”,从这个此点返回到原点。
形象理解:
(图来自知乎:https://www.zhihu.com/question/20507130)
定义:recursion is the process of repeating items in a self-similar way.
递归和循环的区别:递归是静中有动,有去有回。循环是动静如一,有去无回。
用法举例:斐波拉契数列。在定义函数里面,不断的调用自己。
def fib(n):
if n == 0 or n == 1: #Base case
return 1
else:
return fib(n-1) + fib(n-2) #recursive case
--------------------------------------
二叉树
二叉树定义:Binary tree/ 二叉树是一种树形结构,它的特点是每个结点至多有两颗子树,并且,二叉树的子树左右之分,其次序不能任意颠倒。
(图来自知乎 :https://zhuanlan.zhihu.com/p/24800009)
此二叉树有三层,第一层一个结点为1,第二层两个结点为2和3,第三次两个结点为4和5.结点的最大层数为3,所以高度为3;共三个叶结点,分别为2,4,5。两个非叶结点为1和3。树的高度和深度的区别:高度为从结点x向下到某个叶结点最长简单路径中边的条数。 对于整颗树来说,最深的叶结点的深度就是树的深度;树根的高度就是树的高度。这样树的高度和深度是相等的。
二叉查找树:二叉查找树的规则是,它的左孩子的所有结点值都比该结点小,但是右结点所有结点值都比该点大。与结点值相同的结点可以放左孩子或右孩子上都行。
--------------------------------------
递归在二叉树中的运用
剑指offer:二叉树的深度
题目描述:输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def TreeDepth(self, pRoot):
# write code here
#我的思路:使用递归的方法,计数递归的深度
#递归的话,得确定边界以及递归条件。两边同时进行
if not pRoot:
return 0 #判断是不是空结点,同时在递归中也可视为边界条件。
right_d=self.TreeDepth(pRoot.right) #递归函数即是调用本身的函数,但是函数变量需要改变,树结点分左右结点。
left_d=self.TreeDepth(pRoot.left) #同理
return right_d+1 if right_d>left_d el #递归函数调用自己函数,同时一步一步往里面调用,没有到边界不返回值。到边界之后开始返回值0。最里面的返回值为0后,那么次一级的返回为+1,这样就能比较出深度的大小了。
剑指offer:平衡二叉树
题目描述:输入一棵二叉树,判断该二叉树是否是平衡二叉树。
平衡二叉树的判断方法:平衡二叉树又称为AVL树。它或者是空树,或者就是左右子树的深度差不能大于1。
递归解法:[1] 如果二叉树为空,返回真。[2]如果二叉树不为空,如果左右子树都是AVL树并且左子树和右子树高度差不大于1,返回真,其他返回假。
class Solution:
res = True #定义结果为正确,用来判断。
def IsBalanced_Solution(self, pRoot):
# write code here
self.helper(pRoot) #引入子函数,子函数变量为输入的pRoot,子函数用来判断是不是平衡二叉树。
return self.res #结果为对或者不对。总体上这三步确定了框架
#平衡二叉树的判断条件,判断条件为左右子树结点的深度不能超过1。
def helper(self,root): #定义子函数,其传入进来的为pRoot.
if not root: #首先根结点是不是空结点,如果不是的话,返回0.相当于false。同时也是递归函数的判断边界。
return 0 #相当于false
#if not self.res : return 1
left = 1 + self.helper(root.left) #左递归函数 求深度。记得加1.
right = 1 + self.helper(root.right) #右递归函数,求深度,记得加1.
if abs(left-right)>1: #判断深度差是否大于1 abs()为求绝对值!!
self.res = False #如果是的话,定义结果为false
return max(left,right) #返回最大的值
--------------------------------------
总结
[1]:递归可以理解为将问题从远到近,从外到里面,找到那个边界/临界点(调入);再从临界点往外不断的返回,这样就是递归。(往里面递,往外归还)
[2]:二叉树有很多性质,同时也有很多遍历的方法,没有办法全部记录下来了。只能doing under demand,learn by doing。这张主要是想着重了解递归在二叉树深度求法中的运用,重点是理解。在树递归函数中,分别调用左子树和右子树,同时设置边界条件。如果边界条件结点不是头结点,也就是该结点下的子结点为none,那么返回0.从里往外不断返回时候,递归进去几层,返回时候就加了几个1.这样就能求出深度了。左右子树深度最大的为树的深度,左右深度相差不超过1的可以判断是否为平衡二叉树。