方法一:DFS(深度优先遍历)
二叉树的DFS序列化很简单,无非就是先序遍历还是后序遍历的选择问题,唯一需要注意的就是输出的字符串的格式问题,这会直接影响到反序列化的操作
1、序列化
以后我统一使用先序遍历,因为这样根节点就是第一个元素,一路往后即可
def serialize(self, root):
if not root:
# 注意n后面有一个逗号
return 'n,'
left = self.serialize(root.left)
right = self.serialize(root.right)
# 注意我的返回方式,有个逗号隔开了,先序遍历
# 虽然这个操作放在最后的但是是先序遍历!!
return str(root.val)+','+left+right
2、反序列化
首先要将传进来的字符串data以‘,’为分割线割成列表,然后一个个的操作,反序列化需要使用到一个新的辅助函数。
整个反序列化最难的点就是递归的逻辑,这才是将递归用到了极致,就完全不管中间是如何实现的,传进来一个值,先判断是不是‘n’,如果不是,就以这个值创建一个 ’根‘ 节点node,这个时候创建’node‘的那个值已经被弹出去了,剩下的第一个就是左子树的值了,所以直接将剩下的整个data(具体实现是m_data,这样更好理解)传进help,help会一路向左走到头就像先序遍历二叉树那样一直走到某个node.left=None,然后返回一路试探性往右走,其实就是先序遍历的过程。
但是难就难在这,反着先序遍历(指的是,通过先序遍历的方式创建一个本不存在的二叉树)。
注意,pop的时候不用判断列表是否为空,因为列表必定以n结尾,n的话就不会继续向下递归了,换句话说当列表为空的时候刚好递归结束!
还是先记下来把,上来先设置递归出口,然后左子树,右子树,最后返回创建出来的node
def deserialize(self, data):
data = data.split(',')
def help(m_data):
# 使用pop(0)弹出第一个元素,注意是弹出
val = m_data.pop(0)
if val == 'n': return None
# 这一要int一下,不int也能通过。。。。
val = int(val)
node = TreeNode(val)
# 因为先序遍历中->左->右,所以反序列化先以val创建node
# 然后定义左子树,再定义右子树!
node.left = help(m_data)
node.right = help(m_data)
return node
return help(data)
整体代码:
def serialize(self, root):
if not root:
return 'n,'
left = self.serialize(root.left)
right = self.serialize(root.right)
# 注意我的返回方式,有个逗号隔开了,先序遍历
# 虽然这个操作放在最后的但是是先序遍历!!
return str(root.val)+','+left+right
def deserialize(self, data):
data = data.split(',')
def help(m_data):
# 使用pop(0)弹出第一个元素,注意是弹出
val = m_data.pop(0)
if val == 'n': return
node = TreeNode(val)
node.left = help(m_data)
node.right = help(m_data)
return node
return help(data)
这里有个小tips:
其实就是局部变量与全局变量的问题,在一个函数中创建另一个函数,新创建的函数中不能对原来函数中的变量进行改变,比如重新赋值什么的,但是可以对原来函数中的列表进行一些操作(增删改查)啥的,但是同样的,不可以重新定义它!
方法二:BFS(广度,也就是宽度优先遍历)
广度优先遍历比深度优先遍历更直观,他就是直接记录下了整棵数的样子,一层一层排下来,而且每一个位置都保留了值(空的就是n),值得多少只与整个二叉树得深度有关。
看了一下怎么感觉BFS的反序列化更麻烦了,还是记下来吧,记住了这一题就是你得了
1、序列化
BFS的序列化就是二叉树的宽度优先遍历,利用了队列,先进先出,虽然不知道哪些是哪一层的,但是后续的遍历会把关系都一一对应上,实际上的宽度优先遍历就是横着把所有的值一个个送进去,常规的遍历对于空节点是不操作的,也就是没有else的那一步,但是这里需要记下来,而且记录的仅仅是父节点非空的None,看起来是这样的:
横着把所有的数送进去(包括n),没有的数不送,出来的就是
“dbeacnfnnnnngnn”
def serialize(self, root):
s = ""
queue = []
queue.append(root)
while queue:
root = queue.pop(0)
if root:
s += str(root.val)
# 如果root.left为空也会被进队列
queue.append(root.left)
queue.append(root.right)
else:
s += "n"
s += ","
return s
2、反序列化
反序列化其实不用知道哪个数具体属于那一层也能还原,应为指向具体数据的指针i与每个节点一一对应,只要不乱就会一直对应下去,理解不了就tm记下来,就像二叉树的遍历一样,用多了自然就理解了
def deserialize(self, data):
tree = data.split(',')
print(tree)
# 如果根节点就是空得直接返回
if tree[0] == "n":
return None
queue = []
root = TreeNode(int(tree[0]))
queue.append(root)
i = 1
while queue:
# cur是弹出来的节点,不是字符串的值
cur = queue.pop(0)
# 如果cur为空,那他就没有子节点,直接continue
# continue i不加2只因为在BFS的时候空节点就没有子节点!
# 所以当cur到这个空节点的时候,i已经指向下一个非空节点的
# 子节点的值了
if not cur:
continue
cur.left = TreeNode(int(tree[i])) if tree[i] != "n" else None
cur.right = TreeNode(int(tree[i + 1])) if tree[i + 1] != "n" else None
# 注意是+2,因为i的后面一个是当前节点的右节点,两个才是下一个节点的左节点
i += 2
queue.append(cur.left)
queue.append(cur.right)
return root