二叉树问题(二):相关习题

1、二叉树的分类
满二叉树:除叶结点外每一个结点都有左右子结点并且叶子结点都处在最底层的二叉树。

完全二叉树:除最后一层外,其他各层的结点数都达到最大,最后一层的叶子结点都是从左往右依次排布。

二叉排序树(BST):或者是一棵空树,或者具有如下性质:(1)若左子树不为空,则左子树上所有结点的值均小于它的根结点的值;(2)若右子树不为空,则右子树上所有结点的值均大于它的根结点的值;(3)左右子树也分别为二叉排序树;(4)没有值相等的结点。

平衡二叉树(AVL):一种二叉排序树,其中每个结点的左子树和右子树的高度差至多等于1。要么它是一棵空树,要么它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1。

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

class TreeNode():
    def __init__(self,element):
        self.element=element
        self.left=None
        self.right=None
class Solution:
    # 返回构造的TreeNode根节点
    def reConstructBinaryTree(self,pre,tin):
        # write code here
        if len(pre)==0:
            return None
        elif len(pre)==1:
            return TreeNode(pre[0])
        else:
            root=TreeNode(pre[0])
            root.left=self.reConstructBinaryTree(pre=pre[1:tin.index(pre[0])+1],tin=tin[0:tin.index(pre[0])+1])
            root.right=self.reConstructBinaryTree(pre=pre[tin.index(pre[0])+1:],tin=tin[tin.index(pre[0])+1:])
        return root
pre=[0,1,3,7,8,4,9,2,5,6]
tin=[7,3,8,1,9,4,0,2,5,6]
Tree=Solution().reConstructBinaryTree(pre=pre,tin=tin)
def priorsearch(node):
    if node is None:
        return
    else:
        if node.element is not None:
            print(node.element,end=" ")
        priorsearch(node.left)
        priorsearch(node.right)
print(priorsearch(Tree))

结果:我们采用先序遍历的方式来看看结果
在这里插入图片描述
解析:
首先我们要做这道题要清楚了解二叉树的前、中、后序遍历的结果
在这里插入图片描述
先序遍历:从根结点开始,按中左右的顺序从根结点开始不断搜索,直到没有子节点为止开始向上回溯,比如到达7,此时按中左右的顺序打印7,发现7没有子节点,回溯到3,打印右结点。什么意思呢,即进入一个结点先打印中结点,查看是否含有左结点,有就进入,没有的话查看是否有右结点,有就立刻进入,如果左右结点都没有退回到根节点,按上述顺序继续查找。如果回溯到根节点发现已经全部打印完继续向上回溯,直到所有结点都被打印。
中序遍历:从根节点开始,按找左中右的顺序开始搜索,到达一个结点先看是否有左结点,如果有进入,如果没有左结点,则打印中结点,然后查看是否有右结点,如果有则进入,然后重复上述操作,如果左右结点都没有,进行回溯操作,直到遍历完整棵树。
后序遍历:跟上述方法类似,按照左右中的顺序执行。

我们发现前序遍历的第一个元素一定是根节点,而这个元素在中序遍历的位置前的元素全是原二叉树的左枝,中序遍历后面的元素全是二叉树的右枝,且这个元素的位置在前序遍历的数列中[1:中序遍历索引位置+1的位置]为二叉树的左枝,利用这一规律可以不断切分二叉树找出其根元素,和左树的元素,采用递归的方法直到元素只有一个。所以最后我们呢采用递归的方法去实现二叉树的全部遍历。
函数的递归过程如下所示:
在这里插入图片描述
由上图可以清晰的看出这个递归的逻辑,在递归到7和8的时候,root.left和root.right才得出结果(root为3),后面的return root才使1.left=3得出结果。接着继续运行1.right=recontruct这个递归程序。
习题2:
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
代码:

# -*- coding:utf-8 -*-
class TreeNode:
     def __init__(self, x):
         self.val = x
         self.left = None
         self.right = None
