二叉树

插入一些知识点

大根堆建堆的时间复杂度是Olog(n)

 

平衡二叉树

find-min  O(1)

delete-min  O(logn)

insert O(logn)

merge O(n)

 

 

i是当前节点,根节点定义为0

  • 它的左孩子的位置:2*i + 1
  • 它的右孩子的位置:2*i + 2
  • 父节点的位置: i-1 / 2
  • 层数 logN  (N节点总个数)
  • 第n层的节点数:最多2^(n-1)
  • 节点的度:节点所拥有的子树个数(0,1,2)
  • 叶子节点:度为0的节点 (没有子树)
  • 树的深度,高度:从上到下为深度1,深度2。。从下到上为高1,高2,。。。
  • 一颗深度为k的二叉树,最多有2^k - 1个节点,最多k个

 

哈夫曼树

对于给定的有各自权值的 n 个结点,构建哈夫曼树有一个行之有效的办法:

  1. 在 n 个权值中选出两个最小的权值,对应的两个结点组成一个新的二叉树,且新二叉树的根结点的权值为左右孩子权值的和;
  2. 在原有的 n 个权值中删除那两个最小的权值,同时将新的权值加入到 n–2 个权值的行列中,以此类推;
  3. 重复 1 和 2 ,直到所以的结点构建成了一棵二叉树为止,这棵树就是哈夫曼树。

图 2 哈夫曼树的构建过程
 

图 2 中,(A)给定了四个结点a,b,c,d,权值分别为7,5,2,4;第一步如(B)所示,找出现有权值中最小的两个,2 和 4 ,相应的结点 c 和 d 构建一个新的二叉树,树根的权值为 2 + 4 = 6,同时将原有权值中的 2 和 4 删掉,将新的权值 6 加入;进入(C),重复之前的步骤。直到(D)中,所有的结点构建成了一个全新的二叉树,这就是哈夫曼树。

 

以数据集{1,6,8,2,9,4}为权值构造一棵赫夫曼树,其带权路径长度为

 

 

一个重要的结论:

  1. 对于一颗非空二叉树,度为0的节点总是比度为2的节点多一个,即叶子节点的个数为n0, 度为2的节点为n2, n0 = n2 + 1
  2. 具有n个节点的完全二叉树的深度为 logn+1     如log5 = 2 再加1=34

 

例1:一颗完全二叉树的根节点有1001个节点, 其中叶子节点的个数为。

完全二叉树的公式: n=n0+n1+n2。 因为 n0 = n2+1  所以  n = n0-1 + n0 + n1 , 所以 2n0-1+n1 = 1001, 又因为是完全二叉树, 所以

n1只能为1或0, 根据1001所以n1=0, n0=501。

 

例2:X 如果一个二叉树的前序为abcdefg,中序为bcedagf,则该二叉树的后序为?

前序和中序可以确定二叉树的唯一结构。

  1. 根据前序遍历可知,二叉树的根节点为a,再由中序遍历,a左面的bced为它的左子树, 它右面的gf为它的右子树,确定①。
  2. 再看bced,看前序遍历它们位置是bcde,所以bced组成的子树,根节点是b,又因为中序bced, b前面什么都i没有,所以断定ced为b的右子树;gf子树的前序是fg,所以f为根节点,中序为gf,所以g是f的左子树。确定②。
  3. 再看ced,前序为cde,所以c为根节点,再看它的中序为ced,c前面什么都没有,所以ed为c的右子树。确定③。
  4. 看ed的前序为de,所以d为根节点,中序为ed,所以e为d的左子树,确定④。
  5. 递归遍历最终的树,得到⑤,比较前中序结果,确定数结构正确,最终确定后序遍历结果。

例3: 先序遍历序列为啊,a,b ,c d的不同二叉树的个数为?

实际再问,以abcd的顺序入栈, 出栈的情况有多少种?

卡特兰数公式   1/(n+1) * C(n, 2n)

n = 4 时  1/5*((8*7*6*5)/(4*3*2*1)) = 14   

记住常用的值也好  1, 2, 5 ,14 ,42 , 132

 

 

