剑指 Offer 37. 序列化二叉树
解题思路
序列化二叉树:
-
首先判断树是否为空,空则直接返回"[]".
-
借助辅助队列,层序遍历二叉树,首先将"["加入str,并将根节点入队.
-
队列空则结束:
1)获取队列首节点node,将首节点弹出.
2)判断node是否为空,空则直接将"null"加入字符串str,非空则将当前节点node的值val加入字符串,并将node的左右子树节点加入队列.
3)判断队列是否为空,非空将","加入str. -
跳出循环将"]"加入str.
-
最后返回str.
反序列化二叉树:
-
判断序列表data是否为空,空则直接返回NULL.
-
获取data出去前后[]的字符串(使用stringstream获取到数据sstr中).
-
将得到的sstr用",“做分割获取其中的字符,getline一个一个获取”,"分割的字符.
-
将获取的第一个字符转化为整形(atoi(str.c_str()))作为val构造二叉树的根节点TreeNode* root = new TreeNode(atoi(str.c_str()));
-
将新创建的root节点加入队列.
-
队列空则结束:
1)获取队列首节点cur,将首节点弹出.
2)从数据流sstr中获取下一个字符;判断字符是否为空,非空则构造一个树节点lef,将此节点作为cur的左节点cur->left = lef;将lef节点加入到队列.
4)从数据流sstr中获取下一个字符;判断字符是否为空,非空则构造一个树节rig,将此节点作为cur的右节点cur->right = rig;将rig节点加入到队列. -
返回根节点root.
class Codec {
public:
queue<TreeNode*> que;
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
//借助辅助队列层序遍历树种的节点
if(root == NULL)
return "[]";
string str;
str.append("[");
que.push(root);
while(!que.empty())
{
TreeNode *node = que.front(); //取出队列中的首节点
que.pop();
if(node != NULL)
{
str += to_string(node->val);
que.push(node->left);
que.push(node->right);
}
else
str.append("null");
if(!que.empty())
str.append(",");
}
str.append("]");
return str;
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
if(data == "[]")
return NULL;
//从序列表中取出[]获取中间的字符串
stringstream sstr(data.substr(1,data.size()-2)); //出去第一个[和最后一个]
//从获取的字符串中用,分割出单个字符
string str;
getline(sstr,str,','); //str中存放第一个,分割出的字符 1
TreeNode *root = new TreeNode(atoi(str.c_str())); //将str中的字符转换为整形构造根节点
//将根节点入队
que.push(root);
while(!que.empty())
{
TreeNode *cur = que.front();
que.pop();
getline(sstr,str,',');
if(str != "null")
{
TreeNode *lef = new TreeNode(atoi(str.c_str()));
cur->left = lef;
que.push(lef);
}
getline(sstr,str,',');
if(str != "null")
{
TreeNode *rig = new TreeNode(atoi(str.c_str()));
cur->right = rig;
que.push(rig);
}
}
return root;
}
};
用到的其他相关知识:
C++中stringstream的用法
C++引入了ostringstream、istringstream、stringstream这三个类,要使用他们创建对象就必须包含sstream头文件。
istringstream类用于执行C++风格的串流的输入操作。
ostringstream类用于执行C风格的串流的输出操作。
stringstream类同时可以支持C风格的串流的输入输出操作。
sstream库定义了三种类:istringstream、ostringstream和stringstream,分别用来进行流的输入、输出和输入输出操作。另外,每个类都有一个对应的宽字符集版本。简单起见,我主要以stringstream为中心,因为每个转换都要涉及到输入和输出操作。
注意,使用string对象来代替字符数组。这样可以避免缓冲区溢出的危险。而且,传入参数和目标对象的类型被自动推导出来,即使使用了不正确的格式化符也没有危险。
c++中getline的用法
c++中有2种getline函数,一种在头文件 中,是istream类的成员函数;另一种是在头文件 中,是普通函数。
(一) 在头文件 的getline函数
两种重载形式:
- istream& getline (char* s, streamsize n );//读取最多n个字符保存在s对应的数组中,即使大小不够n,
- istream& getline (char* s, streamsize n, char delim ); //读取最多n个字符保存在s对应的数组中,遇到delim,或者读完一行,或字数达到限制则终止
特别说明: 最多读取n个字符中结束字符算一位。
(二)在头文件中的getline函数
- istream& getline (istream& is, string& str, char delim);
istream& getline (istream&& is, string& str, char delim); - istream& getline (istream& is, string& str);
istream& getline (istream&& is, string& str);
说明:
is:表示一个输入流,例如 cin。
str:用来存储输入流中的信息
delim:自定义结束字符,默认是 '\n ’