【剑指offer】29.序列化二叉树

总目录:

算法之旅导航目录

 

1.问题描述 

请实现两个函数,分别用来序列化和反序列化二叉树,不对序列化之后的字符串进行约束,但要求能够根据序列化之后的字符串重新构造出一棵与原二叉树相同的树。
二叉树的序列化(Serialize)是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树等遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#)
二叉树的反序列化(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 };
View Code

 

posted @ 2022-11-14 16:07  啊原来是这样呀  阅读(23)  评论(0编辑  收藏  举报