数组、链表、二叉树、动态规划、栈与队列是面试中常考的知识点,而在这几个知识点中,二叉树属于难度比较大的部分,因此在这里总结一下二叉树常考的操作,包括:
(1)二叉树的递归遍历;
(2)二叉树的非递归遍历;
(3)求二叉树叶子节点的个数;
(4)求二叉树的深度;
(5)在二叉树中查找某颗子树;
(6)求二叉树中和为某个值的路径;
(7)求二叉树中的最大路径和;
(8)二叉树的镜像;
(9)判断某个序列是否是二叉搜索树的后序遍历序列;
(10)二叉搜索树和双向链表的相互转换;
(11)树中两个结点的最近祖先;
(12)二叉树搜索树的插入与删除;
(13)堆的插入与删除;
(14)判断一棵树是不是平衡二叉树;
(15)平衡二叉树的调整;
(1)二叉树的递归遍历
递归的形式非常简洁,几行代码即可搞定。前序、后序、中序遍历的形式基本一样,只是输出结点值的时机不一样。
基本思想:如果该结点为叶结点,则直接返回,否则,看该结点的左孩子是否为空,如果不为空,则递归的遍历其左孩子;接着看其右孩子是否为空,如果不为空,则递归的遍历其右孩子;
代码实现:
def PreOrder_recursion(rootnode):
if rootnode == None:
return
print(rootnode.val)
if rootnode.left != None:
PreOrder_recursion(rootnode.left)
if rootnode.right != None:
PreOrder_recursion(rootnode.right)
return
def MidOrder_recursion(rootnode):
if rootnode == None:
return
if rootnode.left != None:
MidOrder_recursion(rootnode.left)
print(rootnode.val)
if rootnode.right != None:
MidOrder_recursion(rootnode.right)
return
def BackOrder_recursion(rootnode):
if rootnode == None:
return
if rootnode.left != None:
BackOrder_recursion(rootnode.left)
if rootnode.right != None:
BackOrder_recursion(rootnode.right)
print(rootnode.val)
return
(2)二叉树的非递归遍历
基本思想:如果采用非递归遍历,我们需要使用一个栈来模拟函数的递归调用。对于三种遍历方式,我们都采用push当前结点->push左子树->pop左子树->push右子树->pop右子树的方式,只是不同的遍历方式,输出结点值的时机不同。
对于前序遍历来说,每次访问到一个节点,即每次要将节点进栈时,输出该节点的值;【即在左右节点入栈时输出左右子节点的值】
对于中序遍历来说,每次将当前节点的右节点进栈时,输出当前节点的值;【即在右节点进栈、以及pop叶节点的时候,输出当前节点的值】
对于后序遍历来说,每次将节点从栈中弹出的时候,输出当前节点的值。【即在pop的时候输出当前节点的值】
另外,我们还需要一个last_pop指针来记录上次pop的节点;
如果当前节点的左节点非空,并且左节点和子节点都不是上次last_pop,则将左节点进栈;
如果当前节点的右节点非空,也不是last_pop,且当前节点的左节点为空或者左节点是last_pop,则将右节点进栈;
否则的话,让当前节点出栈,让当前节点标记为last_pop。
当前结点被pop有两种情况,一是当前结点为叶节点(左节点 和右节点都为空),二是当前结点的左右结点都已经被访问过了(右节点为last_pop)
二叉树的前序、中序、后序遍历采用的都是深度优先策略。
代码实现:
def PreOrder_Norecursion(rootnode):
stack = []
stack.append(rootnode)
print(rootnode.val,end="")
last_pop = rootnode
while len(stack) != 0:
curnode = stack[-1]
if curnode.left != None and curnode.left != last_pop and curnode.right != last_pop:
stack.append(curnode.left)
print(curnode.left.val,end="")
elif curnode.right != None and curnode.right != last_pop and (curnode.left == None or curnode.left == last_pop):
stack.append(curnode.right)
print(curnode.right.val,end="")
else:
stack.pop()
last_pop = curnode
return
def MidOrder_Norecursion(rootnode):
stack = []
stack.append(rootnode)
last_pop = rootnode
while len(stack) != 0:
curnode = stack[-1]
if curnode.left != None and curnode.left != last_pop and curnode.right != last_pop:
stack.append(curnode.left)
elif curnode.right != None and curnode.right != last_pop and (curnode.left == None or curnode.left == last_pop):
stack.append(curnode.right)
print(curnode.val,end="")
else:
stack.pop()
last_pop = curnode
if curnode.right == None:
print(curnode.val,end="")
return
def BackOrder_Norecursion(rootnode):
stack = []
stack.append(rootnode)
last_pop = rootnode
while len(stack) != 0:
curnode = stack[-1]
if curnode.left != None and curnode.left != last_pop and curnode.right != last_pop:
stack.append(curnode.left)
elif curnode.right != None and curnode.right != last_pop and (curnode.left == None or curnode.left == last_pop):
stack.append(curnode.right)
else:
stack.pop()
last_pop = curnode
print(curnode.val,end="")
return
(3)二叉树种叶子节点的个数
基本思路:使用变量leaf_count对叶节点进行计数,在遍历二叉树时,如果遇到叶节点,则leaf_count 的值加1。
代码实现:
def LeafNums_Norecursion(rootnode):
leaf_count = 0
stack = []
stack.append(rootnode)
last_pop = rootnode
while len(stack) != 0:
curnode = stack[-1]
if curnode.left != None and curnode.left != last_pop and curnode.right != last_pop:
stack.append(curnode.left)
elif curnode.right != None and curnode.right != last_pop and (curnode.left == None or curnode.left == last_pop):
stack.append(curnode.right)
else:
stack.pop()
last_pop = curnode
if curnode.left == None and curnode.right == None:
leaf_count += 1
return leaf_count
leaf_count2 = 0
def LeafNums_Recursion(rootnode):
if rootnode == None:
return
if rootnode.left == None and rootnode.right == None:
global leaf_count2
leaf_count2 += 1
if rootnode.left != None:
LeafNums_Recursion(rootnode.left)
if rootnode.right != None:
LeafNums_Recursion(rootnode.right)
return
(4)二叉树的深度
基本思想:
(1)递归:如果节点为空,则深度为0,否则,该树的深度等于左子树的深度与右子树深度的最大值+1
(2)非递归:stack模拟函数的递归调用,那么栈中元素的最大数量即为树的深度。
代码实现:
def Maxdepth_Recursion1(rootnode):
# 遇到空节点才返回
if rootnode == None:
return 0
left_depth = Maxdepth_Recursion1(rootnode.left)
right_depth = Maxdepth_Recursion1(rootnode.right)
root_depth = max(left_depth, right_depth) + 1
return root_depth
def Maxdepth_Recursion2(rootnode):
# 遇到叶节点或者空节点,返回,避免多递归一层。
if rootnode == None:
return 0
if rootnode.left == None and rootnode.right == None:
return 1
left_depth = 0
if rootnode.left != None:
left_depth = Maxdepth_Recursion2(rootnode.left)
right_node = 0
if rootnode.right != None:
right_depth = Maxdepth_Recursion2(rootnode.right)
root_depth = 0
root_depth = max(left_depth, right_depth) + 1
return root_depth
def Maxdepth_NoRecursion(rootnode):
stack = []
stack.append(rootnode)
last_pop = rootnode
depth = 0
while len(stack) != 0:
curnode = stack[-1]
depth = max(len(stack), depth)
if curnode.left != None and curnode.left != last_pop and curnode.right != last_pop:
stack.append(curnode.left)
elif curnode.right != None and curnode.right != last_pop and (curnode.left == None or curnode.left == last_pop):
stack.append(curnode.right)
else:
stack.pop()
last_pop = curnode
return depth
>>下一篇:通用算法 - [树结构] -二叉树的一些基本操作(二)