class Solution:
    def HasSubtree(self, pRoot1, pRoot2):
        # write code here
        if pRoot1 is None or pRoot2 is None:
            return False
        array = []
        array.append(pRoot1)
        while array:
            #print("开始循环")
            u = array.pop(0)
            if u.val == pRoot2.val:
                array1 = []
                array2 = []
                triger = False
                array1.append(u)
                array2.append(pRoot2)
                while array1 and array2:  # 当两个列表都不为空时
                    node1 = array1.pop(0)
                    node2 = array2.pop(0)
                    print(node1.val,node2.val)
                    if node1.val == node2.val:
                        triger = True
                        if node1.left is not None:
                            array1.append(node1.left)
                        if node1.right is not None:
                            array1.append(node1.right)
                        if node2.left is not None:
                            array2.append(node2.left)
                        if node2.right is not None:
                            array2.append(node2.right)
                    else:
                        triger=False
                        break
                #print("循环结束")
                if triger == True:
                    return True
            #这里不能用else,因为我们将u作为判断条件来使用,如果等于树2的值那么开始判断树2
            #如果不等于我们继续程序,往队列中添加元素即可,但是用了else:此时第一次判断完后
            #发现两者的u和pRoot2的值不等,程序就结束了,没有继续往下搜索
            if u.left is not None:
                array.append(u.left)
            if u.right is not None:
                array.append(u.right)
        return False
node8_1=TreeNode(8)
node8_2=TreeNode(8)
node7_1=TreeNode(7)
node9=TreeNode(9)
node2=TreeNode(2)
node3=TreeNode(3)
node4=TreeNode(4)
node7_2=TreeNode(7)
# 树1
node8_1.left=node8_2
node8_1.right=node7_1
node8_2.left=node9
node8_2.right=node3
node3.left=node4
node3.right=node7_2
#                      8
#                   8     7
#                 9   3
#                   4   7
"""
#树2
node8_3=TreeNode(8)
node9_2=TreeNode(9)
node2=TreeNode(2)
node8_3.left=node9_2
node8_3.right=node2
  8
9    2
##测试1
print(Solution().HasSubtree(node8_1,node8_3))
"""
##测试2
#树2
node8_3=TreeNode(8)
node9_2=TreeNode(9)
node3_2=TreeNode(3)
node8_3.left=node9_2
node8_3.right=node3_2
"""
    8
 9     3
"""
print(Solution().HasSubtree(node8_1,node8_3))

解析:这道题我们采用队列的方式进行树的遍历,其中需要注意的有两点
① 进行树的遍历时,我们添加左右子树时一定要注意左右子树是否为None,如果是的话则不添加,否则添加.其中的array为树1的队列。遍历的方式采用层级遍历即一层一层的遍历的方式来进行头节点的寻找。
②当寻找到头结点后重新将节点中的值和要寻找的子树结构放入两个新的队列中进行新的遍历寻找,如果所有遍历的值都一样,则返回True<1>其中一个队列跑完了另外一个队列没有跑完<2>遍历中其中一个队列的值和另一个队列的值不一样,寻找弹出,标记为False。
③每次在循环1中看是否找到了子结构,如果找到了为True.当Proot1完全遍历完毕后还没有找到返回False.
④这里用if-else来比较搜索的值,用两个循环进行遍历搜索
习题3:
题目描述
操作给定的二叉树,将其变换为源二叉树的镜像。
输入描述:
二叉树的镜像定义:源二叉树
8
/
6 10
/ \ /
5 7 9 11
镜像二叉树
8
/
10 6
/ \ /
11 9 7 5
代码实现:

# -*- coding:utf-8 -*-
class TreeNode:
     def __init__(self, x):
         self.val = x
         self.left = None
         self.right = None
class Solution:
    # 返回镜像树的根节点
    def Mirror(self, root):
    # write code here
        if root is None:
            return None
        queue=[]
        queue.append(root)
        array=[] #记录二叉树的遍历节点
        while queue:
            u=queue.pop(0)
            u.right,u.left=u.left,u.right
            if u.right is not None:
                queue.append(u.right)
            if u.left is not None:
                queue.append(u.left)
        return root

