二叉树的反序列化
经过艰苦卓绝的努力,实现了二叉树的反序列化,
二叉树需要反序列化以如下格式表示的二叉树
(hello(world )(soccer )) //hello代表父节点的值,world和soccer代表子节点的值,每个节点要么没有子节点,要么同时存在左右节点,比如右节点为空的表示为(hello(world )( ))。
使用boost.spirit实现
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
struct BinTree;
typedef boost::variant<
std::string,
boost::recursive_wrapper<BinTree>
>BinTreeNode;
struct BinTree
{
std::string data;
BinTreeNode left;
BinTreeNode right;
};
const int tabsize = 4;
void printtab(int tabstop)
{
for (int i = 0; i < tabstop; ++i)
{
std::cout<<" ";
}
}
struct BinTreePrinter;
struct BinTreeNodePrinter: public boost::static_visitor<>
{
BinTreeNodePrinter(int tabstop = 0):tabstop_(tabstop){}
void operator()(const std::string& s)const
{
printtab(tabstop_);std::cout<<s<<std::endl;
}
void operator()(const BinTree& m_xml)const;
private:
int tabstop_;
};
struct BinTreePrinter
{
BinTreePrinter(int tabstop = 0):tabstop_(tabstop){}
void operator()(const BinTree & m_xml)const
{
printtab(tabstop_);std::cout<<"("<<std::endl;
printtab(tabstop_);std::cout<<m_xml.data<<std::endl;
boost::apply_visitor(BinTreeNodePrinter(tabstop_+tabsize),m_xml.left);
boost::apply_visitor(BinTreeNodePrinter(tabstop_+tabsize),m_xml.right);
printtab(tabstop_);std::cout<<")"<<std::endl;
}
private:
int tabstop_;
};
void BinTreeNodePrinter::operator()(const BinTree& m_xml)const
{
BinTreePrinter m(tabstop_);
m(m_xml);
}
BOOST_FUSION_ADAPT_STRUCT
(BinTree,
(std::string,data)
(BinTreeNode,left)
(BinTreeNode,right)
)
template <typename Iterator>
class Grammar: public qi::grammar<Iterator, BinTree(),ascii::space_type>
{
public:
Grammar():Grammar::base_type(xml){
using ascii::char_;
using ascii::string;
using qi::lit;
using namespace qi::labels;
using qi::lexeme;
start_tag = '(' ;
end_tag = ')';
node %= xml| text;
text %= lexeme[*(char_ - '('-')')] ;
xml %= start_tag
>> text>>node>>node
>> end_tag;
}
private:
qi::rule<Iterator, BinTree(),ascii::space_type> xml;
qi::rule<Iterator, void(),ascii::space_type> start_tag;
qi::rule<Iterator, void(),ascii::space_type> end_tag;
qi::rule<Iterator, std::string(),ascii::space_type> text;
qi::rule<Iterator, BinTreeNode(),ascii::space_type> node;
};
int main(int argc, char** argv)
{
char const* filename;
if (argc > 1)
{
filename = argv[1];
}
else
{
std::cerr << "Error: No input file provided." << std::endl;
return 1;
}
std::ifstream in(filename, std::ios_base::in);
if (!in)
{
std::cerr << "Error: Could not open input file: "
<< filename << std::endl;
return 1;
}
std::string storage; // We will read the contents here.
in.unsetf(std::ios::skipws); // No white space skipping!
std::copy(
std::istream_iterator<char>(in),
std::istream_iterator<char>(),
std::back_inserter(storage));
Grammar<std::string::const_iterator> grammar;
BinTree ast;
std::string::const_iterator iter = storage.begin();
std::string::const_iterator end = storage.end();
bool r = qi::phrase_parse(iter, end, grammar , ascii::space, ast);
if (r && iter == end)
{
std::cout << "-------------------------\n";
std::cout << "parsing succeeded\n";
std::cout << "-------------------------\n";
BinTreePrinter printer;
printer(ast);
return 0;
}
else
{
std::string context(iter, (end-iter)>30?iter+30:end);
std::cout << "-------------------------\n";
std::cout << "parsing failed\n";
std::cout << "stopped at: \": " << context << "...\"\n";
std::cout << "-------------------------\n";
return 1;
}
}
Posted 2013-07-10