龙空技术网

一篇文章读懂系列-2.二叉树及常见面试题

easycome 165

前言:

现在看官们对“计算二叉树高度”都比较注意,我们都需要学习一些“计算二叉树高度”的相关文章。那么小编在网摘上汇集了一些有关“计算二叉树高度””的相关文章,希望咱们能喜欢,姐妹们快快来了解一下吧!

大家通常认知的二叉树如下所示:

数据结构如下定义:

class Node:    def __init__(self,val,left=None,right=None):    	self.val = val      self.left = left      self.right = right

换成链表视角的话,可以这样看待二叉树:

可以理解成常规的链表只有一个next节点,二叉树有两个next节点,只不过我们把这两个next节点通常理解和表示成左孩子和右孩子。既然和链表性质很像,类比来看,可以认为二叉树基本继承了链表的一些性质:

①增加节点和删除节点的效率会比较高,随机访问效率会比较低。

②可以用递归来操作二叉树

实际上,绝大多数情况时候使用递归的形式来操作二叉树,具体做法是对二叉树的左子树和右子树递归进行操作即可。

下面是一些常见的练习或面试题,最好做到熟练掌握:

准备工作,通过函数创建上述二叉树:

arr = [10 ,6 ,4 ,-1, -1, 7, -1 ,9 ,-1 ,-1, 12 ,-1 ,16, 15 ,-1 ,-1 ,20, -1, -1]def create_bin_tree(arr,i):    if arr and i >= len(arr):        return None,i    if arr[i] == -1:        return None,i    tree = Node(arr[i])    tree.left, j = create_bin_tree(arr,i+1)    tree.right,k = create_bin_tree(arr,j+1)    return tree,ktree,_ = create_bin_tree(arr,0)

① 前序遍历:先打印当前节点,然后递归前序访问A,最后递归前序访问B,代码类似如下

def pre_order(tree):    if not tree:        return    print(tree.val)    pre_order(tree.left)    pre_order(tree.right)

②中序遍历:先递归中序访问A,再打印当前节点,最后递归中序访问B,代码:

def mid_order(tree):    if not tree:        return    mid_order(tree.left)    print(tree.val)    mid_order(tree.right)

③后续遍历:先递归后续遍历A,再递归后续遍历B,再访问当前节点

def post_order(tree):    if not tree:        return    post_order(tree.left)    post_order(tree.right)    print(tree.val)

④求二叉树的高度: 先递归求A的高度,再递归求B的高度,取二者中最大值+1

def get_height(tree):    if not tree:        return 0    left_height = get_height(tree.left)    right_height = get_height(tree.right)    return 1+max(left_height,right_height)

⑤求二叉树的镜像: 将当前节点的A和B部分互换,递归求A和B的镜像

def mirror(tree):    if not tree:        return None    temp = tree.left    tree.left = tree.right    tree.right = temp    mirror(tree.left)    mirror(tree.right)    return tree

⑥求二叉树的节点数:先求A的节点数,再求B的节点数,二者的和加1

def get_node_count(node):    if not node:        return 0    left_node_count = get_node_count(node.left)    right_node_count = get_node_count(node.right)    return 1 + left_node_count + right_node_count

⑦求二叉树的叶子节点数:如果当前节点无孩子节点,则返回1;否则递归调用A和B的叶子节点并相加。

def get_leaf_count(node):    if node == None:        return 0    if node.left == None and node.right==None:        return 1    return get_leaf_count(node.left)+get_leaf_count(node.right)

⑧广度遍历二叉树:初始化时,将二叉树的根节点放到队列中;后续每次从队列取一个节点,将其左右孩子放到队列中,接着递归调用即可。

def BFS(queue):    if not queue:        return    node = queue[0]    print(node.val)    if node.left:        queue.append(node.left)    if node.right:        queue.append(node.right)    del queue[0]    BFS(queue)queue = [tree]BFS(queue)

⑨通过前序和中序构建二叉树:

前序:10 6 4 7 9 12 16 15 20

中序:4 6 7 9 10 12 15 16 20

核心思想:通过前序数组可以得知根节点,通过中序可以将根节点的左右孩子,也就是A和B找出来,然后递归调用即可。如下图所示:

通过前序中的第一个元素10将中序数组分成了2部分

本代码的主要细节是下标的处理,见下图所示:

代码如下:

def create_bin_tree_pre_mid(pre_trans,i,j,mid_trans,m,n):    if i>j or m>n:        return None    pivot = pre_trans[i]    s = m    while s<=n:        if mid_trans[s] == pivot:            break        s+=1    node = Node(pre_trans[i])    node.left = create_bin_tree_pre_mid(pre_trans,i+1,i+s-m,mid_trans,m,s-1)    node.right = create_bin_tree_pre_mid(pre_trans,i+s-m+1,j,mid_trans,s+1,n)    return nodetree2 = create_bin_tree_pre_mid(pre_trans,0,len(pre_trans)-1,mid_trans,0,len(mid_trans)-1)

从上面的例子也可以看出,学好递归的重要性,递归本身是一种自顶向下的思维方式,比较容易掌握,实际编程中也非常有用,值得我们练习和掌握。关于递归更深入的例子和探讨,可以查看笔者的算法求解思路培养系列。算法求解思路培养-2. 八皇后问题(说说递归) 算法求解思路培养-5.从递归到动态规划 算法求解思路培养-4.棋盘覆盖问题(递归终结篇) 算法求解思路培养-3.链表反转(链表和递归结合) 算法求解思路培养-6.动态规划之凸多边形剖分 算法求解思路培养-9.动态规划之最大连续子串和 算法求解思路培养-7.最长公共子序列问题求解(从递归到非递归)

标签: #计算二叉树高度