一 前序中序后序递归实现

class BinaryTreeNode(object):
    def __init__(self, data=None, left=None, right=None):
        self.data = data
        self.left = left
        self.right = right


class BinaryTree(object):
    def __init__(self, root=None):
        self.root = root

    def is_empty(self):
        return self.root is None

    def preOrder(self, BinaryTreeNode):
        if BinaryTreeNode is None:
            return
        # 先打印根结点,再打印左结点,后打印右结点
        print(BinaryTreeNode.data)
        self.preOrder(BinaryTreeNode.left)
        self.preOrder(BinaryTreeNode.right)

    def inOrder(self, BinaryTreeNode):
        if BinaryTreeNode is None:
            return
        # 先打印左结点,再打印根结点,后打印右结点
        self.inOrder(BinaryTreeNode.left)
        print(BinaryTreeNode.data)
        self.inOrder(BinaryTreeNode.right)

    def postOrder(self, BinaryTreeNode):
        if BinaryTreeNode is None:
            return
        # 先打印左结点,再打印右结点,后打印根结点
        self.postOrder(BinaryTreeNode.left)
        self.postOrder(BinaryTreeNode.right)
        print(BinaryTreeNode.data)


n1 = BinaryTreeNode(data="D")
n2 = BinaryTreeNode(data="E")
n3 = BinaryTreeNode(data="F")
n4 = BinaryTreeNode(data="B", left=n1, right=n2)
n5 = BinaryTreeNode(data="C", left=n3, right=None)
root = BinaryTreeNode(data="A", left=n4, right=n5)
bt = BinaryTree(root)
print('先序遍历')
bt.preOrder(bt.root)
print('中序遍历')
bt.inOrder(bt.root)
print('后序遍历')
bt.postOrder(bt.root)

# 先序遍历
# ABDECF
# 中序遍历
# DBEAFC
# 后序遍历
# DEBFCA

二 非递归实现

class BinaryTreeNode(object):
    def __init__(self, data=None, left=None, right=None):
        self.data = data
        self.left = left
        self.right = right


class BinaryTree(object):
    def __init__(self, root=None):
        self.root = root

    def is_empty(self):
        return self.root is None

    def preOrder1(self):
        """
        preOrder每次都将遇到的节点压入栈,当左子树遍历完毕后才从栈中弹出最后一个访问的节点,再访问其右子树。入栈打印
        """
        if not self.root:
            return
        stack = []
        node = self.root
        while node or stack:
            while node:
                # 从根节点开始,一直找它的左子树
                print(node.data)
                stack.append(node)
                node = node.left
            # while结束表示当前节点node为空,即前一个节点没有左子树了
            node = stack.pop()
            # 开始查看它的右子树
            node = node.right

    def inOrder1(self, root):
        """
        中序的非递归遍历与先序的非递归遍历类似。先序遍历是先访问节点,然后再将节点入栈,后中序遍历则是先入栈,然后节点弹出栈后再访问。出栈打印
        """
        if not self.root:
            return
        stack = []
        node = self.root
        while node or stack:
            while node:
                #  从根节点开始,一直找到左子树
                stack.append(node)
                node = node.left
            # while结束表示当前节点node为空,即前一个节点没有左子树了
            node = stack.pop()
            print(node.data)
            node = node.right

    def postOrder1(self, root):
        """
        从直觉上来说,后序遍历对比中序遍历难度要增大很多。因为中序遍历节点序列有一点的连续性,而后续遍历则感觉有一定的跳跃性。先左,再右,
        最后才中间节点;访问左子树后,需要跳转到右子树,右子树访问完毕了再回溯至根节点并访问之
        """
        if not self.root:
            return
        stack1 = []
        stack2 = []
        node = self.root
        stack1.append(node)
        while stack1:
            node = stack1.pop()
            if node.left:
                stack1.append(node.left)
            if node.right:
                stack1.append(node.right)
            stack2.append(node)
        while stack2:
            print(stack2.pop().data)



    def postOrder2(self):
        """
        自己写的后序遍历,自己更容易理解, 把先序遍历, 改成先压右节点,变成 中右左  在用个列表逆序下, 左右中 变成后序
        """
        if not self.root:
            return
        stack = []
        stack1 = []
        node = self.root
        while node or stack:
            while node:
                stack1.append(node.data)
                stack.append(node)
                node = node.right
            node = stack.pop()
            node = node.left
        for i in stack1[::-1]:
            print(i)



