二叉树练习

本文主要介绍了二叉树的几种遍历方法,包括中序遍历、前序遍历和后序遍历,并详细讲解了从上往下打印二叉树、按之字形打印二叉树、判断二叉树是否对称以及找到二叉树的下一个节点等经典问题的解决方案。通过这些实例,读者可以深入理解二叉树的遍历和操作技巧。

中序遍历

class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


def in_order_traversal(root):  # 中序
    res = []
    stack = []#借用栈
    if root is None:
        return res
    cur = root
    while len(stack) != 0 or cur is not None:
        while cur is not None:
            stack.append(cur)
            cur = cur.left
        node = stack.pop()
        res.append(node.val)
        cur = node.right
    return res
    
# 中序打印二叉树(递归)
def inOrderTraverse(node):
    if node is None:
        return None
    inOrderTraverse(node.left)
    print(node.val)
    inOrderTraverse(node.right)

前序遍历

class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


def pre_order_traversal(root):  # 前序
    result = []
    stack = []
    stack.append(root)
    while len(stack) != 0:
        node = stack.pop()
        if node is None:
            continue
        result.append(node.val)
        stack.append(node.right)
        stack.append(node.left)
    return result
    
# 先序打印二叉树(递归)
def preOrderTraverse(node):
    if node is None:
        return None
    print(node.val)
    preOrderTraverse(node.left)
    preOrderTraverse(node.right)

后序遍历

class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


def post_order_traversal(root):  # 后序
    """
    前序遍历为 root -> left -> right,后序遍历为 left -> right -> root,
    可以修改前序遍历成为 root -> right -> left,那么这个顺序就和后序遍历正好相反
    """
    result = []
    stack = []
    stack.append(root)
    while len(stack) != 0:
        node = stack.pop()
        if node is None:
            continue
        result.append(node.val)
        stack.append(node.left)
        stack.append(node.right)
    return result[::-1]
    
# 后序打印二叉树(递归)
def postOrderTraverse(node):
    if node is None:
        return None
    postOrderTraverse(node.left)
    postOrderTraverse(node.right)
    print(node.val)

从上往下打印二叉树(简单)

题目描述
从上往下打印出二叉树的每个节点,同层节点从左至右打印。

思路:

  1. 根节点不存在 返回空

  2. 开辟queue空间 初始化为[root] 队列意味着一层一层的遍历

  3. 开辟放结果的数组 res

  4. 当队列不为空时while:
    计算这一层有几个节点n
    遍历这一层for
    如果这一层不存在节点 退出for循环
    否则 取出一个节点 添加到放结果的数组res
    将下一层的节点都添加到队列 即如果该节点左右节点存在添加到队列

  5. 返回res

运行时间:26ms

占用内存:5860k

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
def construct_tree():
    root = TreeNode(8)
    root.left = TreeNode(6)
    root.right = TreeNode(10)
    root.left.left = TreeNode(5)
    root.left.right = TreeNode(7)
    root.right.left = TreeNode(9)
    root.right.right = TreeNode(11)
    root.left.right.left = TreeNode(12)
    root.left.right.right = TreeNode(13)
    return root
class Solution:
    # 返回从上到下每个节点值列表,例:[1,2,3]
    def PrintFromTopToBottom(self, root):
        # write code here
        if not root:return []
        queue=[root]
        res=[]
        while queue:
            n=len(queue)
            for _ in range(n):
                if not queue:break
                temp=queue.pop(0)
                res.append(temp.val)
                if temp.left:
                    queue.append(temp.left)
                if temp.right:
                    queue.append(temp.right)
        return res
s=Solution()
tree= construct_tree()
res=s.PrintFromTopToBottom(tree)
print(res)  
#return [8, 6, 10, 5, 7, 9, 11, 12, 13]

按之字形打印二叉树

题目描述
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

