通用算法 - [树结构] -二叉树的一些基本操作(一)

本文深入探讨了二叉树的递归与非递归遍历、求叶子节点数、求深度等关键操作,提供了详细的代码实现,是理解与掌握二叉树的重要资源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、前言

数组、链表、二叉树、动态规划、栈与队列是面试中常考的知识点,而在这几个知识点中,二叉树属于难度比较大的部分,因此在这里总结一下二叉树常考的操作,包括:
(1)二叉树的递归遍历;
(2)二叉树的非递归遍历;
(3)求二叉树叶子节点的个数;
(4)求二叉树的深度;
(5)在二叉树中查找某颗子树;
(6)求二叉树中和为某个值的路径;
(7)求二叉树中的最大路径和;
(8)二叉树的镜像;
(9)判断某个序列是否是二叉搜索树的后序遍历序列;
(10)二叉搜索树和双向链表的相互转换;
(11)树中两个结点的最近祖先;
(12)二叉树搜索树的插入与删除;
(13)堆的插入与删除;
(14)判断一棵树是不是平衡二叉树;
(15)平衡二叉树的调整;

2、二叉树的基本操作

(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。

  • 注意,这里有两个比较重要的数据结构:
  • 当前节点:栈顶元素;
  • last_pop:上一次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

>>下一篇:通用算法 - [树结构] -二叉树的一些基本操作(二)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Albert_YuHan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值