n1 = BinaryTreeNode(data="D")
n2 = BinaryTreeNode(data="E")
n3 = BinaryTreeNode(data="F")
n4 = BinaryTreeNode(data="B", left=n1, right=n2)
n5 = BinaryTreeNode(data="C", left=n3, right=None)
root = BinaryTreeNode(data="A", left=n4, right=n5)


bt = BinaryTree(root)
print('非递归先序遍历')
bt.preOrder1()
print('非递归中序遍历')
bt.inOrder1()
print('非递归后续遍历')
bt.postOrder1()

三 构造二叉树还可以直接用列表构造

不过如[1, 2, 3 ,4, 5, 6, 7 ,8 ,9]  

是这样的情况,不是列表的第一个节点作为root。

这样实现

 

 

四 判断是否是搜索二叉树

其实总体思路挺简单的, 就是中序遍历二叉树, 如果是搜索二叉树的话, 中序遍历是升序的。那么更优化方法是,就是中序变量时,记录下前继节点的值,再和当前的值比较, 如果前继节点小于当前节点,就继续, 否则直接返回False。

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


class TreeList(object):
    def __init__(self, root=None, prev=None):
        self.root = root
        self.prev = prev

    def arr_to_tree(self, arr, start, end):
        if end >= start:
            root = TreeNode()
            # 最好+1, 能构成二叉搜索
            mid = (start + end + 1) // 2
            root.data = arr[mid]
            root.left = self.arr_to_tree(arr, start, mid - 1)
            root.right = self.arr_to_tree(arr, mid + 1, end)
        else:
            root = None
        self.root = root
        return root

    def helper(self, root):
        """
        判断是否是搜索二叉树
        """
        if root is None:
            return True
        if not self.helper(root.left):
            return False
        if self.prev and self.prev.data >= root.data:
            return False
        self.prev = root
        if not self.helper(root.right):
            return False
        return True


t = TreeList()
t.arr_to_tree([1, 2, 3, 4, 5, 6], 0, 5)
print(t.helper(t.root))

 

五 找到两个节点的最近公共节点

二叉树怎么找, 和搜素二叉树怎么找。

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


class TreeList(object):
    def __init__(self, root=None, prev=None):
        self.root = root
        self.prev = prev

    def arr_to_tree(self, arr, start, end):
        if end >= start:
            root = TreeNode()
            # 最好+1, 能构成二叉搜索
            mid = (start + end + 1) // 2
            root.data = arr[mid]
            root.left = self.arr_to_tree(arr, start, mid - 1)
            root.right = self.arr_to_tree(arr, mid + 1, end)
        else:
            root = None
        self.root = root
        return root


    def find_it(self, root, p, q):
        """
        任意二叉树找最近的公共祖先
        """
        if not root or root.data == p or root.data == q:
            return root
        tree_left = self.find_it(root.left, p, q)
        tree_right = self.find_it(root.right, p, q)
        if not tree_left:
            return tree_right
        elif not tree_right:
            return tree_left
        elif tree_left:
            return root
        else:
            return

    def lowest_common_ancestor(self, p, q):
        """
        搜索二叉树找公共祖先
        """

        root = self.root
        while root:
            if p < root.data > q:
                root = root.left
            elif p > root.data < q:
                root = root.right
            else:
                return root


t = TreeList()
t.arr_to_tree([1, 2, 3, 4, 5, 6], 0, 5)
print()
print(t.lowest_common_ancestor(1, 3).data)
print(t.find_it(t.root, 1, 3).data)

 

 

二叉树集大成

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


