題目描述:
請實現兩個函數,分別用來序列化和反序列化二叉樹。
解題思路:
序列化是指將結構化的對象轉化為字節流以便在網絡上傳輸或寫到磁盤進行永久存儲的過程。反序列化是指將字節流轉回結構化的對象的過程,是序列化的逆過程。
受第4題:重建二叉樹的啟發,我們知道從前序遍歷和中序遍歷序列中可以構造出一棵二叉樹,因此將一棵二叉樹序列化為一個前序遍歷序列和一個中序遍歷序列,然后在反序列化時用第四題的思路重建二叉樹。
這種思路是可行的,但是存在兩個缺點:一是該方法要求二叉樹中不能有重復的結點(比如我們通過前序知道根是1,若有重復的結點無法在中序序列中定位根的位置);二是只有當兩個序列中所有的數據都讀出后才能開始反序列化,如果兩個遍歷序列是從一個流中讀出來的,那么可能需要等待較長的時間。
因此,這里我們采用另外一種方法,即只根據前序遍歷的順序來進行序列化,前序遍歷是從根結點開始,在遍歷二叉樹碰到null指針時,就將其序列化為一個特殊字符,比如$
,另外,結點的數值之間用一個特殊字符(比如,
)進行分隔。比如對於以下的樹,序列化為字符串:"1,2,4,$,$,$,3,5,$,$,6,$,$"
。

然后我們可以以"1,2,4,$,$,$,3,5,$,$,6,$,$"
為例來分析反序列化的過程,第一個讀出1,這是根結點的值,然后讀出2,這是根結點的左孩子,同樣接下來的4是值為2的結點的左孩子結點;接下來讀出兩個“\(”,說明值為4的結點左右孩子都是null,這是一個葉結點。然后回到值為2的結點,重建它的右子樹,由於下一個字符是“\)”,說明值為2的結點的右孩子結點為null,這個結點的左右子樹都重建完畢,接下來再次回溯就到了根結點,所以,左子樹重構完畢。
由於下一個數字是3,所以右子樹的根結點值為3,左結點時一個值為5的葉結點(因為接下來的三個字符是5,$,$
),同理右結點時一個值為6的結點。至此,重構完畢,反序列化完成。
序列化比較簡單,就是一個前序遍歷的過程,而反序列化也不難發現,實際就是一個遞歸解決每個子樹的問題,詳見以下代碼實現。
編程實現(Java):
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
public class Solution {
String Serialize(TreeNode root){
if(root==null)
return "#,";
String res="";
res+=root.val+","; //前序遍歷,根左右
res+=Serialize(root.left);
res+=Serialize(root.right);
return res;
}
//反序列化
int start=-1;
TreeNode Deserialize(String str){
if(str==null || str.length()==0)
return null;
String[] strArr=str.split(",");
return Deserialize(strArr);
}
TreeNode Deserialize(String[] strArr){
start++;
if(start>=strArr.length || strArr[start].equals("#"))
return null;
TreeNode cur=new TreeNode(Integer.valueOf(strArr[start]));
cur.left=Deserialize(strArr);
cur.right=Deserialize(strArr);
return cur;
}
}