思路:
同上一道题,不同之处在于添加了标记偶数行的标记 j,j 初始化为-1 ,每开始新一行的循环 j 就加一,最后每一行遍历完后 判断这是奇数行还是偶数行,偶数行的话,反转这一行的数值。第二个不同之处在于,开辟了放每一行数值的暂存数组temp,因为偶数行的话,必须反转后才能添加到结果数组res里面。

运行时间:27ms

占用内存:5728k

class Solution:
    def Print(self, pRoot):
        # write code here
        if not pRoot: return []
        res = []#放结果的数组
        queue = [pRoot]
        j = -1#标记偶数行
        while queue:
            j += 1
            n = len(queue)
            temp = []#放这一行的节点数值
            for _ in range(n):
                node = queue.pop(0)
                temp.append(node.val)
                if node.left: queue.append(node.left)
                if node.right: queue.append(node.right)
            if j % 2:#当j表示这一行为偶数行 反转这一行
                temp.reverse()
            res.append(temp)#把这一行确定的节点数值放进结果数组里
        return res
        
s=Solution()
tree= construct_tree()
res=s.Print(tree)
print(res) 

把二叉树打印成多行

题目描述
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

运行时间:25ms

占用内存:5632k

class Solution:
    # 返回二维列表[[1,2],[4,5]]
    def Print(self, pRoot):
        # write code here
        if not pRoot: return []
        queue = [pRoot]
        res = []
        while queue:
            n = len(queue)
            temp = []
            for _ in range(n):
                node = queue.pop(0)
                temp.append(node.val)
                if node.left: queue.append(node.left)
                if node.right: queue.append(node.right)
            res.append(temp)
         #   print(res)
        return res
#return [[8], [6, 10], [5, 7, 9, 11]]

对称的二叉树

题目描述
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

思路:

如果根节点不存在 返回真
把每一层放进队列 queue = [pRoot]

当队列里有节点时 进行以下操作
看这一层有多少个节点 n

如果非根节点且这一层节点数是奇数
则返回false
否则
重点,判断这一行最左和最右是否一样

【判断两个节点一样么
两节点都不存在则两节点一样
两节点都存在且数值一样则两节点一样
否则返回不一样】

遍历这一行
弹出队列中的一个节点
如果该节点不存在 过
否则将下一层的节点都添加到队列 即如果该节点左右节点存在添加到队列

运行时间:25ms

占用内存:5732k

class Solution:
    def isEqual(self,p1, p2):
        if not p1 and not p2:
            return True
        elif p1 and p2 and p1.val == p2.val:
            return True
        else:
            return False
    def isSymmetrical(self, pRoot):
        # write code here
        if not pRoot: return True
        queue = [pRoot]
        while queue:
