二叉树反序列化 非递归实现

生成随机二叉树并彩色打印参考这个链接
前序遍历反序列化非递归有很多种解法,在写算法的过程种,我们可能会有很多想法,有的实现起来简单,有的实现起来复杂,但总的来说是殊途同归的。解题中可能会遇到的一个难点是,我们把很多种解法杂糅到一起了,把自己的思绪搞的很乱,这时候可以先不追求最优解,把每种思路一直推演下去,不要夹杂其他思路的实现细节。看到某种别人的解法的思路和自己不同时,就感觉自己想错了。这种想法会很限制自己的思维,从不同的思路出发可能会有不同的解法,不要因为最终没有实现就认为这种思路是错的。平时刷题也可以练习一下复杂的解法,用多种解法实现会对问题从不同方面认识的都更深刻。花了两天才用非递归实现反序列化,智商不够用时间弥补吧。~~~

前序遍历时间复杂度O(N), 额外空间复杂度O(lgN)的解法

前序遍历的序列化和非序列化 递归实现
# 前序序列化
def serializeTree(head):
    if not head:
        return [None]
    strLeft = serializeTree(head.left)
    strRight = serializeTree(head.right)
    return [head.val]+strLeft+strRight

# 这个递归形式很巧妙 使用了全局变量
def reconstructTree(ss):
	from collections import deque
	ss = deque(ss)
    s = ss.popleft()
    if not s:
        return None
    root = Node(s, left=reconstructTree(ss), right=reconstructTree(ss))
    return root
前序遍历的序列化和反序列化 非递归实现
方法1 哑节点

前序遍历非空的情况下,第一个节点就是根节点
非递归实现关键是要判断是否后面的节点是前面节点的左孩子还是右孩子。默认创建的节点是Node(val, left=None,right=None)。当有的节点,它的孩子是None,反序列化的时候就很难判断是否已经给这个节点添加左孩子或有孩子了。
创建节点时,左右孩子使用哑节点来代替默认的None,可以方便判断是否已经给这个节点添加左孩子或有孩子了。

# 非递归形式的前序遍历序列化
def serializeTree(head):
    if not head:
        return
    stack = [head]
    ss = []
    while stack:
        finish = stack.pop()
        if finish:
            ss.append(finish.val)
            stack.append(finish.right)
            stack.append(finish.left)
        else:
            ss.append(None)
    return ss
    
# 和反序列化
def deserializeTree1(ss):
    if not ss:
        return
    ss = deque(ss)
    s = ss.popleft()
    head = Node(s, left=Node(None), right=Node(None))
    stack = [head]
    while stack:
        finish = stack[-1]
        s= ss.popleft()
        node = None
        if s:
            node = Node(s,left=Node(None), right=Node(None))
        # 如果左孩子时哑节点,存在但值为空
        if finish.left and not finish.left.val:
            finish.left = node
            if s:
                stack.append(finish.left)
        else:
            finish.right = node
            stack.pop()
            if s:
                stack.append(finish.right)
    return head
方法2 模拟后序遍历的方式 用node作循环条件而不是ss弹出的s,左右孩子已经有指向的节点从栈中弹出。
def deserializeTree2(ss):
    if not ss:
        return
    ss = deque(ss)
    node = head = generateNode(ss.popleft())
    stack = []
    while ss:
        while node:
            if stack and not stack[-1].left:
                stack[-1].left = node
            stack.append(node)
            node = generateNode(ss.popleft())
        # 可能会有右孩子
        s = ss.popleft()
        if s:
            node = generateNode(s)
            stack[-1].right = node
        stack.pop()
    return head
方法3 通过hasLeft这个额外变量来判断是否已经反序列化左右孩子
def deserializeTree3(ss):
    if not ss:
        return
    ss = deque(ss)
    head = Node(ss.popleft())
    stack = [head]
    hasLeft = False
    while ss:
        s = ss.popleft()
        # s 不为空时,只可能是上一个节点的左孩子
        if s:
            node = Node(s)
            if not hasLeft and not stack[-1].left:
                stack[-1].left = node
            else:
                stack[-1].right = node
                stack.pop()
                hasLeft = False
            stack.append(node)
        else:
            if hasLeft or stack[-1].left:
                stack.pop()
                hasLeft = False
            elif not hasLeft:
                hasLeft = True
    return head
