描述
設計一個算法,并編寫代碼來序列化和反序列化二叉樹。將樹寫入一個文件被稱為“序列化”,讀取文件后重建同樣的二叉樹被稱為“反序列化”。如何反序列化或序列化二叉樹是沒有限制的,你只需要確保可以將二叉樹序列化為一個字符串, 并且可以將字符串反序列化為原來的樹結構。
注意事項
There is no limit of how you deserialize or serialize a binary tree,
LintCode will take your output of serialize as the input of deserialize, it won't check the result of serialize.
樣例
給出一個測試數據樣例, 二叉樹{3,9,20,#,#,15,7},表示如下的樹結構:
3
/ \
9 20
/ \
15 7
我們的數據是進行BFS遍歷得到的。當你測試結果wrong answer時,你可以作為輸入調試你的代碼。你可以采用其他的方法進行序列化和反序列化。
關鍵點
- 要知道序列化是什么
http://www.lxweimin.com/writer#/notebooks/15589466/notes/16028033/preview- 無論是序列化還是反序列化都需要用queue來控制結點的執行順序,當然queue的實現要根據題目需求選擇是用LinkedList()方法還是ArrayList方法,本題算法中用到大量讀取操作,若用LinkedList來實現queue不方便,本題用了ArrayList來實現queue
代碼
/**
* Definition of TreeNode:
* public class TreeNode {
* public int val;
* public TreeNode left, right;
* public TreeNode(int val) {
* this.val = val;
* this.left = this.right = null;
* }
* }
*/
class Solution {
// 加public表示全局類,該類可以import到任何類內
// 不加public默認為保留類,只能被同一個包內的其他類引用
/**
* This method will be invoked first, you should design your own algorithm
* to serialize a binary tree which denote by a root node to a string which
* can be easily deserialized by your own "deserialize" method later.
*/
public String serialize(TreeNode root) {
if (root == null) {
return "{}";
}
/* 利用for循環將樹中結點全部添加到隊列里面,利用隊列來控制序列化順序
* queue不是一個隊列,是一個數組只是名字是queue
*/
ArrayList<TreeNode> queue = new ArrayList<TreeNode>();
queue.add(root);
for (int i = 0; i < queue.size(); i++) {
// queue是動態數組用get()方法來得到下標對應的數值
TreeNode node = queue.get(i);
// 空結點跳過不執行葉子結點添加的操作
if (node == null) {
continue;
}
// 無需理會葉子結點是不是空,把當前非空結點的葉子結點添加到了隊列中
queue.add(node.left);
queue.add(node.right);
}
// 去掉隊列結尾的空結點
while (queue.get(queue.size() - 1) == null) {
queue.remove(queue.size() - 1);
}
// 根據隊列往動態數組里添加相應的值
// StringBuilder對象是動態對象,允許擴充它所封裝的字符串中字符的數量
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append(queue.get(0).val);
// 在for循環前已經將初值加入sb中,所以 i 初值應設為1
for (int i = 1; i < queue.size(); i++) {
if (queue.get(i) == null) {
sb.append(",#");
}
else {
sb.append(",");
sb.append(queue.get(i).val);
}
}
sb.append("}");
return sb.toString();
}
/**
* This method will be invoked second, the argument data is what exactly
* you serialized at method "serialize", that means the data is not given by
* system, it's given by your own serialize method. So the format of data is
* designed by yourself, and deserialize it here as you serialize it in
* "serialize" method.
*/
public TreeNode deserialize(String data) {
// 字符用equals,數值用==
if (data.equals("{}")) {
return null;
}
// 此處需注意用點截取data的區間
// 字符串長度用length()
String[] vals = data.substring(1, data.length() - 1).split(",");
ArrayList<TreeNode> queue = new ArrayList<TreeNode>();
TreeNode root = new TreeNode(Integer.parseInt(vals[0]));
/* 新建一節點,節點值為vals[0]
* Integer.parseInt()將字符串轉化為整型
*/
queue.add(root);
boolean isLeftChild = true;
// index是queue的索引
int index = 0;
// i 是vals的索引
for (int i = 1; i < vals.length; i++) {
// 數組長度用length
// 此處同樣要注意先判斷是不是空結點再討論結點的子結點
if (!vals[i].equals("#")) {
TreeNode node = new TreeNode(Integer.parseInt(vals[i]));
if (isLeftChild) {
// 注意此處index=0,i=1
queue.get(index).left = node;
}
else {
queue.get(index).right = node;
}
queue.add(node);
/* '#'所的代表的空指針不要加入queue,沒有任何意義,
* 此時for循環遍歷的是index,即node的父節點,
* for循環接下來還要遍歷node來確定node的子節點
* 此處不能忘記將node加入queue
*/
}
if (!isLeftChild) {
index++;
/* isLeftChild=false時說明此時index對應的結點的右兒子已經添加到隊列中了,
* 應將index往后移一位
*/
}
// i 每變化一次 isLeftChild 進行一次變化
isLeftChild = !isLeftChild;
}
return root;
}
}
錯誤
- 單引號里面放一個字符,雙引號里放多個字符
錯誤
錯誤代碼
正確代碼
需要先判斷node是否為空,若node都為空研究node左右子結點無意義