class TreeList(object):
    def __init__(self, root=None):
        self.root = root

    def arr_to_tree(self, arr, start, end):
        """
        数组转成搜索二叉树, 别忘记传start,end
        :param arr:
        :param start:
        :param end:
        :return:
        """
        if end >= start:
            root = TreeNode()
            # 最好+1, 能构成二叉搜索
            mid = (start+end+1) // 2
            root.data = arr[mid]
            root.left = self.arr_to_tree(arr, start, mid-1)
            root.right = self.arr_to_tree(arr, mid+1, end)
        else:
            root = None
        self.root = root
        return root

    def pre_print(self):
        """
        前序遍历
        :return:
        """
        if not self.root:
            return
        stack = []
        node = self.root
        while node or stack:
            while node:
                print(node.data)
                stack.append(node)
                node = node.left
            node = stack.pop()
            node = node.right

    def ord_print(self):
        """
        中序遍历
        :return:
        """
        if not self.root:
            return
        stack = []
        node = self.root
        while stack or node:
            while node:
                stack.append(node)
                node = node.left
            node = stack.pop()
            print(node.data)
            node = node.right

    def last_print(self):
        """
        后续遍历
        :return:
        """

        if not self.root:
            return
        stack, tmp = [], []
        node = self.root
        while stack or node:
            while node:
                stack.append(node)
                tmp.append(node)
                node = node.right
            node = stack.pop()
            node = node.left
        for i in reversed(tmp):
            print(i.data)

    def revers_tree(self):
        """
        反转二叉树
        :return:
        """
        root = self.root
        if not root:
            return
        node_list = [root]
        while node_list:
            node = node_list.pop(0)
            if node:
                node_list.append(node.right)
                node_list.append(node.left)
                node.left, node.right = node.right, node.left

     def level_order(self):
        """
        层序遍历
        """
        
        root = self.root
        if not root:
            return []
        result = []
        queue = deque()
        queue.append(root)
        while queue:
            level_size = len(queue)
            current_level = []
            for _ in range(level_size):
                node = queue.popleft()
                current_level.append(node.data)
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            result.append(current_level)
        return result

    def find_it(self, root, p, q):
        """
        任意二叉树找最近的公共祖先
        """
        if not root or root.data == p or root.data == q:
            return root
        tree_left = self.find_it(root.left, p, q)
        tree_right = self.find_it(root.right, p, q)
        if not tree_left:
            return tree_right
        elif not tree_right:
            return tree_left
        elif tree_left:
            return root
        else:
            return

    def lowest_common_ancestor(self, p, q):
        """
        搜索二叉树找公共祖先
        """

        root = self.root
        while root:
            if p < root.data > q:
                root = root.left
            elif p > root.data < q:
                root = root.right
            else:
                return root


    def helper(self, root):
        """
        判断是否是搜索二叉树
        """
        if root is None:
            return True
        if not self.helper(root.left):
            return False
        if self.prev and self.prev.data >= root.data:
            return False
        self.prev = root
        if not self.helper(root.right):
            return False
        return True

    def max_depth(self, root):
        """
        最大深度 
        """
        if not root:
            return 0
        return 1 + max(self.max_depth(root.left), self.max_depth(root.right))

    def min_depth(self, root):
        """
        最小深度
        """
        if not root:
            return 0
        left = self.min_depth(root.left)
        right = self.min_depth(root.right)
        if left == 0 or right == 0:
            # 判断是否右左右子树
            return left + right + 1
        else:
            return min(left, right) + 1


class Solution(object):
    """
    实现的是二叉树中两个节点的最大路径
    """
    def __init__(self):
        self.tmp = []

    def max_depth(self, root):
        if not root:
            return 0
        left = self.max_depth(root.left)
        right = self.max_depth(root.right)
        return max(right, left) + 1

    def max_distance(self, root):
        if not root:
            return 0
        self.tmp.append(self.max_depth(root.left) + self.max_depth(root.right))
        self.max_distance(root.left)
        self.max_distance(root.right)
        return max(self.tmp)


t = TreeList()
t.arr_to_tree([1, 2, 3, 4, 5, 6], 0, 5)
t.revers_tree()
t.pre_print()
t.ord_print()
s = Solution()
print(s.max_distance(t.root))
print(t.helper(t.root))

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值