#测试数据
node8=TreeNode(8)
node6=TreeNode(6)
node10=TreeNode(10)
node5=TreeNode(5)
node7=TreeNode(7)
node9=TreeNode(9)
node11=TreeNode(11)

node8.left=node6
node8.right=node10
node6.left=node5
node6.right=node7
node10.left=node9
node10.right=node11

root=Solution().Mirror(node8)
array=[]
array.append(root)
while array:
    u=array.pop(0)
    print(u.val)
    if u.left is not None:
        array.append(u.left)
    if u.right is not None:
        array.append(u.right)

解析:通过队列的形式按层输入其这一层所有的节点,将所有按顺序弹出,每次将节点的左右子树对换,直到所有节点遍历完成为止
习题4:判断二叉树是否对称
题目描述
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

# -*- coding:utf-8 -*-
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
class Solution:
    def isSymmetrical(self,pRoot):
        # write code here
        if pRoot == None:
            return True
        array1=self.mid_left_right(pRoot)
        array2=self.mid_right_left(pRoot)
        if self.compare_twoarray(array1,array2):
            return True
        else:
            return False
    def __init__(self):
        self.array1=[]
        self.array2=[]

    def mid_left_right(self,pRoot):
        if pRoot is None:
            self.array1.append(pRoot)
            return
        else:
            self.array1.append(pRoot.val)
            self.mid_left_right(pRoot.left)
            self.mid_left_right(pRoot.right)
        return self.array1
    def mid_right_left(self,pRoot):
        if pRoot is None:
            self.array2.append(pRoot)
            return
        else:
            self.array2.append(pRoot.val)
            self.mid_right_left(pRoot.right)
            self.mid_right_left(pRoot.left)
        return self.array2
    def compare_twoarray(self,array1,array2):
        if len(array1)!=len(array2):
            return False
        else:
            triger=False
            while array1 and array2:
                if array1.pop()==array2.pop():
                    triger=True
                else:
                    triger=False
                    break
            if triger== True:
                return  True
            else:
                return  False
##测试数据
node8=TreeNode(8)
node6_1=TreeNode(6)
node6_2=TreeNode(6)
node5_1=TreeNode(5)
node7_1=TreeNode(7)
node7_2=TreeNode(7)
node5_2=TreeNode(5)

##生成树
node8.left=node6_1
node8.right=node6_2
node6_1.left=node5_1
node6_1.right=node7_1
node6_2.left=node7_2
node6_2.right=node5_2

print(Solution().isSymmetrical(node8))

解析:利用两中左右和中右左两种方式来分别遍历树并存储,如果树是对称的则这两种遍历方式所获得的列表一定一模一样,然后将两个队列中的值进行一一比较。如果全部比较成功,则代表这棵树是对称的。
习题5:二叉搜索树的后序遍历序列
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。二叉搜索树和二叉树不同,二叉搜索树的左结点一定小于根节点,右结点大于根节点。

# -*- coding:utf-8 -*-
class Solution:
    def VerifySquenceOfBST(self, sequence):
        # write code here
        if sequence==[]:
            return False
        if len(sequence)==1:
            return True
        i=0
        length=len(sequence)
        root=sequence[length-1]
        #搜索左子树,找出左子树的结束值
        for i in range(length):
            if sequence[i]>root:
                break
        #搜索右子树,看右子树中的值是不是都大于root,如果不是证明不是后序遍历,递归终止条件
        for j in range(i,length):
            if sequence[j]<root:
                return False
        return True
        #递归搜索左子树,除非子序列中出现左边子树的值大于根节点
        if i>0:#不能让截取的字符为一个空值
            left=self.VerifySquenceOfBST(sequence[:i])
        #搜索右子树
        if i<length-1:
            right=self.VerifySquenceOfBST(sequence[i:-1])
        return left and right
