当我们需要在另一台计算机中重构一棵二叉树,我们便需要对序列化的二叉树反序列化。
举个栗子!
我们有这样的二叉树序列:A(B(D),C(E,F))
我们人类用肉眼便可以一下子看出这棵二叉树的结构
如图所示,很简单吧!
可是计算机处理广义表没有人脑那么智能o(╥﹏╥)o,我们必须另寻他法!
看到广义表的结构(完全包含关系),便可以想到一个基本数据结构:栈!
要解决这个比较复杂的问题,我们由浅处着手。
1.假如这棵树的广义表序列只有一个结点A,我们如何去做?
当然这很简单,我们只需要创建一个结点A,并将它作为root便可以了。
2.加一点点难度呢?我们需要转换一个广义表序列为A( , B)的树呢?
现在想象你自己是一台计算机!你只会从左向右慢慢扫描字符!
①当我们扫描到A字符,我们可以先创建一个A节点。
②当我们扫描到'(',我们知道A节点存在子树,我们想要构建A的子树节点,所以我们可以先将A压入栈中。
③当我们扫描到‘,’,我们知道应当处理的下个节点是A节点的右子树,我们设置一个标记(用一个flag变量设置)。
④当我们扫描到B字符,我们创建B节点,并且设置栈顶元素A节点的右子树为B。
⑤当我们扫描到‘)’,标志着我们已经处理完成了栈顶节点A的左右子树,所以我们将A弹栈,完成本次反序列化操作。
由这样一个简单的例子,我们可以抽象出处理的法则!
一、遇到关键字:生成新节点,并且处理与上一个节点的关系。
二、遇到左括号:最新节点入栈。
三、遇到逗号:设置下一个处理的节点为栈顶节点的右子树(作标记)。
四、遇到右括号:弹栈。
大概就是这样的一个方法了,下面给出一种实现代码,代码使用了状态机的原理,仅供参考!
Node *deserialize(char *buff, int n) {
Node **s = new Node*[MAX_NODE];
//用数组模拟一个栈,指向节点的指针数组
int top = -1, flag = 0, scode = 0;
//flag为标记数:0为左子树,1为右子树
//scode为状态码
Node *p = NULL;//p永远指向最后一个生成的节点
Node *root = NULL;
for(int i = 0; buff[i] ; i++){//状态机原理
switch(scode){
//0状态码:根据当前字符任务分发:
/*关键字:跳转到1状态码
左括号:跳转到2状态码
逗号 :跳转到3状态码
右括号:跳转到4状态码
*/
case 0:{
if(buff[i]>= '0'&&buff[i] <= '9') scode = 1;
else if(buff[i] == '(') scode = 2;
else if(buff[i] == ',') scode = 3;
else scode = 4;
i -= 1;
}break;
case 1:{//生成一个新节点
int num = 0;
while(buff[i]>= '0'&&buff[i] <= '9'){
num = num * 10 + (buff[i] - '0');
i++;
}
p = getNewNode(num);
if(top>=0 && flag == 0) s[top]->lchild = p;
if(top>=0 && flag == 1) s[top]->rchild = p;
i--;
scode = 0;
}break;
case 2:{//节点入栈
s[++top] = p;
flag = 0;
scode = 0;
}break;
case 3:{//设置下一个处理的是右子树
flag = 1;
scode = 0;
}break;
case 4:{//弹栈
root = s[top];
top -= 1;
scode = 0;
}break;
}
}
return root;
}
完整测试代码:
#include <iostream>
#include <cstdio>
#include <time.h>
#include <string.h>
#define MAX_NODE 10
#define KEY(n) (n? n->key:-1)
using namespace std;
typedef struct Node {
int key;
Node *lchild, *rchild;
} Node;
Node *getNewNode(int key) {
Node *p = new Node;
p->key = key;
p->lchild = p->rchild = NULL;
return p;
}
void clear(Node *root) {
if (root == NULL) return;
clear(root->lchild);
clear(root->rchild);
delete root;
}
Node *insert(Node *root, int key) {
if (root == NULL) return getNewNode(key);
if (rand() % 2) root->lchild = insert(root->lchild, key);
else root->rchild = insert(root->rchild, key);
return root;
}
Node *getRandomBinaryTree(int n) {
Node *root = NULL;
for (int i = 0; i < n; i++) {
root = insert(root, rand() % 100);
}
return root;
}
char buff[1000];
int len = 0;
void __serialize(Node *root) {
if (root == NULL) return;
len += snprintf(buff + len, 100, "%d", root->key); //向字符数组中输出信息
if (root->lchild == NULL && root->rchild == NULL) return;
len += snprintf(buff + len, 100, "(");
__serialize(root->lchild);
if (root->rchild) {
len += snprintf(buff + len, 100, ",");
__serialize(root->rchild);
}
len += snprintf(buff + len, 100, ")");
return;
}
void serialize(Node *root) {
memset(buff, 0, sizeof(buff)); //初始化buff
len = 0;
__serialize(root);
return;
}
void print(Node *node) {
printf("%d(%d,%d)\n", KEY(node),
KEY(node->lchild),
KEY(node->rchild));
return;
}
void output(Node *root) {
if (root == NULL) return;
print(root);
output(root->lchild);
output(root->rchild);
return;
}
Node *deserialize(char *buff, int n) {
Node **s = new Node*[MAX_NODE];
//用数组模拟一个栈,指向节点的指针数组
int top = -1, flag = 0, scode = 0;
//flag为标记数:0为左子树,1为右子树
//scode为状态码
Node *p = NULL;//p永远指向最后一个生成的节点
Node *root = NULL;
for(int i = 0; buff[i] ; i++){//状态机原理
switch(scode){
//0状态码:根据当前字符任务分发:
/*关键字:跳转到1状态码
左括号:跳转到2状态码
逗号 :跳转到3状态码
右括号:跳转到4状态码
*/
case 0:{
if(buff[i]>= '0'&&buff[i] <= '9') scode = 1;
else if(buff[i] == '(') scode = 2;
else if(buff[i] == ',') scode = 3;
else scode = 4;
i -= 1;
}break;
case 1:{//生成一个新节点
int num = 0;
while(buff[i]>= '0'&&buff[i] <= '9'){
num = num * 10 + (buff[i] - '0');
i++;
}
p = getNewNode(num);
if(top>=0 && flag == 0) s[top]->lchild = p;
if(top>=0 && flag == 1) s[top]->rchild = p;
i--;
scode = 0;
}break;
case 2:{//节点入栈
s[++top] = p;
flag = 0;
scode = 0;
}break;
case 3:{//设置下一个处理的是右子树
flag = 1;
scode = 0;
}break;
case 4:{//弹栈
root = s[top];
top -= 1;
scode = 0;
}break;
}
}
return root;
}
int main() {
srand(time(0));
Node *root = getRandomBinaryTree(MAX_NODE);
serialize(root);//调用序列化
output(root);
printf("Buff[]:%s\n", buff);
Node *new_root = deserialize(buff, len); //反序列化
output(new_root);
return 0;
}
感谢观看!*★,°*:.☆( ̄▽ ̄)/$:*.°★* 。