#            print(queue)
            n = len(queue)
            if queue[0] != pRoot and n % 2 != 0: 
                return False
            for i in range(n//2):
                if not self.isEqual(queue[i], queue[-1-i]):
                    return False
            for _ in range(n):
                node = queue.pop(0)
                if not node: continue
                queue.append(node.left)
                queue.append(node.right)
        return True

二叉树的下一个结点

题目描述
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

思路:
分情况讨论

  1. 第一:节点p的右节点存在:p的下一个节点 则为p的右子树的最左节点 [1.1】
  2. 第二:节点p的右节点不存在的话 分两种情况:
    第一 :节点p的右节点不存在的话 且 p为其父节点的左子节点:p的下一个节点 则为p的父节点 【2.1】
    第二:节点p的右节点不存在的话 且 p为其父节点的右子节点: p的下一个节点 为 沿着父节点往上遍历 找到一个点 满足该点是其父节点的左子节点。(若该点不存在,则p的下一个节点不存在)【2.2】

如果该节点为空 返回None
p的右节点存在的话
找到右子树的最左节点 返回

节点p的右节点不存在的话 且 p为其父节点的右子节点 时:
关键,往上遍历 当pNode是自己父节点的左子节点时,跳出while
返回pNode的父节点

运行时间:26ms

占用内存:5864k

def construct_tree():
    root = TreeNode(1)
    root.left = TreeNode(2)
    root.right = TreeNode(3)
    root.left.left = TreeNode(4)
    root.left.right = TreeNode(5)
    root.right.left = TreeNode(6)
    root.right.right = TreeNode(7)
    root.left.right.left = TreeNode(8)
    root.left.right.right = TreeNode(9)
     '''
    root = TreeNode('a')
    root.left = TreeNode('b')
    root.right = TreeNode('c')
    root.left.left = TreeNode('d')
    root.left.right = TreeNode('e')
    root.right.left = TreeNode('f')
    root.right.right = TreeNode('g)
    root.left.right.left = TreeNode('h')
    root.left.right.right = TreeNode('i')
    '''
    root.parent = None
    root.left.parent= root
    root.right.parent= root
    root.left.left.parent= root.left
    root.left.right.parent =root.left
    root.right.left.parent= root.right
    root.right.right.parent= root.right
    root.left.right.left.parent = root.left.right
    root.left.right.right.parent =root.left.right
    return root

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
        self.parent = None

class Solution:
    def GetNext(self, pNode):
        # write code here
        if not pNode: return None
        if pNode.right:  # 
            p = pNode.right
            while p.left:
                p = p.left
            return p
         # 
        while pNode.parent and pNode.parent.right == pNode:
            pNode = pNode.parent
        return pNode.parent
        
        
root=construct_tree()
s=Solution()
#res=s.GetNext(root.left.left)
res=s.GetNext(root.right.left)
print(res.val)

二叉树的深度

题目描述
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

思路:
队列queue 用来放每一层节点

运行时间:28ms

占用内存:5728k

class Solution:
    def TreeDepth(self, pRoot):
        # write code here
        if not pRoot: return 0#根节点不存在 返回0
        queue = [pRoot]# 把每一层放进队列
        deep = 0#深度初始化为0
        while queue:#当这一层有节点时
            n = len(queue)#看着一层有几个节点n
            for _ in range(n):#遍历这一层的n个节点
                node = queue.pop(0)#弹出一个,并把弹出的节点的下一层的节点(即左右子节点)添加到队列
                if node.left: queue.append(node.left)
                if node.right: queue.append(node.right)
            deep += 1#每一层遍历完 深度加一
        return deep

二叉搜索树的第k个结点

题目描述
给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。

运行时间:26ms

占用内存:5864k

树的子结构

题目描述
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

重建二叉树(中等)

题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

思路

用前序遍历找到根结点,用根结点在中序遍历中切开左右子树,递归重建二叉树

  1. 前序数组为空时,返回空
  2. 用前序遍历找到根结点
  3. 初始化一个为根值的树节点
  4. 遍历后序数组,找到根数值的索引位置i
  5. 切分左右子树,递归调用本函数
  6. 返回根节点

运行时间:42ms

占用内存:5724k

# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回构造的TreeNode根节点
    def reConstructBinaryTree(self, pre, tin):
        # write code here
        if not pre:
            return
        root_val=pre[0]
        root=TreeNode(root_val)
        for i in range(len(tin)):
            if tin[i]==root_val:break
        root.left=self.reConstructBinaryTree(pre[1:1+i],tin[:i])
        root.right=self.reConstructBinaryTree(pre[1+i:],tin[i+1:])
        return root

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

1)非递归定义 树(tree)是由n(n≥0)个结点组成的有限集合。n=0的树称为空树;n>0的树T: ① 有且仅有一个结点n0,它没有前驱结点,只有后继结点。n0称作树的根(root)结点。 ② 除结点外n0 , 其余的每一个结点都有且仅有一个直接前驱结点;有零个或多个直接后继结点。 (2)递归定义 一颗大树分成几个大的分枝,每个大分枝再分成几个小分枝,小分枝再分成更小的分枝,… ,每个分枝也都是一颗树,由此我们可以给出树的递归定义。 树(tree)是由n(n≥0)个结点组成的有限集合。n=0的树称为空树;n>0的树T: ① 有且仅有一个结点n0,它没有前驱结点,只有后继结点。n0称作树的根(root)结点。 ② 除根结点之外的其他结点分为m(m≥0)个互不相交的集合T0,T1,…,Tm-1,其中每个集合Ti(0≤i<m)本身又是一棵树,称为根的子树(subtree)。 2、掌握树的各种术语: (1) 父母、孩子与兄弟结点 (2) 度 (3) 结点层次、树的高度 (4) 边、路径 (5) 无序树、有序树 (6) 森林 3二叉树的定义 二叉树(binary tree)是由n(n≥0)个结点组成的有限集合,此集合或者为空,或者由一个根结点加上两棵分别称为左、右子树的,互不相交的二叉树组成。 二叉树可以为空集,因此根可以有空的左子树或者右子树,亦或者左、右子树皆为空。 4、掌握二叉树的五个性质 5二叉树的二叉链表存储。
### 关于线索二叉树练习题 #### 中序线索二叉树的特点 中序线索二叉树通过在每个节点增加两个指针域 `ltag` 和 `rtag` 来实现,分别表示该节点是否有前驱和后继。如果某个节点有左孩子,则它的 `lchild` 指向左孩子;如果没有左孩子,则指向其前驱节点。同样地,如果有右孩子,则 `rchild` 指向右孩子;如果没有右孩子,则指向其后继节点[^2]。 #### 寻找特定节点的前驱与后继 在一个中序线索二叉树中,对于任意节点 X 的前驱可以通过以下方式找到: - 如果节点 X 存在左子树,则前驱为左子树中的最右侧节点(即沿着左子树一直往右走直到无法再继续)。 - 若不存在左子树,则前驱为其父节点链上的最近祖先节点,且该祖先节点的右子树包含当前节点[^5]。 #### 构造一棵二叉树并对其进行线索化处理 假设已知某棵二叉树的先序遍历序列 `[A, B, D, E, C, F]` 及其中序遍历序列 `[D, B, E, A, C, F]`,则可以根据这些信息重建原始二叉树,并进一步将其转化为中序线索二叉树[^4]。 以下是基于 Python 实现的一个简单例子来展示如何构建这样的二叉树以及完成中序线索化的操作: ```python class TreeNode: def __init__(self, val=0, lchild=None, rchild=None, ltag=False, rtag=False): self.val = val self.lchild = lchild self.rchild = rchild self.ltag = ltag self.rtag = rtag def build_tree(preorder, inorder): if not preorder or not inorder: return None root_val = preorder[0] root_index_in_inorder = inorder.index(root_val) left_inorder = inorder[:root_index_in_inorder] right_inorder = inorder[root_index_in_inorder + 1:] left_preorder = preorder[1:len(left_inorder)+1] right_preorder = preorder[len(left_inorder)+1:] node = TreeNode(val=root_val) node.lchild = build_tree(left_preorder, left_inorder) node.rchild = build_tree(right_preorder, right_inorder) return node def threaded_binary_tree(root): pre_node = None def thread(node): nonlocal pre_node if not node: return thread(node.lchild) if not node.lchild: node.lchild = pre_node node.ltag = True if pre_node and not pre_node.rchild: pre_node.rchild = node pre_node.rtag = True pre_node = node thread(node.rchild) thread(root) # Example Usage preorder = ['A', 'B', 'D', 'E', 'C', 'F'] inorder = ['D', 'B', 'E', 'A', 'C', 'F'] tree_root = build_tree(preorder, inorder) threaded_binary_tree(tree_root) ``` 上述代码展示了如何利用给定的先序和中序遍历来创建一颗完整的二叉树,并对该二叉树执行中序线索化过程。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值