二叉树的python实现

深度优先遍历中每个节点会被进入三次,
如果第一次进入就访问称为先序遍历,对于每个节点来说,会先访问它,再访问左子树,最后访问右子树
如果第二次进入才访问称为中序遍历,对于每个节点来说,会先访问左子树,再访问它,最后访问右子树
如果第三次进入才访问称为后序遍历,对于每个节点来说,会先访问左子树,再访问右子树,最后访问它

广度优先遍历每个节点只进入一次,
从图像上来看是从上到下、从左到右依次进入(访问)每个节点

class Node(object):
    def __init__(self, item=None, lchild=None, rchild=None):
        self.item = item
        self.lchild = lchild
        self.rchild = rchild


def build_tree1(preorder, inorder):
    if len(preorder) == 0:
        return None
    tree = Node(preorder[0])
    # 前序遍历的第一个元素为根节点,
    # 中序遍历中,根节点的左边为左子树,右边为右子树
    # 前序遍历序列中,左子树部分第一个出现的数为左子树根节点,同理右子树(这个信息目前不使用)
    root_index_inorder = inorder.index(preorder[0])
    # 已知左子树有root_index_inorder个元素
    # 前序遍历序列中,根节点后取root_index_inorder个元素即为参与左子树构建的元素
    tree.lchild = build_tree1(
        preorder[1:root_index_inorder+1], inorder[:root_index_inorder])
    # 前序遍历序列剩下的元素即为参与右子树构建的元素
    tree.rchild = build_tree1(
        preorder[root_index_inorder+1:], inorder[root_index_inorder+1:])
    return tree


def build_tree2(inorder, postorder):
    if len(postorder) == 0:
        return None
    tree = Node(postorder[-1])
    # 后序遍历的最后一个元素为根节点,
    # 中序遍历中,根节点的左边为左子树,右边为右子树
    # 后序遍历序列中,左子树部分最后出现的数为左子树根节点,同理右子树(这个信息目前不使用)
    root_index_inorder = inorder.index(postorder[-1])
    # 已知左子树有root_index_inorder个元素
    # 后序遍历序列中,前root_index_inorder个元素即为参与左子树构建的元素
    tree.lchild = build_tree2(
        inorder[:root_index_inorder], postorder[:root_index_inorder])
    # 后序遍历序列中剩下的元素(不包括最后一个元素)即为参与右子树构建的元素
    tree.rchild = build_tree2(
        inorder[root_index_inorder+1:], postorder[root_index_inorder:-1])
    return tree


def build_tree_bfs(arr):
    root = Node(arr[0])
    queue = [root]
    arr.pop(0)
    while arr and queue:
        size = len(queue)
        for _ in range(size):
            cur = queue.pop(0)
            if arr and not cur.lchild:
                cur.lchild = Node(arr[0])
                arr.pop(0)
                queue.append(cur.lchild)
            if arr and not cur.rchild:
                cur.rchild = Node(arr[0])
                arr.pop(0)
                queue.append(cur.rchild)
    return root


def bfs(root):
    queue = []
    queue.append(root)
    while queue and queue[0]:
        size = len(queue)
        for i in range(size):
            cur = queue.pop(0)
            print(cur.item)
            if cur.lchild:
                queue.append(cur.lchild)
            if cur.rchild:
                queue.append(cur.rchild)



def dfs_preorder(root):
    if not root:
        return
    print(root.item)
    dfs_preorder(root.lchild)
    dfs_preorder(root.rchild)
    return


def dfs_preorder_stack(root):
    if not root:
        return
    stack = []
    cur = root
    while stack or cur:
        # 第一次进入某个节点cur,都是先访问,然后进入左节点
        while cur:
            print(cur.item)
            stack.append(cur)
            cur = cur.lchild
        # 第二进入某个节点cur,由于先序遍历一定是已经访问过了,所以再进右节点
        cur = stack.pop()
        cur = cur.rchild

# 时间复杂度O(n)
# 空间复杂度O(logn)
def dfs_inorder(root):
    if not root:
        return
    dfs_inorder(root.lchild)
    print(root.item)
    dfs_inorder(root.rchild)
    return