方法4 前序遍历的反序列化 由一般递归改成非递归的套路实现,可以参考递归改写成非递归的两种套路 Python实现。这种方法按部就班的改写就好了,通用性很强,不需要什么特别的技巧。
def deserializeTree2(ss):
    if not ss:
        return
    ss = deque(ss)
    s = ss.popleft()
    stack = []
    while ss or stack:
        while s:
            paramsLeft = [False, s, None]
            paramsRight = [False, s, None]
            stack.append(paramsRight)
            stack.append(paramsLeft)
            s = ss.popleft()
        finishLeft = stack[-1]
        finishRight = stack[-2]
        if not finishLeft[0]:
            finishLeft[0] = True
        if not finishRight[0]:
            s = ss.popleft()
            if not s:
                finishRight[0] = True
        if finishRight[0]:
            node = Node(finishRight[1])
            node.left = finishLeft[-1]
            node.right = finishRight[-1]
            stack.pop()
            stack.pop()
            if stack:
                # 先判断左边是否处理了
                if not stack[-1][0]:
                    stack[-1][-1] = node
                    stack[-1][0] = True
                else:
                    stack[-2][-1] = node
                    stack[-2][0] = True
    return node
方法5 对序列化后的字符串列表本身进行后续遍历。时间复杂度O(NlgN),额外空间复杂度O(lgN)
# 时间复杂度O(NlgN),空间复杂度O(lgN)
def deserializeTree5(ss):
    if not ss:
        return
    stack = []
    L = 0
    R = len(ss)-1
    while stack or L < R:
        while L+1 < R:
            # L+1到i为左子树的范围,i+1到R为右子树的范围。
            n = 0
            for i in range(L, R + 1):
                if ss[i]:
                    n += 1
                else:
                    n -= 1
                if n == 0:
                    break
            stack.append([Node(ss[L]),L, i, R])
            if L+1+1 < i:
                L = L + 1
                R = i
            else:
                L = i + 1
                R = R
        finish = stack.pop()
        i, R = finish[2:]
        # 如果是右孩子
        if stack and R == stack[-1][-1]:
            stack[-1][0].right = finish[0]
        # 如果是左孩子,查看有无右孩子
        elif stack and R != stack[-1][-1]:
            stack[-1][0].left = finish[0]
            L = stack[-1][2] + 1
            R = stack[-1][-1]
    return finish[0]
方法5的递归形式 没有用全局变量
def deserializeTree6(ss):
    if not ss:
        return
    def process(L, R):
        if L >= R:
            return
        n = 0
        for i in range(L, R+1):
            if ss[i]:
                n += 1
            else:
                n -= 1
            if n == 0:
                break
        node = Node(ss[L])
        left = process(L+1,i)
        right = process(i+1, R)
        node.left = left
        node.right = right
        return node
    head = process(0,len(ss)-1)
    return head
层序遍历的序列化和非序列化 非递归实现
# 层序遍历的序列化
def levelSerializeTree(head):
    if not head:
        return
    strlst = deque([head.val])
    queue = deque([head])
    while queue:
        node = queue.popleft()
        if node.left:
            queue.append(node.left)
            strlst.append(node.left.val)
        else:
            strlst.append(None)
        if node.right:
            queue.append(node.right)
            strlst.append(node.right.val)
        else:
            strlst.append(None)
    return strlst
    
# 反序列化
def levelReconstructTree(ss):
    if not ss:
        return
    root = generateNode(ss.popleft())
    queue = deque([root])
    while queue:
        node = queue.popleft()
        node.left = generateNode(ss.popleft())
        node.right = generateNode(ss.popleft())
        if node.left:
            queue.append(node.left)
        if node.right:
            queue.append(node.right)
    return root
测试六种方法
def test(num=10000):
    for i in range(num):
        head = generateRandomTree(30)
        ss = serializeTree1(head)
        if printTree(deserializeTree2(ss[::])) != printTree(deserializeTree1(ss[::])) \
            or printTree(deserializeTree1(ss[::])) != printTree(deserializeTree3(ss[::])) \
            or printTree(deserializeTree1(ss[::])) != printTree(deserializeTree4(ss[::]))\
            or printTree(deserializeTree1(ss[::])) != printTree(deserializeTree5(ss[::]))\
            or printTree(deserializeTree1(ss[::])) != printTree(deserializeTree6(ss[::])):
            print("varify Failed")
            break
    else:
        print("nice!")

if __name__ == "__main__":
    test()
效果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值