力扣第 297 题「 二叉树的序列化与反序列化」
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Codec {
public:
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
}
};
// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));
总结结论:
-
如果你的序列化结果中不包含空指针的信息,且你只给出一种遍历顺序,那么你无法还原出唯一的一棵二叉树。
-
如果你的序列化结果中不包含空指针的信息,且你会给出两种遍历顺序,那么按照前文 东哥手把手带你刷二叉树(构造篇) 所说,分两种情况:
2.1. 如果你给出的是前序和中序,或者后序和中序,那么你可以还原出唯一的一棵二叉树。
2.2. 如果你给出前序和后序,那么除非你的整棵树中不包含值相同的节点,否则你无法还原出唯一的一棵二叉树。
-
如果你的序列化结果中包含空指针的信息,且你只给出一种遍历顺序,也要分两种情况:
3.1. 如果你给出的是前序或者后序,那么你可以还原出唯一的一棵二叉树。
3.2. 如果你给出的是中序,那么除非你的整棵树中不包含值相同的节点,否则你无法还原出唯一的一棵二叉树。
class Codec {
public:
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
if(root==NULL) return "#,";
string res = to_string(root->val)+",";
res += serialize(root->left);
res += serialize(root->right);
return res;
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
stringstream ss(data);
string item;
queue<string> q;
while (getline(ss, item, ','))
q.push(item);
return helper(q);
}
//辅助函数
TreeNode* helper(queue<string>& q)
{
string val = q.front();
q.pop();
if (val == "#")
return NULL;
TreeNode* head = new TreeNode(stoi(val));
head->left = helper(q);
head->right = helper(q);
return head;
}
};
stringstream的用法
一、概念
stringstream 是 C++ 标准库中的一个流类,可以用于将字符串当做流来处理。stringstream 可以对字符串进行输入输出、格式化、类型转换等操作,常用于字符串解析、格式化输出、类型转换等场景。
原文链接:stringstream用法总结_子木呀的博客-CSDN博客
C++ stringstream 类是一种十分有用的类,特别是当我们需要在程序中使用字符串和数字数据的时候。要想在程序中使用 stringstream 类,我们需要在源程序文件中包含头文件include<sstream>。stringstream 对象的使用方法与cout对象的使用方法基本相同。stringstream 类提供的函数,将数字化转化为字符串。
当我们需要按预定的格式将程序中的数据保存在一个string 中的时候,可以先创建一个stringstream 对象,并通过运算符 ”<<“ 将数据传递给 stringstream 对象。(这与通过”<<“ 使用cout 对象的方法相同。)接着,我们可以通过调用stringstream 类的函数str() 将对象所包含的内容赋给一个string对象。在一下的程序中,我们先将数据传递给一个stringstream 对象,然后通过该 stringstream 对象将数值赋给一个string 对象。
二、基本功能
功能一、预定的格式将程序中的数据保存在一个string中
// 如何使用 stringstream
// 对象生成格式化的 string
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
cout << "\n Welcome to the StringStream Demo program.\n";
// 构建一些将在string中出现的数据变量
// PI 精确到小数点后15位
double pi = 3.141592653589793;
float dollar = 1.00;
int dozen = 12;
string text;
// 我们希望tring 的格式如下:
// dozen适12,dollar是$1.00
// 精确到小数点后10为pi是3.141592653589793
// 生成stringstream 对象
stringstream ss;
// 现在像使用cout一样使用ss
ss << " A dozen is "<< dozen << ", a dollar is $ ";
ss.setf(ios::fixed);
ss.precision(2);
ss << dollar << " and \n the value of pi to 10 places is ";
ss.precision(10);
ss << pi << ".";
// 现在将ss中的内容赋给一个string对象
// 使用str()函数
text = ss.str();
cout << "\nHere is our formatted text string:\n" << text << endl;
// 再加入一些信息
ss << "\ There are 2 \"+\" in C++.";
text = ss.str();
cout<< "\nHere is the final string:\n" << text << endl;
return 0;
}
stringstream类常用的成员函数
ss.str(); 读取对象中的字符串内容
ss.clear(); 清除当前对象的状态
ss.setf(ios::fixed);
是 stringstream
类的一个成员函数,用于设置流格式标志,即指定流的输出格式。在这里,ios::fixed
是一个枚举值,表示输出浮点数时按照定点格式输出。
具体来说,当使用 ios::fixed
标志时,浮点数的输出格式将被固定,小数部分将保留指定的位数(默认是 6 位),即使小数部分为 0。这与默认的浮点数格式 ios::scientific
不同,后者将自动选择科学计数法输出浮点数,根据数值的大小自动确定精度。
在代码中,ss.setf(ios::fixed);
的作用是将 stringstream
对象 ss
的输出格式设置为定点格式,这样在输出浮点数时,小数点后的位数将保留指定的精度。这个设置通常与 setprecision()
函数一起使用,后者用于指定输出的小数点后的位数。
ss.precision(2);
是 stringstream
类的一个成员函数,用于设置浮点数输出的精度,即小数点后的位数。在这里,参数 2 表示输出浮点数时小数点后保留 2 位。
具体来说,当使用 ss.precision(2)
时,输出浮点数时,小数点后的位数将保留 2 位。例如,输出 3.14159265358979323846 时,将会输出 3.14。
功能二、实现类型转换
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
double rb;
int ri; // 存储结果
string s; // 要转化的字符串
stringstream ss;
s = "123.456789";
ss << s; // 类似 cout
ss >> rb; // 类似 cin
cout.precision(10);
cout << "string \""<< s << "\" to double object "
<< rb << endl;
s = "654321";
ss.clear(); //清空流
ss << s;
ss >> ri;
cout << "string \""<< s << "\" to int object "
<< ri << endl;
return 0;
}
三、重要功能
1.数字由空格或者都好分开
#include<iostream>
#include<sstream>
#include<vector>
using namespace std;
int main() {
stringstream ss;
vector<int> nums;
string input;
getline(cin, input);
ss << input;
int num;
while (ss >> num) { //读取的时候自动将string型转换成int型
nums.push_back(num);
}
for (auto a : nums) {
cout << a << endl;
}
return 0;
}
//因为stringstream默认输出由空格分开
下面是一个简单的示例,展示了如何使用 stringstream
类来进行字符串流的输入输出操作:
#include <iostream>
#include <sstream>
#include <string>
int main() {
std::string str = "Hello World";
std::stringstream ss;
ss << str; // 将字符串写入 stringstream 对象中
std::string str_out;
ss >> str_out; // 从 stringstream 对象中读取字符串
std::cout << str_out << std::endl; // 输出读取到的字符串
return 0;
}
在上面的代码中,我们首先创建了一个字符串 str
,然后创建了一个 stringstream
对象 ss
。将字符串 str
写入 ss
中,然后从 ss
中读取字符串到变量 str_out
中,并使用 cout
流输出 str_out
的值。(只读取了前面的一个字符串,如果加上while循环就会自动读取ss中的以空格分开的所有字符串)
输出结果为:
Hello
2.数字由逗号分开
#include<iostream>
#include<sstream>
#include<vector>
using namespace std;
int main() {
stringstream ss;
vector<int> nums;
string input;
getline(cin, input);
ss << input;
string num;
while (getline(ss, num, ',')) {
nums.push_back(stoi(num));
}
for (auto a : nums) {
cout << a << endl;
}
return 0;
}
stoi 用法链接:【最贴心】C++字符串转换(stoi;stol;stoul;stoll;stoull;stof;stod;stold)_来老铁干了这碗代码的博客-CSDN博客
getline用法
getline
是 C++ 标准库中用于从输入流中读取一行数据的函数。其基本语法如下:
istream& getline(istream& is, string& str, char delim);
其中,is
是输入流对象,str
是存储读取数据的字符串对象,delim
是行分隔符(默认为 \n
)。函数将从输入流对象 is
中读取一行数据,存储到字符串对象 str
中,直到遇到行分隔符为止(或者到达文件末尾)。最后,函数将返回输入流对象 is
的引用。
例如,下面的代码从标准输入流中读取一行数据,并将其存储到字符串变量 input
中:
string input;
getline(cin, input);
在这个例子中,cin
是标准输入流对象,input
是存储读取数据的字符串对象。函数 getline(cin, input)
从标准输入流对象 cin
中读取一行数据,存储到字符串变量 input
中。如果输入流对象 cin
已经到达文件末尾,函数将返回 cin
的引用,即 cin
的值为 false
。
getline
函数还有其他的用法,例如可以指定行分隔符为其他字符或字符串,并且可以从文件或其他输入流中读取数据。根据具体用法,函数的语法和参数可能会有所不同。
指定行分隔符:
默认情况下,getline
函数的行分隔符为换行符 \n
。如果需要指定其他的行分隔符,可以使用第三个参数 delim
。例如,下面的代码将从标准输入流中读取一行数据,以逗号为行分隔符:
string input;
getline(cin, input, ',');
在这个例子中,cin
是标准输入流对象,input
是存储读取数据的字符串对象,','
是指定的行分隔符。函数 getline(cin, input, ',')
从标准输入流对象 cin
中读取一行数据,以逗号为行分隔符,存储到字符串变量 input
中。
stringstream ss(data);
string item;
queue<string> q;
while (getline(ss, item, ','))
q.push(item);
这段代码将一个以逗号分隔的字符串 data
中的每个元素,逐个压入一个队列中。具体来说,它使用了 stringstream
和 getline
函数来实现字符串分割,以逗号为分隔符,将每个子字符串作为队列的元素。
具体来说,首先创建了一个 stringstream
对象 ss
,将待分割的字符串 data
作为参数传入。接着,定义一个字符串变量 item
,用于存储每个子字符串。然后,创建一个队列 q
,用于存储分割后的每个子字符串。在 while
循环中,使用 getline
函数逐行读取 ss
中的数据,以逗号作为分隔符,将每个子字符串存储到 item
变量中,然后将 item
插入到队列 q
的末尾。最终,当所有子字符串都被读取和插入到队列 q
后,队列中存储的就是分割后的每个子字符串了。
这段代码可以用于解析一些逗号分隔的数据格式,例如 CSV 文件或一些自定义的数据格式,例如上面提到的二叉树序列化格式。通过将输入的字符串分割成一个个子字符串,并逐个处理,可以更方便地对这些数据进行处理和解析。