【刷题日记】树的那些事儿(一)——基本操作

树在面试中真的是一个出镜率异常高的数据结构了。而且和递归结合紧密,作为手撸代码的考察真是再合适不过。
所以就在这篇日记里不断更新树的一些概念和相应的题目吧~
我的梦想是!一文在手!天下我有!

树的手撸代码中常常涉及到的知识

  • 树的深度
    • 递归 / 非递归
  • 树的高度
    • 递归
    • 非递归: 可以层序
    • 平衡树
  • 树的结点
    • 结点数
    • 求下一个结点:前中后序
  • 数的遍历
    • 前中后序遍历
      • 递归
      • 非递归:栈/队列辅助
    • 层序遍历(队列辅助)
      • 层序遍历一棵树
      • 逐层打印一棵树
      • 之字形打印一棵树等等
    • 前序+中序 / 后序+中序重建一棵树
  • 子树
  • 树的镜像
  • 二叉树
  • 二叉平衡树
    • 左右子树高度差不超过1
  • 二叉搜索树
    • 左子树永远小于等于右子树
  • 树的路径

面试还可能问到

  • 红黑树
  • B树
  • B+树

先写一棵树

你一定要会写树的结点定义啊

# 没有指向老父亲的结点指针的树结点
class TreeNode():
	def __init__(self,x):
		self.val = x
		self.left = None
		self.right = None
# 有指向父亲的结点指针的树结点
class TreeNode2():
	def __init__(self,x):
		self.val = x
		self.left = None
		self.right = None
		self.next = None # 父指针

然后呢?结点写出来了不会写出一棵树来测试自己的代码丢不丢人。。。

# Test:
#        10
#       /  \
#      5   12
#     / \     
#    4   7
value = [10,5,12,4,7]
node = []
# 初始化这些结点
for val in value:
	node.append(TreeNode(val))
# 然后把结点连起来
node[0].left = node[1]
node[0].right = node[2]
node[1].left = node[3]
node[1].right = node[4]

# 或者这样
node_var = [10,9,8,7,6,5]
node = []
for item in node_var:
    node.append(TreeNode(item))

i = 0
while 2*i+1<len(node):
    node[i].left = node[2*i+1]
    if 2*i+2<len(node):
        node[i].right = node[2*i+2]
    i+=1

然后是树的遍历!

这个不管是递归还是非递归,手撸的概率很高。之前阿里的暑期实习就要求我写一个非递归的中序遍历。
非递归可以写出各种版本。但是可以用一个统一的逻辑概括起来。便于记住。如下图所示。
在这里插入图片描述
当然还可以有其他逻辑。我就不贴出来了。
太多会乱。统一起来便于记忆!
详细的递归 / 非递归代码如下

class Tranverse():
	# 递归先序
	def preOrderIter(self,root):
		if not root:
			return []
		res =[]
		res.append(root.val)
		left = self.preOrderIter(root.left)
		right = self.preOrderIter(root.right)
		res += left+right
		return res
	# 非递归先序
	# 用一个栈辅助的话,先右孩子在左孩子入栈
	# 用一个队列,那就pop(0),先左后右
	def preOrderNoIter(self,root):
		if not root:
			return []
		res =[]
		stack =[root]
		while stack:
			# 元素出栈
			root = stack.pop()
			# 访问这个元素
			res.append(root.val)
			# 先右
			if root.right:
				stack.append(root.right)
			# 再左
			if root.left:
				stack.append(root.left)
		return res

	# 递归中序
	def inOrderIter(self,root):
		if not root:
			return []
		res =[]
		left = self.inOrderIter(root.left)
		res += left
		res.append(root.val)
		right = self.inOrderIter(root.right)
		res += right
		return res

	# 非递归中序
	def inOrderNoIter(self,root):
		if not root:
			return []
		res =[]
		stack =[]
		# 如果栈不空或者结点存在
		while stack or root:
			#结点存在
			while root:
				# 结点入栈并向左子树
				stack.append(root)
				root = root.left
			# 左孩子空了跳出循环。如果栈不空
			if stack:
				# 元素出栈并访问
				root = stack.pop()
				res.append(root.val)
				# 然后访问右子树
				root = root.right
		return res

	# 递归后序
	def postOrderIter(self,root):
		if not root:
			return []
		res =[]
		left = self.postOrderIter(root.left)
		right = self.postOrderIter(root.right)
		res += left+right
		res.append(root.val)
		return res
	
	# 非递归后序
	# 按照根-右-左的顺序存储到res,然后倒序输出
	# 可以直接对照先序非递归来写
	def postOrderNoIter1(self,root):
		if not root:
			return []
		stack = [root]
		res = []
		while stack:
			root = stack.pop()
			# res 存储根
			res.append(root.val)
			# 先压栈左孩子,之后会后存入res
			if root.left:
				stack.append(root.left)
			# 后压入右孩子,之后会先弹出先存入res
			if root.right:
				stack.append(root.right)
		return res[::-1]
			
	def postOrderNoIter2(self,root):
		if not root:
			return []
		res = []
		stack =[]
		while stack or root:
			while root:
				stack.append(root)
				res.append(root.val)
				root = root.right
			if stack:
				root = stack.pop()
				root = root.left
		return res[::-1]

	# 层序遍历
	def layerOrder(self,root):
		if not root:
			return []
		res =[]
		queue =[root]
		while len(queue)>0:
			root = queue.pop(0)
			res.append(root.val)
			if root.left:
				queue.append(root.left)
			if root.right:
				queue.append(root.right)
		return res

然后数一下树的结点

其实数树的的结点数有很多办法。
比如可以用任意一种遍历,每次访问一个结点就计数。或者返回结点值列表的长度。
也可以这样直接递归数:

def treeNodeNums(root):
	if not root:
		return 0
	nums = treeNodeNums(root.left)+treeNodeNums(root.right) + 1
	# 当然这里也可以写:
	# left = treeNodeNums(root.left)
	# right = treeNodeNums(root.right)
	# nums = left+right+1
	return nums

再然后求一下树的深度

树的深度当然也可以用递归或者非递归方法求。
非递归的话可以借助一下层序遍历
递归的话就很类似于数结点数了:

def treeDepth(root):
	if not root:
		return 0
	# 左子树深度
	left = treeDepth(root.left)
	# 右子树深度
	right = treeDepth(root.right)
	return max(left,right)+1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值