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