左神算法-初级5(python)

二叉树

0、构建二叉树

class BinaryTree(object):
    def __init__(self, data):
        self.data = data
        self.child_l = None
        self.child_r = None
        self.parent = None

# 创建
a = BinaryTree(1)
b = BinaryTree(2)
c = BinaryTree(3)
d = BinaryTree(4)
e = BinaryTree(5)
f = BinaryTree(6)
g = BinaryTree(7)

# 构造节点关系
a.child_l = b
a.child_r = c
b.child_l = d
b.child_r = e
c.child_l = f
c.child_r = g
b.parent = a
c.parent = a
d.parent = b
e.parent = b
f.parent = c
g.parent = c

# 设置根
root = a
print('根:', root.data)

1、实现二叉树的先序、 中序、 后序遍历(递归、非递归)

'''
递归会回到每个节点3次:中左左左中右右右中
前序:每个节点取第一次出现的值:中左右
中序:每个节点取第二次出现的值:左中右
后序:每个节点取第三次出现的值:左右中
'''
# 递归模式
def pre_order(tree):
    if tree:
        print(tree.data, end=',')
        pre_order(tree.child_l)
        pre_order(tree.child_r)

def in_order(tree):
    if tree:
        in_order(tree.child_l)
        print(tree.data, end=',')
        in_order(tree.child_r)

def post_order(tree):
    if tree:
        post_order(tree.child_l)
        post_order(tree.child_r)
        print(tree.data, end=',')

print('前序:')        
pre_order(root) 
print('\n')
print('中序:')  
in_order(root)
print('\n')
print('后序:') 
post_order(root)    
# 非递归模式 
# 前序  中左右      
def pre_order1(root):
    if not root:
        return 
    stack = [root]
    while stack:
        tmp = stack.pop()
        print(tmp.data)
        if tmp.child_r:
            stack.append(tmp.child_r)
        if tmp.child_l:
            stack.append(tmp.child_l)

#pre_order1(root)        

# 先压入所有左边界,再弹出最左边的节点,  左中右        
def in_order1(root):
    if not root:
        return 
    stack = []
    while stack or root:
        if root:
            stack.append(root)
            root = root.child_l
        else:
            root = stack.pop()
            print(root.data, end = ', ')
            root = root.child_r
            
#in_order1(root)

# 先实现 中右左  将结果存入栈中  再依次弹出,即为后序  左右中
def post_order1(root):
    if not root:
        return 
    stack = [root]
    res = []
    while stack:
        tmp = stack.pop()
        res.append(tmp.data)
        if tmp.child_l:
            stack.append(tmp.child_l)
        if tmp.child_r:
            stack.append(tmp.child_r)
    while res:
        print(res.pop(), end=', ')
        
#post_order1(root) 

2、中序遍历后继/前继节点

'''
中序遍历后继节点
左中右

当前节点有右孩子:返回右孩子的最左节点
当前节点没有右孩子:
当前节点是父节点的左孩子,返回父节点;
当前节点是父节点的右孩子,向上找,直到某一结点是其父节点的左孩子,返回父节点
'''
def find(node):
    if node == None:
        return None
    if node.child_r != None:
        tmp = node.child_r
        while tmp and tmp.child_l:
            tmp = tmp.child_l
        return tmp
    else:
        p = node.parent
        while p and p.child_l != p:
            node = p
            p = p.parent
        return p

print(find(a).data)  
'''
中序遍历前继节点
左中右

当前节点有左孩子:返回右孩子的最右节点
当前节点没有左孩子:
当前节点是父节点的右孩子,返回父节点;
当前节点是父节点的左孩子,向上找,直到某一结点是其父节点的右孩子,返回父节点
'''        
def find1(node):
    if node == None:
        return None
    if node.child_l != None:
        tmp = node.child_l
        while tmp and tmp.child_r:
            tmp = tmp.child_r
        return tmp
    else:
        p = node.parent
        while p and p.child_r != p:
            node = p
            p = p.parent
        return p
    
print(find1(a).data)

3、二叉树的序列化和反序列化(前序、层序)

'''
序列化:用文件记录树结构,可以永久保存
'''
# 先序序列化
def string(root):
    res = []
    def pre(root):
        if root == None:
            res.append('#')
        else:
            res.append(str(root.data))
            pre(root.child_l)
            pre(root.child_r)
    pre(root)
    return ' '.join(res)

print('序列化结果:', string(root))    
# 反序列化:还原树结构
def str2tree(root):
    s = string(root) # 序列化
#    print(s)
#   利用分隔好的字符串生成的数组生成一个迭代器。也可以遍历字符串,生成数组
    vallist = iter(s.split(' '))
    def totree():
#       通过next不断调用vallist这个迭代器里的元素,相当于for循环
        val = next(vallist)
#        print(val)
        if val == '#':
            return None
        else:
            head = BinaryTree(int(val))
            head.child_l = totree()
            head.child_r = totree()
        return head
    head = totree()
    return head 

