二叉树 总述(性质,定义, BFS,DFS遍历)

1.树

树是n个结点的有限集。
当n等于0时,为空树。
当n等于1时,为根结点。
当n大于1时,其余节点可以分为m个互不相交的有限集T1、T2、...、Tm。每个集合本身又是一棵树,并且称为一根结点的子树。

显然,树是一种递归的数据结构。

树中某结点的孩子个数称为该结点的度。树的度=max{结点的度}。

树中结点数等于所有点的度数和加1.

结点编号通常从1起,从上到下、从左到右递增。
通常认为树高从1算起,根结点第一层,最后一
个叶结点层数最大。
节点间关系有父、祖先、兄弟、孩子、子孙。
两个结点A、B之间的路径就是从A到B所经过的结点的序列。路径长度就是所经过的边的个数。

2.二叉树

二叉树是度不大于2的 且 单个孩子结点分左右的 有序树。在一棵有序树中,只有一个结点做孩子时不分左右。

二叉树的存储——数组、链表。

满二叉树:除叶节点外每个结点度都为2。

完全二叉树:对一棵满二叉树,从后往前连续删除若干个结点,就成了完全二叉树。

完全二叉树两个特点:(1)叶子节点只出现在最高两层上;(2)度为1的结点最多只能有1个,且它只有左孩子。

3.树中数学规律

4.最优二叉树

树中结点的值代表该结点权重。从根到任意结点的路径长度(即经过的边数)与该结点权重之积为该结点的带权路径长度

树的带权路径长度,WPL,Weighted Path Length of Tree。表示树中所有叶结点的带权路径长度之

最优二叉树也称为哈夫曼树。表示带权路径长度最小的二叉树。

对于一个待处理的字符序列,如果对不同字符采用同样的编码长度,这种编码方式叫固定长度编码。如果采用不等长度的二进制位表示,叫可变长度编码。

哈夫曼编码可以对高频字符赋以短编码,达到压缩数据的目的。

给定n个权值分别为w1,w2,、、、,wn的结点,最优二叉树的构造算法如下:

1. 将这n个结点看作n棵二叉树组成的森林F;

2. 构造一个新节点,从森林F中选取两棵根结点权值最小的树作为新结点的左右子树,并且将新结点的权值置为两个选中树根的权值之和。

3. 从F中删除选中的两棵树,并将新构造的树加入F。

4. 重复步骤2和3,直至F中剩下最后一棵树为止。

5.平衡二叉树

节点的 平衡因子——它的左子树的高度减去它的右子树的高度。
平衡树——树中[任意]一个节点的平衡因子的 绝对值不大于1。
def is_Balanced_Binary_Tree(root):
    """判断它是否为平衡二叉树. 平衡的要求是:树中的[每个]节点, 其左右子树的高度差都不能超过1)"""

    def calc_height(root):
        if root is None:
            return 0
        l_height, r_height = calc_height(root.left), calc_height(root.right)
        # 因为要求每个节点的左右子树高度, 所以要这么写
        if l_height == -1 or r_height == -1:
            return -1
        if abs(l_height - r_height) > 1:
            return -1
        return max(l_height, r_height) + 1

    return calc_height(root) != -1

6.二叉树的遍历

先序:根左右。
中序:左根右。
后序:左右根。
根据先序(或后序)与中序遍历可以唯一地确定一棵二叉树。而只靠先序与后序是不行的。
from typing import List


class TreeNode:
    """
    Definition of TreeNode:
    """

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

    def __repr__(self):
        return f"val={self.val}, id={id(self)}"

    @staticmethod
    def BFS(root: 'TreeNode', res: List[int]):
        """
        对二叉树作广度优先搜索(遍历)
        """
        from queue import Queue

        q: Queue[TreeNode] = Queue()
        q.put(root)
        while not q.empty():
            node = q.get()
            if node is not None:
                res.append(node.val)
                q.put(node.left)
                q.put(node.right)
        return

    @staticmethod
    def post_order_DFS(root: 'TreeNode'):
        """ 后序遍历二叉树 """
        result = []
        if root:
            if root.left:
                result += TreeNode.post_order_DFS(root.left)
            if root.right:
                result += TreeNode.post_order_DFS(root.right)
            result.append(root.val)
        return result

    @staticmethod
    def get_shallowest_and_deepest_node(root: 'TreeNode') -> List[int]:
        """返回二叉树中, 最浅和最深的两个叶子节点"""
        height_2_node_dict = {}

        def traversal(root, height):
            if root:
                if root.left:
                    traversal(root.left, height + 1)
                if root.right:
                    traversal(root.right, height + 1)
                # 判断是叶子节点
                if not (root.left or root.right):
                    height_2_node_dict[height] = root

        traversal(root, 0)
        # 按深度升序排序
        sorted_tuple = sorted(height_2_node_dict.items(), key=lambda x: x[0])
        return [sorted_tuple[0][1].val, sorted_tuple[-1][1].val]


def construct_tree():
    """
           0
         /   \
        1     2
      /        \
     3          4
               / \
              5   6
    """
    root = TreeNode(0)
    node_1 = TreeNode(1)
    node_2 = TreeNode(2)
    node_3 = TreeNode(3)
    node_4 = TreeNode(4)
    node_5 = TreeNode(5)
    node_6 = TreeNode(6)

    root.left = node_1
    root.right = node_2
    node_1.left = node_3
    node_2.right = node_4
    node_4.left = node_5
    node_4.right = node_6
    return root


if __name__ == '__main__':
    root = construct_tree()

    search_res_arr = TreeNode.post_order_DFS(root)
    print('post_order_DFS', search_res_arr)

    search_res_arr.clear()
    TreeNode.BFS(root, search_res_arr)
    print('BFS', search_res_arr)

    res = TreeNode.get_shallowest_and_deepest_node(root)
    print('get_shallowest_and_deepest_node', res)
"""
post_order_DFS [3, 1, 5, 6, 4, 2, 0]
BFS [0, 1, 2, 3, 4, 5, 6]
get_shallowest_and_deepest_node [3, 6]
"""

7.字典树

又叫 Trie树,可以看作是一个确定的有限状态自动机。
树种一个节点的所有子孙都有相同的前缀,故常用于搜索提示。

8.扩展二叉树

若一个节点左孩子为空,补一个空节点;若右孩子为空,补一个空节点。参照图8-1可有直观的理解。
图8-1 扩展二叉树
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值