【剑指offer】29.序列化二叉树
总目录:
1.问题描述
请实现两个函数,分别用来序列化和反序列化二叉树,不对序列化之后的字符串进行约束,但要求能够根据序列化之后的字符串重新构造出一棵与原二叉树相同的树。
二叉树的序列化(Serialize)是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树等遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#)
二叉树的反序列化(Deserialize)是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
二叉树的反序列化(Deserialize)是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
例如,可以根据层序遍历的方案序列化,如下图:
层序序列化(即用函数Serialize转化)如上的二叉树转为"{1,2,3,#,#,6,7}",再能够调用反序列化(Deserialize)将"{1,2,3,#,#,6,7}"构造成如上的二叉树。
当然你也可以根据满二叉树结点位置的标号规律来序列化,还可以根据先序遍历和中序遍历的结果来序列化。不对序列化之后的字符串进行约束,所以欢迎各种奇思妙想。
数据范围:节点数 n≤100,树上每个节点的值满足 0≤val≤150
要求:序列化和反序列化都是空间复杂度 O(n),时间复杂度 O(n)
2.问题分析
1层序遍历,注意处理好空子节点,中间的工程代码真的很多。。。
3.代码实例
1层序遍历
1 /* 2 struct TreeNode { 3 int val; 4 struct TreeNode *left; 5 struct TreeNode *right; 6 TreeNode(int x) : 7 val(x), left(NULL), right(NULL) { 8 } 9 }; 10 */ 11 #include "math.h" 12 #include <memory.h> 13 using namespace std; 14 15 class Solution { 16 private: 17 const char cForSplit = ',', cForStart = '{', cForEnd = '}'; 18 const int minVal = 0, maxVal = 150, illegalNum = -1; 19 const char cForNA = '#';//not a number 20 const int maxNumWidth = 4;//0 <= num <= 150 21 char* numBuf; 22 23 public: 24 //将char队列转到char数组 25 char* queueToCharBuf(queue<char>& cQueue) { 26 queue<char> seriQ; 27 28 //遍历填充 29 //添加起始符 30 seriQ.push(cForStart); 31 while (!cQueue.empty()) { 32 //最后一个分割符不压入 33 if (cQueue.size() == 1 && cQueue.front() == cForSplit) { 34 break; 35 } 36 37 char c = cQueue.front(); 38 cQueue.pop(); 39 seriQ.push(c); 40 } 41 //添加结束符 42 seriQ.push(cForEnd); 43 44 //初始化 45 int cSize = seriQ.size(); 46 int bufSize = cSize + 1;//+1 for \0 47 char* buf = (char*)malloc(sizeof(char) * bufSize); 48 memset(buf, 0, sizeof(char) * bufSize); 49 50 //存入 51 int cIndex = 0; 52 while (!seriQ.empty()) { 53 buf[cIndex++] = seriQ.front(); 54 seriQ.pop(); 55 } 56 57 //不可释放buf的内存 58 //free(buf); 59 return buf; 60 } 61 62 //将数字存入char队列,自动添加分割符号 63 void addNumToQuque(queue<char>& cBuf, int num) { 64 //如果数值范围超限则设定指定符号 65 if (num < minVal || num > maxVal) { 66 cBuf.push(cForNA); 67 } else { 68 //准备临时内存,存储数字 69 numBuf = numBuf != NULL ? numBuf : (char*)malloc(sizeof(char) * maxNumWidth); 70 memset(numBuf, 0, sizeof(char)*maxNumWidth); 71 std::sprintf(numBuf, "%d", num); 72 73 //数字-》char数组 74 int cIndex = 0; 75 while (numBuf[cIndex] != '\0') { 76 cBuf.push(numBuf[cIndex++]); 77 } 78 79 //记得释放内存 80 if (numBuf != NULL) { 81 free(numBuf); 82 } 83 numBuf = NULL; 84 } 85 86 //添加分隔符 87 cBuf.push(cForSplit); 88 } 89 90 //层序迭代,将节点的值逐层存入队列中 91 void levelIterSerialize(TreeNode* root, queue<char>& cBuf) { 92 if (!root) { 93 return; 94 } 95 96 int nodeNumInLevel = 0;//指示某层的节点数量,2^(n-1) 97 queue<TreeNode*> nodeBuf; 98 nodeBuf.push(root); 99 100 //典型的层序迭代 101 while (!nodeBuf.empty()) { 102 nodeNumInLevel = nodeBuf.size(); 103 104 //逐个弹出本层节点并处理 105 for (int i = 0; i < nodeNumInLevel; i++) { 106 TreeNode* pNode = nodeBuf.front(); 107 nodeBuf.pop(); 108 109 //将本层节点入char队 110 addNumToQuque(cBuf, pNode == NULL ? illegalNum : pNode->val); 111 112 //空节点则不添加其下层节点 113 if (pNode == NULL) { 114 continue; 115 } 116 117 //添加下层节点 118 nodeBuf.push(pNode->left); 119 nodeBuf.push(pNode->right); 120 } 121 } 122 } 123 124 //////////////////////////////////////////////////////////////////////////////////////////// 125 //序列化入口 126 //////////////////////////////////////////////////////////////////////////////////////////// 127 char* Serialize(TreeNode* root) { 128 queue<char> cBuf; 129 130 //层序遍历 131 levelIterSerialize(root, cBuf); 132 133 //返回序列化字符串 134 return queueToCharBuf(cBuf); 135 } 136 137 //将char数组转为char队列 138 void charBufToQueue(char* str, queue<char>& cQueue) { 139 //清空队列 140 while (!cQueue.empty()) { 141 cQueue.pop(); 142 } 143 144 //逐char转存 145 char* pChar = str; 146 while (pChar) { 147 if ((*pChar) == '\0') { 148 return; 149 } 150 151 cQueue.push(*pChar); 152 pChar++; 153 } 154 } 155 156 //从char队列中弹出数字 157 bool popNumFromQueue(queue<char>& cQueue, int& outVal) { 158 //初始化 159 outVal = illegalNum; 160 if (cQueue.empty()) { 161 return false; 162 } 163 164 //排除调队列前端的无用字符 165 while (!cQueue.empty()) { 166 char tmp = cQueue.front(); 167 if ( tmp != cForStart && tmp != cForSplit && tmp != cForEnd) { 168 break; 169 } 170 171 //弹出 172 cQueue.pop(); 173 } 174 175 //逐char解析,将属于该数字的一段从队列中弹出 176 queue<char> tempQueue; 177 while (!cQueue.empty()) { 178 char c = cQueue.front(); 179 cQueue.pop(); 180 181 //若干可能的中断情况 182 //跳过起始符 183 if (c == cForStart) { 184 continue; 185 } 186 //遇到分割符和结束符则中止 187 if (c == cForSplit || c == cForEnd) { 188 break; 189 } 190 //发现占位符,立即返回非法数字 191 if (c == cForNA) { 192 outVal = illegalNum; 193 return true; 194 } 195 196 //存入临时队列 197 tempQueue.push(c); 198 } 199 200 //queue转入char数组 201 int charCount = tempQueue.size(); 202 if (charCount <= 0) { 203 return false; 204 } 205 int bufSize = charCount + 1; 206 char* cBuf = (char*)malloc(sizeof(char) * (bufSize)); 207 memset(cBuf, 0, sizeof(char) * (bufSize)); 208 int charIndex = 0; 209 while (!tempQueue.empty()) { 210 cBuf[charIndex++] = tempQueue.front(); 211 tempQueue.pop(); 212 } 213 214 //char数组转数字 215 outVal = std::atoi(cBuf); 216 free(cBuf); 217 218 return true; 219 } 220 221 //层序遍历,反序列化 222 TreeNode* levelIterDeserialize(queue<char>& cQueue) { 223 int curVal = illegalNum; 224 bool gotNum = false; 225 226 //是否存在根节点 227 gotNum = popNumFromQueue(cQueue, curVal); 228 if (!gotNum) { 229 return NULL; 230 } 231 232 //典型的层序遍历 233 int nodeNunInLevel = 0; 234 TreeNode* head = new TreeNode(curVal); 235 queue<TreeNode*> nodeQueue; 236 nodeQueue.push(head); 237 while (!nodeQueue.empty()) { 238 nodeNunInLevel = nodeQueue.size(); 239 for (int i = 0; i < nodeNunInLevel; i++) { 240 TreeNode* root = nodeQueue.front(); 241 nodeQueue.pop(); 242 243 //left 244 gotNum = popNumFromQueue(cQueue, curVal); 245 if (!gotNum) { 246 return head; 247 } 248 if (curVal != illegalNum) { 249 root->left = new TreeNode(curVal); 250 nodeQueue.push(root->left); 251 } 252 253 //right 254 gotNum = popNumFromQueue(cQueue, curVal); 255 if (!gotNum) { 256 return head; 257 } 258 if (curVal != illegalNum) { 259 root->right = new TreeNode(curVal); 260 nodeQueue.push(root->right); 261 } 262 } 263 } 264 265 return head; 266 } 267 268 //////////////////////////////////////////////////////////////////////////////////////////// 269 //反序列化入口 270 //////////////////////////////////////////////////////////////////////////////////////////// 271 TreeNode* Deserialize(char* str) { 272 if (!str) { 273 return NULL; 274 } 275 276 //将char*转为char队列,方便处理 277 queue<char> cQueue; 278 charBufToQueue(str, cQueue); 279 280 return levelIterDeserialize(cQueue); 281 } 282 };