# 时间复杂度O(n)
# 空间复杂度O(n)
def dfs_inorder_stack(root):
    if not root:
        return
    stack = []
    cur = root
    while stack or cur:
        # 第一次进入某个节点cur, 先进入其左节点
        while cur:
            stack.append(cur)
            cur = cur.lchild
        # 第二次进入某个几点cur, 由于是中序遍历,它的左子树应该全部访问过了
        # 所以现在才访问cur, 然后进入它的右节点
        cur = stack.pop()
        print(cur.item)
        cur = cur.rchild


def dfs_postorder(root):
    if not root:
        return
    dfs_postorder(root.lchild)
    dfs_postorder(root.rchild)
    print(root.item)
    return

# 按照根-右-左的顺序来访问,最后反向
def dfs_postorder_stack(root):
    if not root:
        return
    stack = []
    output = []
    cur = root
    while stack or cur:
        # 第一次进入某个节点cur, 先访问,然后进入右节点
        while cur:
            output.append(cur.item)
            stack.append(cur)
            cur = cur.rchild
        # 第二次进入某个节点cur, 由于是该节点已经被访问过,直接进入左节点
        cur = stack.pop()
        cur = cur.lchild
    return output[::-1]


def get_maxdepth_bfs(root):
    queue = []
    queue.append(root)
    max_depth = 0
    while queue and queue[0]:
        max_depth += 1
        size = len(queue)
        for i in range(size):
            cur = queue.pop(0)
            print(cur.item)
            if cur.lchild:
                queue.append(cur.lchild)
            if cur.rchild:
                queue.append(cur.rchild)
    return max_depth


def get_maxdepth_dfs_postorder(root):
    if not root:
        return 0
    left_depth = get_maxdepth_dfs_postorder(root.lchild)
    right_depth = get_maxdepth_dfs_postorder(root.rchild)
    max_depth = max(left_depth, right_depth) + 1
    return max_depth


class GetMaxdepthDfsPreorder:
    def _dfs_preorder(self, root, temp):
        # temp是root的父节点的深度
        if not root:
            self.max_depth = max(temp, self.max_depth)
            return
        temp += 1
        self._dfs_preorder(root.lchild, temp)
        self._dfs_preorder(root.rchild, temp)

    def _get_max_depth(self, root):
        self.max_depth = -1
        self._dfs_preorder(root, temp=0)
        return self.max_depth


# 时间复杂度O(n)
# 空间复杂度O(logn)为栈的开销
# 每个节点只进入了一次
def is_symmetric(root):
    def check(self, left, right):
        if (not left) and (not right):
            return True
        elif (not left) or (not right):
            return False
        # 此时left, right全部是有值的
        return (left.item == right.item) and check(left.lchild, right.rchild) \
               and check(left.rchild, right.lchild)
    return check(root, root)


# 由于递归的时候每个节点只进入了一次,将递归改成迭代依靠队列
# 时间复杂度O(n)
# 空间复杂度O(n)为队列的开销
def isSymmetric(root):
    def check(left, right):
        queue = []
        queue.append(left)
        queue.append(right)

        # 改成迭代后,只有false才return, 最终运行完没有结束再return True
        while queue:
            left = queue.pop(0)
            right = queue.pop(0)
            # 枚举所有情况:
            # 1:如果left right都是空,则当前是叶子节点
            # 这里如果直接return整个程序就结束了,因此是continue继续判断其他节点
            if (not left) and (not right):
                continue
            # 2: 如果left right只有一个为空,则一定不对称
            elif (not left) or (not right):
                return False
            # 3: 如果left right都不为空,且值不等,则一定不对称
            elif left.val != right.val:
                return False
            # 4: 如果left right都不为空,且值相同,
            # 还要继续往下判断它的子节点的情况,所以并不是continue, 而是要把子节点入队列
            else:
                pass

            queue.append(left.left)
            queue.append(right.right)
            queue.append(left.right)
            queue.append(right.left)

        return True

    return check(root, root)


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值