今天练习算法,在leetcode上做了一道练习,照着上面的分析写了下面的代码,编译执行也都没有问题,在这里写写。
这里采用二叉树的先序遍历方式作为序列化和反序列化的主要思路,对空的子树用'#'进行记录。
在序列化的时候,使用递归进行先序遍历,递归执行到空节点,则保存'#'并返回;否则记录当前节点的值,并继续对其左右节点进行遍历。
同样,在反序列化的时候,当前读到的值作为新子树的根节点root,下一个读到的节点则为root节点的左子树root->left,并将当前索引值的引用传入下一步的递归,直到读到'#'递归层层返回;因为递归调用传入了当前值的引用,所以递归返回到root时,下一个读到的值将会用来初始化root的右子树root->right。
1 #include <cstdio> 2 #include <iostream> 3 #include <fstream> 4 #include <vector> 5 #include <cstring> 6 #include <vld.h> 7 8 using namespace std; 9 10 struct TreeNode 11 { 12 int i_val; 13 TreeNode *p_left; 14 TreeNode *p_right; 15 TreeNode() : i_val(0), p_left(0), p_right(0) {} 16 TreeNode(int val) : i_val(val), p_left(0), p_right(0) {} 17 TreeNode(const TreeNode &treeNode) : i_val(treeNode.i_val), p_left(treeNode.p_left), p_right(treeNode.p_right) {} 18 TreeNode &operator=(const TreeNode &treeNode) 19 { 20 if(this != &treeNode) 21 { 22 this->i_val = treeNode.i_val; 23 this->p_left = treeNode.p_left; 24 this->p_right = treeNode.p_right; 25 } 26 return *this; 27 } 28 }; 29 30 // 读到的字符是否是分隔符 31 inline bool isToken(char c, string &token) 32 { 33 for(string::iterator it = token.begin(); it != token.end(); ++it) 34 { 35 if(c == (*it)) 36 { 37 return true; 38 } 39 } 40 return false; 41 } 42 43 // 读到的内容是否是数字 44 inline bool isNumber(string &str) 45 { 46 if(str.size() == 0) 47 { 48 return false; 49 } 50 for(int i = 0; i < str.size(); ++i) 51 { 52 if(str[i] < '0' || str[i] > '9') 53 { 54 return false; 55 } 56 } 57 return true; 58 } 59 60 // 字符串转数字 61 int str2int(string &str) 62 { 63 int ret = 0; 64 for(int i = 0; i < str.size(); ++i) 65 { 66 ret = ret * 10 + (str[i] - '0'); 67 } 68 return ret; 69 } 70 71 // 从文件中读序列化后的内容 72 // 这里读到的内容是 73 // 30 10 50 # # # 20 45 # # 35 # # 74 vector<string> readFile(ifstream &in, string &token) 75 { 76 if(!in.is_open()) 77 { 78 cout << "Error during opening the file." << endl; 79 exit(1); 80 } 81 char c; 82 string word; 83 vector<string> vec_Str; 84 while(in.get(c)) 85 { 86 if(!isToken(c, token)) 87 { 88 word.push_back(c); 89 continue; 90 } 91 92 if(word.length() > 0) 93 { 94 vec_Str.push_back(string(word.begin(), word.end())); 95 word.clear(); 96 } 97 } 98 if(word.length() > 0) 99 { 100 vec_Str.push_back(string(word.begin(), word.end())); 101 } 102 103 return vec_Str; 104 } 105 106 // 反序列化二叉树 107 TreeNode *DeserializeTree(int &cur, vector<string> &vec_SerialTree) 108 { 109 if(cur < 0 || cur >= vec_SerialTree.size() || vec_SerialTree.size() == 0 || !isNumber(vec_SerialTree[cur])) 110 { 111 return 0; 112 } 113 TreeNode *p_Node = new TreeNode(str2int(vec_SerialTree[cur])); 114 cur = cur + 1; 115 p_Node->p_left = DeserializeTree(cur, vec_SerialTree); 116 cur = cur + 1; 117 p_Node->p_right = DeserializeTree(cur, vec_SerialTree); 118 119 return p_Node; 120 } 121 122 // 序列化二叉树 123 void SerializeTree(TreeNode *p_Root, ostream &out) 124 { 125 if(!p_Root) 126 { 127 out << "# "; 128 } 129 else 130 { 131 out << p_Root->i_val << " "; 132 SerializeTree(p_Root->p_left, out); 133 SerializeTree(p_Root->p_right, out); 134 } 135 } 136 137 // 释放资源 138 void DestroyTree(TreeNode **p_Root) 139 { 140 if(!p_Root || !(*p_Root)) 141 { 142 return; 143 } 144 DestroyTree(&((*p_Root)->p_left)); 145 DestroyTree(&((*p_Root)->p_right)); 146 delete *p_Root; 147 p_Root = 0; 148 } 149 150 int main() 151 { 152 string token(" "); 153 ifstream in("D:/Lab/clab/file/1.txt"); 154 ofstream out("D:/Lab/clab/file/2.txt"); 155 156 vector<string> vec_SerialTree = readFile(in, token); 157 158 int cur = 0; 159 TreeNode *p_Root = DeserializeTree(cur, vec_SerialTree); 160 161 if(out) 162 { 163 SerializeTree(p_Root, out); 164 } 165 166 DestroyTree(&p_Root); 167 168 return 0; 169 }