第四章 深度优先遍历算法
4.1 什么是深度优先遍历
深度优先遍历算法是经典的图论算法,从某个节点v触发开始搜索,不断搜索直到该节点的所有边都被遍历完。当节点v的所有边都被遍历后,深度优先遍历算法则需要回溯到v的前驱节点,来继续搜索这个前驱节点的其他边。
注意:深度优先遍历问题一定要按照规则尝试所有的可能才行。
4.2 二叉树
二叉树是一种特殊的数据结构。二叉树中的每一个节点都有两个分支,称为“左子树”与“右子树”。如图所示,二叉树中的每一层最多有2^n -1个节点。和普通树不同,普通树的节点没有分支限制,并且普通树的节点没有左、右子树之分。
1、二叉树的类型
- 空二叉树:有零个节点。
- 满二叉树:每一个节点都有零活两个节点。
- 完美二叉树:每一层的节点都是满的。
- 完全二叉树:除了最后一层,每一层的节点都是满的,并且最后一层的节点全部从左排序。
- 平衡二叉树:每个节点的两个子树的深度相差不超过1。
2、二叉树的相关术语
- 度:节点的度为节点的子树个数
- 叶子节点:度为零的节点
- 分支节点:度不为零的节点
- 孩子节点:节点下的两个子节点
- 双亲节点:节点上一层的源头节点
- 兄弟节点:拥有同一个双亲节点的节点
- 根:二叉树的源头节点
- 深度:二叉树中节点的层的数量
3、二叉树的节点代码
因为每一个节点都与两个子节点相连,所以我们只需要拥有根节点就能找到二叉树上的任意节点。每一个节点的定义都是相同的,代码如下:
class Node: # 二叉树节点的定义
def __init__(self, x):
self.val = x # 节点值
self.left = None # 左侧子节点
self.right = None # 右侧子节点
4、二叉树的遍历顺序
二叉树有三种遍历顺序:DLR(先序)、LDR(中序)、LRD(后序)。L/R/D分别代表左子树、右子树和根。
DLR:1-2-4-5-3-6-7
LDR:4-2-5-1-6-3-7
LRD:4-5-2-6-7-3-1
5、 深度优先遍历和广度优先遍历
在深度优先遍历中,我们从根节点出发直奔最远的节点。在广度优先遍历中,我们首先访问离根节点最近的节点,按层递进。以广度优先的顺序遍历,顺序为:1-2-3-4-5-6-7
4.3 怎么捉住小偷
除了第一栋别墅,每一栋别墅都与另一栋“源头”别墅连接。一旦小偷闯入两栋相连接的别墅,就会触发警铃。怎么样在不触发警铃的情况下偷得最多?模型为二叉树模型。
1、解题思路
经过分析得到规律:每一个节点的偷值都是:左侧子节点的不偷值+右侧子节点的不偷值+节点的财富;每一个节点的不偷值都是:左侧子节点的最大值+右侧子节点的最大值。
如果节点定义为:
class TreeNode: # 二叉树节点的定义
def __init__(self, x):
self.val = x # 节点值
self.left = None # 左侧子节点
self.right = None # 右侧子节点
那么任意一个节点(用root表示)的偷值(robValue)与不偷值(skipValue)则表达为:
robValue = root.val + root.left.skipValue + root.right.skipValue
skipValue = max(root.left.robValue, root.left.skipValue) + max(root.right.robValue, root.right.skipValue)
现在需要解决的问题是,如何得到子节点的偷值与不偷值。
答案很简单,只要找到子节点的子节点的偷值和不偷值就可以了(套娃)。
2、从思路到代码
def rob(self, root):
a = self.helper(root) # a是一个二维数组,为root的[偷值,不偷值]
return max(a[0], a[1])
def helper(self, root): # 参数root为节点,helper方法输出一个二维数组:root节点的[偷值,不偷值]
if(root==None): # 如果root节点为空,输出[0,0]
return [0,0]
left = self.helper(root.left) # left是一个二维数组,为root左侧子节点的[偷值,不偷值]
right = self.helper(root.right) # right是一个二维数组,为root右侧子节点的[偷值,不偷值]
robValue = root.val + left[1] + right[1] # root的偷值
skipValue = max(left[0], left[1]) + max(right[0], right[1]) # root的不偷值
return [robValue, skipValue] # 输出小偷可获得的最大金额