print('反序列化结果:', str2tree(root).data)
# 验证反序列化结果
newtree = str2tree(root)
print('验证反序列化结果:', string(newtree))
# 层序序列化
def string1(root):
    if not root:
        return []
    res = []
    queue = [root]
    while queue:
        p = queue.pop(0)
        if p:
            res.append(str(p.data))
            queue.append(p.child_l)
            queue.append(p.child_r)
        else:
            res.append('#')
    
    return ' '.join(res)

print('序列化结果:', string1(root)) 
# 反序列化
def str2tree1(root):
    s = string1(root) # 序列化
    if s == []:
        return None

    val = s.split(' ')
    i = 1
    head = BinaryTree(int(val[0]))
    queue = [head]
    while queue:
        p = queue.pop(0)
        if val[i] != '#':
            p.child_l = BinaryTree(int(val[i]))
            queue.append(p.child_l)
        i += 1
        if val[i] != '#':
            p.child_r = BinaryTree(int(val[i]))
            queue.append(p.child_r)
        i += 1
        
    return head 

print('反序列化结果:', str2tree1(root).data)
# 验证反序列化结果
newtree = str2tree1(root)
print('验证反序列化结果:', string1(newtree))

4、平衡二叉树,左右子树高度差不超1(不一定是满树)、满二叉树(一定是平衡树)

'''
平衡二叉树:以每个节点为头节点的子树都是平衡树

① 左平衡否
② 右平衡否
③ 左高乎?
④ 右高乎?

进阶:树形dp
'''
# 每个子树都要判断是否平衡
# 自底向上
def IsBalanced(root):
    def psf(p):
        if p ==  None:
            return 0
        left = psf(p.child_l)
        if left == -1:
            return -1
        right = psf(p.child_r)
        if right == -1:
            return -1
         
        if abs(left-right)>1:
            return -1
        return 1 + max(right,left)
    return psf(root) != -1

print('是平衡数:',IsBalanced(root))

# 自上而下
def IsBalanced2(root):
    def treehight(root):
        if not root:
            return 0
        left = treehight(root.child_l)
        right = treehight(root.child_r)
        return max(left, right) + 1
    if not root:
        return True
    # 判断子树是否平衡
    left = treehight(root.child_l)
    right = treehight(root.child_r)
    if abs(right - left) > 1:
        return False
    return balance_tree(root.child_l) and balance_tree(root.child_r)
        
print('是平衡数:',IsBalanced2(root))

5、搜索二叉树

'''
任何一个节点的左节点值比他小,右节点值比他大,即中序遍历结果升序
通常二叉树不含重复节点
'''
# 判断是否为搜索二叉树
def isBST(root):
    if not root:
        return 
    stack = []
    pre = float('-inf')
    while stack or root:
        if root:
            stack.append(root)
            root = root.child_l
        else:
            root = stack.pop()
            print(root.data, end = ', ')
            if root.data > pre:
                pre = root.data
                root = root.child_r
            else:
                return False
            
    return True

print('是搜索二叉树:', isBST(root))

6、完全二叉树

'''
完全二叉树:若二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,
第 h 层所有的结点都连续集中在最左边。

判断:
层序遍历过程中:
① 某节点有右子无左子,False
② 某节点左右孩子不全,后面所有节点必须是叶子节点
'''
def isCBT(root):
    if not root:
        return True
    flag = False
    queue = [root]
    while queue:
        head = queue.pop(0)
        l = head.child_l
        r = head.child_r
        # 情况 1
        if l == None and r != None:
            return False
        # 情况 2
        if flag and (l != None or r != None):
            return False
        if l:
            queue.append(l)
        if r:
            queue.append(r)
        # 某节点左右孩子不全,改变flag ,下一次判断条件 2 
        else:
            flag = True
    return True

print('是完全二叉树:', isCBT(root))


# 数组实现堆,扩容代价,二叉树实现则没有

7、完全二叉树节点的个数

'''
已知一颗完全二叉树,求其节点的个数
要求:时间复杂度低于O(n),n是节点个数

满二叉树:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点二叉树。
满二叉树一定是完全二叉树,反之不一定。

满树节点:2^深度 - 1
时间复杂度:O((logN)^2)

遍历左边界 得到二叉树高度 h
遍历右边界 到达最后一层,则为满二叉树

对于完全二叉树来说,左右子树最少一个为满树
右子树的  左高度触底,则左子树为满二叉树
右子树的  左高度没有触底,则右子数为满二叉树
'''        
def countNodes(root):
    def recursion(node, level, h):
        # node当前节点, level当前节点高度, h树的高度
        if level == h:
            return 1
        if mostLeftlevel(node.child_r, level+1) == h:
            return (1<<(h-level)) + recursion(node.child_r, level+1, h)
        else:
            return (1<<(h-level-1)) + recursion(node.child_l, level+1, h)
        
    def mostLeftlevel(node, level):
        while node:
            level += 1
            node = node.child_l
        return level - 1  
    
    if not root:
        return 0
    return recursion(root, 1, mostLeftlevel(root, 1))

print('完全二叉树节点的个数:', countNodes(root))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值