print(Solution().VerifySquenceOfBST([5,7,6,9,11,10,8]))
print(Solution().VerifySquenceOfBST([5,7,6,9,11,10,3]))
print(Solution().VerifySquenceOfBST([7,4,6,5]))

习题6:
题目描述
输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。

#-*- coding:utf-8 -*-
class TreeNode:
     def __init__(self, x):
         self.val = x
         self.left = None
         self.right = None
class Solution:
    def __init__(self):
        self.result=[]
        self.path=[]
    def FindPath(self,root,expectNumber):
        # write code here
        if root==None:
            return []
        self.findrightpath(root,0,expectNumber) #遍历所有路径
        return self.result
    def findrightpath(self,root,currentNumber,expectNumber):
        self.path.append(root.val)
        currentNumber+=root.val
        #判断是否为根节点
        if root.left is None and root.right is None:
            islef=True
        else:
            islef=False
        if islef and currentNumber==expectNumber:
            one_path=[]
            one_path=[i for i in self.path]
            self.result.append(one_path)
        if currentNumber<expectNumber:
            if root.left:
                self.findrightpath(root.left,currentNumber,expectNumber)
            if root.right:
                self.findrightpath(root.right,currentNumber,expectNumber)
        #当前路径和比期待路径和大时,弹出并进行下次递归
        self.path.pop()
###测试数据
node_10=TreeNode(10)
node_5=TreeNode(5)
node_12=TreeNode(12)
node_4=TreeNode(4)
node_7=TreeNode(7)
node_10.left=node_5
node_10.right=node_12
node_5.left=node_4
node_5.right=node_7
	 10
  5     12
4    7 

解析:采用前序遍历的方式进行遍历,并用一个列表进行记录,但是这里有两点需要注意,一个是记录遍历列表的数组,我们在记录路径时要找新的列表将元素全部取出来,因为程序后面有个弹出程序,在进行递归时有多少层递归就会有多少弹出,所以不能使用递归记录的列表来进行路径记录,其次递归程序不一定要有递归终止条件,当所有程序运行完程序也结束了,这点要注意。

例2:按照上题同样的要求,写出树中所有的路径。
解析:写出树中所有的路径,其实有多少路径也就是看有多少叶子节点,叶子节点的个数基本就等于路径数。

    def findallpath(self,root):
        self.findallpath1(root)
        return self.result
    def findallpath1(self,root):
        self.path.append(root.val)
        if root.left:
            self.findallpath1(root.left)
        if root.right:
            self.findallpath1(root.right)
        if root.left is None and root.right is None:
            one_path=[i for i in self.path]
            self.result.append(one_path)
            self.path.pop()

习题6:寻找二叉搜索树中第k大的节点(剑指offer54)
给定一个二叉搜索树,(二叉搜索树的特征是,左子树的值小于节点的值,右子树的值大于节点的值。)
如 5
3 7
2 4 6 8

class node:
    def __init__(self,value):
        self.value=value
        self.left=None
        self.right=None
node_5=node(5)
node_3=node(3)
node_2=node(2)
node_4=node(4)
node_7=node(7)
node_6=node(6)
node_8=node(8)
node_5.left=node_3
node_5.right=node_7
node_3.left=node_2
node_3.right=node_4
node_7.left=node_6
node_7.right=node_8
head=node_5
class solution:
    def __init__(self):
        self.count=0
    def mid_search(self,head):
        if head==None:
            return
        else:
            self.mid_search(head.left)
            print(head.value)
            self.mid_search(head.right)
    def Tree_search(self,head,k):
        #self.count+=1
        #print(self.count)
        if head==None:
            return
        else:
            #print(1)
            self.Tree_search(head.left,k)
            if head.value is not None:
                self.count+=1
                if self.count==k:
                    print(head.value)
            self.Tree_search(head.right,k)
        
#solution().mid_search(head)
#测试数据
solution().Tree_search(head,3)
solution().Tree_search(head,5)

