数据结构——二叉树

二叉树(binary tree)

这里都是定义的处理函数,在主程序中,怎么输入一颗二叉树?

书本描述:按序输入一颗二叉树的界定啊的数据(什么叫按序输入)

 

树的遍历目的:访问树的每一个节点,可用方法:前序,中序,后序法

百度:二叉树的深度优先遍历和广度优先遍历

小米面试手写判断一颗树是否为平衡二叉树(当时自己都不知道怎么用程序将二叉树构建出来...)

 

二叉树不能形成回路,如环状链表会造成回路现象,不符合树的定义

树在内存中的存储方式以链表为主,同样可以使用数组存储

二叉树的两个特殊情况:

①满二叉树:高度为h(高度肯定是包含根节点n)的树,其节点(所有点,包括根节点)个数为2^h-1(减1是因为根节点只有一个,而其他层都是2的次幂)

②完全二叉树:除了最后一层之外的其他每一层都被完全填充,并且所有结点都保持向左对齐

通过列表构建二叉树(首先都没二叉树就谈不上后面的操作了)

构建二叉树的方法很多:弄清楚通过列表是怎么构建出的二叉树(书本方法和博客方法不同)

 

 

二叉查找数:根值在左子树值和右子树值之间,左子树值<根值<右子树值

需要构造出2的幂次的数组,按照从上到下,从左到右的顺序,将二叉树的每个节点值依次加入到列表对应的索引处。如果二叉树某处不存在左节点或者右节点,则列表对应位置加入0(博客上都是用的“#”表示)

 

链表方法(首选方法):对于节点的增加和删除很容易,但很难找到父节点

 

1、返回树的最大深度

思路:

比较左子树和右子树的,获取最大值

递归+1向下迭代,直到返回空

传入参数为root,第二次迭代传入参数为root.left和root.right

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

class solution:
    def tree_deep(self,root):#会传入根节点
        if root==None:
            return 0
        else:
            l=1+self.tree_deep(root.left)#这里如果不加self,就无法调用tree_deep方法,去掉self后,tree_deep下后 红色波浪线
            r=1+self.tree_deep(root.right)#不停迭代知道计算出结果
        return max(l,r)

1、left,right都是自己定义的,也有定义成lchild和rchild的

2、程序执行过程

当执行到右子树的节点后,即不要考虑左边了,到第一个递归处,继续递归

 

 

2、二叉查找数/二叉搜索树(BST,binary search tree)

一个二叉搜索树具有如下特征:

•节点的左子树只包含小于当前节点的值。

•节点的右子树只包含大于当前节点的值。

•所有左子树和右子树自身必须也是二叉搜索树。

根据这个特征可以得出:二叉搜索树的中序遍历(左根右)是一个单调递增的序列,最小值一定在左子树的最左边叶子节点,最大值在右子树的最右边叶子节点

如果左子树还有一层,这个题目怎么理解?

class Solution:
    def isValidBST(self, root):
        def inorderTraversal(root):#构造二叉树的中序遍历
            if root == None:
                return []
            res = []
            res += inorderTraversal(root.left)#递归添加节点
            res.append(root.val)
            res += inorderTraversal(root.right)
            return res

        res = inorderTraversal(root)
        if res != sorted(list(set(res))): #判断通过二叉树构造出来的中序遍历是否按照从小到大的顺序排列
            return False
        return True

先递归完再往下执行,有函数就先执行函数

 

这里是先添加左子树直到完毕再添加根节点和右子树

self.InOrder(root.left)

print(root.val, end=' ')

self.InOrder(root.right)

 

变形:将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树

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


class Solution(object):
    def sortedArrayToBST(self, nums):
        #递归方法
        if not nums:
            return None
        mid=len(nums)//2#找到中间节点
        root=Node(nums[mid])#当前节点为根节点
        root.left=self.sortedArrayToBST(nums[:mid])#小于当前根节点的作为左子树
        root.right=self.sortedArrayToBST(nums[mid+1:])#大于当前根节点的作为右子树
        return root

这里传入的是列表,先构建左子树再构建右子树(上面方法是添加的节点)

可以直接传入列表吗?

 

3、判断一棵树是否对称

注意对称的含义:

最左边和最右边相等self.isSame(p1.left, p2.right),传入的参数是p1的左和p2的右

递归的方法:类中包含判断函数,判断函数中包含递归函数(通常的写法套路)

class Solution:
    def isSymmetrical(self, Root):
        # write code here
        def isSame(p1,p2):

            if not p1 and not p2:#根节点左右没有子树
                return True
            if not p1 or not p2:
                return False
            if p1.val != p2.val:
                return False
            return self.isSame(p1.left, p2.right) and self.isSame(p1.right, p2.left)
        if not Root:#不存在根节点
            return True

        return isSame(Root.left,Root.right)

4、判断一颗二叉树是否是平衡二叉树

左右子树深度之差的绝对值不大于1

左右子树都是平衡二叉树(通过递归对每个节点进行判断,若全部均未返回False,则返回True

class Node():
    def __init__(self,x):
        self.val  = x
        self.left = None
        self.right = None
# 递归求当前节点的深度
def depth(node):
    if not node:
        return 0
    ld = depth(node.left)
    rd = depth(node.right)
    return max(ld, rd) + 1#这里的加1,是把父节点包括在内

def isBalance(root):
    if root is None:
        return True
    ld = depth(root.left)
    rd = depth(root.right)
    if abs(ld - rd) > 1:
        return False
    return isBalance(root.left) and isBalance(root.right)

 

5、5种遍历:前中后序,深度优先,广度优先(每一种都要熟练掌握)

前序遍历:

递归调用:先打印根节点值,然后递归打印根节点的左子树的节点和右子树的界定啊,直到遍历到叶子节点(root=None,因为之前会有root.left,所以会有为None的情况)

self.PreOrder(root.left)函数一直递归,直到将左子树全部打印出来后才会向下执行

 

self.InOrder(root.left)当递归到root.left不存在,即root=None后,就会打印root节点的值

 

 

 

广度优先遍历

广度优先遍历函数传入根节点

将当前节点的左节点和右节点分别存入队列中

先弹出再加入,加入顶点,取出顶点,将与顶点相邻且未访问过的顶点加入队列,再重复上述过程(和图的思路过程是一样的),注意这里取的是队列的顶点,二深度优先遍历是取的栈顶元素(即可以看成是队列的尾部元素)

注:图和二叉树都存在深度优先遍历和广度优先遍历

 

按根的右子树和左子树的顺序存入栈中(按这个顺序的话,结果就是唯一的,之前这里不确定)

广度是pop(0),queue

深度是pop(),stack

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值