第四章笔记——深度优先遍历算法

第四章 深度优先遍历算法

4.1 什么是深度优先遍历

深度优先遍历算法是经典的图论算法,从某个节点v触发开始搜索,不断搜索直到该节点的所有边都被遍历完。当节点v的所有边都被遍历后,深度优先遍历算法则需要回溯到v的前驱节点,来继续搜索这个前驱节点的其他边。

注意:深度优先遍历问题一定要按照规则尝试所有的可能才行。

4.2 二叉树

二叉树是一种特殊的数据结构。二叉树中的每一个节点都有两个分支,称为“左子树”与“右子树”。如图所示,二叉树中的每一层最多有2^n -1个节点。和普通树不同,普通树的节点没有分支限制,并且普通树的节点没有左、右子树之分。
在这里插入图片描述
1、二叉树的类型

  1. 空二叉树:有零个节点。
  2. 满二叉树:每一个节点都有零活两个节点。
  3. 完美二叉树:每一层的节点都是满的。
  4. 完全二叉树:除了最后一层,每一层的节点都是满的,并且最后一层的节点全部从左排序。
  5. 平衡二叉树:每个节点的两个子树的深度相差不超过1。

2、二叉树的相关术语

  1. 度:节点的度为节点的子树个数
  2. 叶子节点:度为零的节点
  3. 分支节点:度不为零的节点
  4. 孩子节点:节点下的两个子节点
  5. 双亲节点:节点上一层的源头节点
  6. 兄弟节点:拥有同一个双亲节点的节点
  7. 根:二叉树的源头节点
  8. 深度:二叉树中节点的层的数量

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]	# 输出小偷可获得的最大金额
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值