序列化二叉樹
問題描述
請實現兩個函式,分別用來序列化和反序列化二叉樹。你需要設計一個演算法來實現二叉樹的序列化與反序列化。這裡不限定你的序列 / 反序列化演算法執行邏輯,你只需要保證一個二叉樹可以被序列化為一個字串並且將這個字串反序列化為原始的樹結構。
示例:
輸入:root = [1,2,3,null,null,4,5]
輸出:[1,2,3,null,null,4,5]
分析問題
我們都知道對於不同的二叉樹進行先序、中序、後序或者層序遍歷得到的遍歷結果有可能是相同的,即如果知道了遍歷序列,我們不能確定唯一的一顆二叉樹,而題目要求的序列化和反序列化是一對可逆操作,即對一棵樹進行序列化後,我們還能通過序列化後的結果反序列化還原成原來的那棵樹。所以我們需要對二叉樹的遍歷過程改造一下,這裡以層序遍歷為例。在遍歷的過程中,為了完整的表示二叉樹,考慮將葉節點下的 null 也記錄。下面我們來看一下具體的實現。
序列化
我們可以藉助佇列來實現二叉樹的層序遍歷,在層序遍歷的過程中,我們把越過葉子節點的null也加入序列化的結果中。具體演算法流程如下所示:
- 如果給定的二叉樹為空,直接返回"[]"
- 初始化一個佇列queue,並把根節點加入。
- 對二叉樹進行層序遍歷。當佇列為空時跳出。
- 節點出隊,記為node。
- 如果node不為空,將node.val加入結果列表中,並且將node的左、右子節點入隊。如果node為空,將“null”加入結果列表中。
- 拼接結果列表,用
','
隔開,首尾新增中括號;並將其返回。
反序列化
利用佇列按層構建二叉樹。具體演算法流程如下所示:
- 如果data為空,直接返回null。
- 初始化列表vals(去掉首尾括號,再用逗號隔開),指標 i = 1 ,將根節點 root (值為 vals[0] )入隊;
- 按層構建二叉樹,當佇列為空時跳出;
- 節點出隊,記為node。
- 構建 node 的左子節點,node.left 的值為 vals[i] ,並將 node.left 入隊;然後執行i=i+1。
- 構建 node 的右子節點,node.right 的值為 vals[i] ,並將 node.right 入隊;然後執行i=i+1。
- 返回根節點 root 即可。
下面我們來看一下程式碼的實現。
class Codec:
def serialize(self, root):
#如果二叉樹為空,直接返回"[]"
if not root:
return "[]"
#初始化一個佇列
queue = collections.deque()
#將根節點加入佇列中
queue.append(root)
#結果列表
res = []
#記錄null的個數,遇到非空節點就將之前的null節點加入到結果列表中
null_count=0
while queue:
node = queue.popleft()
if node:
#遇到非空節點就將之前的null節點加入到結果列表中
if null_count != 0:
res.extend(["null"] * null_count)
null_count=0
res.append(str(node.val))
#node的左、右子節點入隊
queue.append(node.left)
queue.append(node.right)
else:
#記錄null節點的個數
null_count=null_count+1
return '[' + ','.join(res) + ']'
def deserialize(self, data):
#如果data為"[]",代表二叉樹是空,直接返回
if data == "[]":
return
#初始化
vals = data[1:-1].split(',')
i=1
#初始化根節點,並將其入隊
root = TreeNode(int(vals[0]))
queue = collections.deque()
queue.append(root)
while queue:
if i>=len(vals):
break
node = queue.popleft()
#新增左子節點
if vals[i] != "null":
node.left = TreeNode(int(vals[i]))
queue.append(node.left)
i += 1
if i>=len(vals):
break
#新增右子節點
if vals[i] != "null":
node.right = TreeNode(int(vals[i]))
queue.append(node.right)
i += 1
return root