左神算法-初级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
    评论
初级算法 - Python实现 初级算法是帮助入门算法的一部分,它们旨在帮助初学者掌握算法和数据结构,并提高编程能力。在Python中,我们可以使用各种排序算法来实现初级算法。 常见的初级排序算法包括选择排序、插入排序、冒泡排序和希尔排序。选择排序是一种简单直观的排序方法,它通过不断选择最小的元素并将其放在正确的位置上来排序。插入排序则是通过逐步构建有序序列来排序,将每个元素插入到已排序的序列中的适当位置。冒泡排序通过重复比较相邻的元素并交换它们的位置来排序。希尔排序是一种改进的插入排序算法,通过将比较的元素间隔逐步缩小来提高效率。 选择合适的排序算法取决于具体的应用场景和数据规模。在Python中,我们可以根据需要选择相应的算法来实现初级排序。这些算法在性能上可能有所差异,因此在实际应用中需要根据情况进行选择。 总结起来,初级算法Python中可以通过实现选择排序、插入排序、冒泡排序和希尔排序等常见的排序算法来实现。这些算法可以帮助初学者掌握基本的排序方法,并在实践中提高编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [用 Python 学习算法初级排序算法](https://blog.csdn.net/wangs0622/article/details/78690519)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [力扣初级算法Python)](https://blog.csdn.net/qq_41068877/article/details/121952963)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值