解析:这道题的基本思路其实就是利用中序遍历的递归思想在二叉搜索树中进行查找,每找到一个值,count数+=1,知道找到顺序值为第k个值的数
习题7:判断一个满二叉树是否为二叉搜索树

'''
给定一棵满二叉树,判定该树是否为二叉搜索树,是的话打印True,不是的话打印False
说明:
a. 二叉搜索树(Binary Search Tree),它或者是一棵空树,或者是具有下列性质的二叉树;
 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 
 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 
 它的左、右子树也分别为二叉搜索树。
b. 满二叉树,除最后一层无任何子节点外,每一层上的所有结点都有两个子结点二叉树
c. 树内节点数不超过 10000,非空节点值为大于0小于65536的整数,空树或空节点输入为None
解析:
          10(0)
     5(1)      15(2)
   3(3)   7(4)  13(5)   18(6)
方法1:
一棵树的根节点为len(list1)//2 长度为7 根节点有三个
长度为6 根节点有三个
先对整颗树的非叶子节点进行遍历,遍历时,遍历到改节点的左树
将左树的所有节点存储下来,并判断其左树的值是否都小于根节点,如果不是返回False
将右树的所有节点存储下来,并判断其右树的值是否都大于根节点,如果不是返回False
遍历完成返回True
方法2:
通过中序遍历,其数组为递增数组
'''
try:
    list1=input().split(',')
    list1=[int(i) if i.isdigit() else i for i in list1]
    #print(list1)
    n=len(list1)
    def is_erchasearch_tree(list1,n):
        if n==0:
            return True
        if n==1:
            return True
        for i in range(n//2):
            left=i*2+1
            right=i*2+2
            #print(left,right)
            if list1[left] is not None:
                arr=[]
                arr1=[]
                arr.append(left)
                while arr:
                    a=arr.pop(0)
                    if a*2+1<n:
                        arr1.append(list1[a*2+1])
                        arr.append(a*2+1)
                    if a*2+2<n:
                        arr.append(a*2+2)
                        arr1.append(list1[a*2+2])
                arr1.insert(0,list1[left])
                #print(arr1)
                max_left=max(arr1)
                if max_left>list1[i]:
                    return False
            if list1[right] is not None:
                #print(list1[right],list1[last_root],list1[i])
                arr=[]
                arr1=[]
                arr.append(right)
                while arr:
                    a=arr.pop(0)
                    if a*2+1<n:
                        arr1.append(list1[a*2+1])
                        arr.append(a*2+1)
                    if a*2+2<n:
                        arr.append(a*2+2)
                        arr1.append(list1[a*2+2])
                arr1.insert(0,list1[right])
                #print(arr1)
                min_right=min(arr1)
                if min_right<list1[i]:
                    return False
        return True
    print(is_erchasearch_tree(list1,n))
except:
    pass
#方法2:
list1=input().split(',')
list1=[int(i) if i.isdigit() else i for i in list1]
class TreeNode:
    def __init__(self,x):
        self.val=x
        self.left=None
        self.right=None

def re_build_tree(list1,i):
    if i>=len(list1) or list1[i]=='None':
        return None
    root=TreeNode(list1[i])
    root.left=re_build_tree(list1,i*2+1)
    root.right=re_build_tree(list1,i*2+2)
    return root
class bianli:
    def __init__(self):
        self.arr=[]
    def prio_search(self,head):
        if head==None:
            return 
        self.prio_search(head.left)
        #print(head.val)
        self.arr.append(head.val)
        self.prio_search(head.right)
        return self.arr
    def is_ercha_searchtree(self,list1):
        i,j=0,1
        while j<len(list1):
            if list1[j]-list1[i]<0:
                return False
            i+=1
            j+=1
        return True
if len(list1)==1:
    print(True)       
else:
    root=re_build_tree(list1,0)
    list2=bianli().prio_search(root)
    #print(list2)
    print(bianli().is_ercha_searchtree(list2))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值