二叉树的序列化和反序列化(括号表示法)

一. 数的括号表示法

1、树的线性表示

    树型结构和线性结构的主要区别在于树型结构具有分支性和层次性。使用树的遍历操作,可以将树中的结点按照规定的顺序排成一个线性序列;然而仅凭借树的某种遍历序列有时无法唯一地确定一棵树,但只要在遍历序列的基础上增加一些附加信息便可以唯一地确定一棵树,从而得到树的线性表示。树的线性表示便于树的输入、输出,同时在存储时也比较节省空间。

2、树的括号表示规则

(1)若树T为空树,则其括号表示为空

(2)若树T只包含一个结点,则其括号表示即为该结点本身

(3)若树T由根结点A和它的m棵子树T1,T2,...,Tm构成,则其括号表示为:A(T1的括号表示,T2的括号表示,... ,Tm的括号表示)

其中,子树的括号表示同样应该遵循以上规则

上图中树的括号表示为 A(B,C(F,G,H),D,E(I,J))

实现方法如下:

(1)从左到右扫描树的括号表示;

(2)每当遇到左括号时,其前一个结点进栈,并读入下一个符号;

(3)每当遇到右括号时,栈顶元素出栈。说明以栈顶元素为根的树(子树)构造完毕,此时若栈为空,算法结束,否则读入下一个符号

(4)每当遇到结点时,则它一定为栈顶元素的子女,将其挂到栈顶元素的某子女位置上,并读入下一个符号;

(5)每当遇到“,”,则略过该符号,并读入下一个符号。

通过一个例子说明具体实现代码如下:

设一棵完全二叉树为1(2(4(8,9),5(10,11)),3(6(,12),7)) ,图形表示为

二、括号表达式序列化为树形结构

TreeNode* prase(string& data)
{
	TreeNode* root = nullptr;
	char ch = data[0];
	bool isLeft = false;
	TreeNode* lastNode = nullptr;
	stack<TreeNode*> nodeStack;
	int curIn = 0;

	while (ch != '\0')
	{
		switch(ch) {

		case '(' :
			isLeft = true;
			nodeStack.push(lastNode);
			break;
		case ',' :
			isLeft = false;
			break;
		case ')' :
			isLeft = false;
			nodeStack.pop();
			break;
		default:
			lastNode = new TreeNode(ch - '0');
			if (root == nullptr)
			{
				root = lastNode;
			} else {
				TreeNode* parentNode = nodeStack.top();
				if (isLeft)
				{
					parentNode->left = lastNode;
				} else {
					parentNode->right = lastNode;
				}
			}
			break;

		}
		curIn++;
		if (curIn == data.length())
		{
			break;
		}
		ch = data[curIn];
	}

	return root;
}

三、 树形结构转为括号表达式

void normalizeTree(TreeNode* root, string& str)
{
	if (root == nullptr)
	{
		return;
	}
	
	str += to_string(long long(root->val));
	if (root->left != nullptr || root->right != nullptr)
	{
		str += "(";
		normalizeTree(root->left, str);
		str += ",";
		normalizeTree(root->right, str);
		str += ")";
	}
}

四、先序遍历输出二叉树

void preOrder(TreeNode* root)
{
	if (root == nullptr)
	{
		return;
	}

	cout << root->val;
	preOrder(root->left);
	preOrder(root->right);

}

五、完整程序

#include <iostream>
#include <string>
#include <string.h>
#include <vector>
#include <algorithm>
#include <iostream>
#include <set>
#include <algorithm>
#include <sstream>
#include <queue>
#include <iomanip>
#include <stack>

using namespace std;
struct TreeNode{
	int val;
	TreeNode* left;
	TreeNode* right;
	TreeNode(int v) : val(v), left(nullptr), right(nullptr)
	{

	}
};

void preOrder(TreeNode* root)
{
	if (root == nullptr)
	{
		return;
	}

	cout << root->val;
	preOrder(root->left);
	preOrder(root->right);

}

TreeNode* prase(string& data)
{
	TreeNode* root = nullptr;
	char ch = data[0];
	bool isLeft = false;
	TreeNode* lastNode = nullptr;
	stack<TreeNode*> nodeStack;
	int curIn = 0;

	while (ch != '\0')
	{
		switch(ch) {

		case '(' :
			isLeft = true;
			nodeStack.push(lastNode);
			break;
		case ',' :
			isLeft = false;
			break;
		case ')' :
			isLeft = false;
			nodeStack.pop();
			break;
		default:
			lastNode = new TreeNode(ch - '0');
			if (root == nullptr)
			{
				root = lastNode;
			} else {
				TreeNode* parentNode = nodeStack.top();
				if (isLeft)
				{
					parentNode->left = lastNode;
				} else {
					parentNode->right = lastNode;
				}
			}
			break;

		}
		curIn++;
		if (curIn == data.length())
		{
			break;
		}
		ch = data[curIn];
	}

	return root;
}


void normalizeTree(TreeNode* root, string& str)
{
	if (root == nullptr)
	{
		return;
	}
	
	str += to_string(long long(root->val));
	if (root->left != nullptr || root->right != nullptr)
	{
		str += "(";
		normalizeTree(root->left, str);
		str += ",";
		normalizeTree(root->right, str);
		str += ")";
	}
}


int main()
{
	string data = "1(2(,5),3)";
	TreeNode* rootNode = prase(data);
	string str = "";

	normalizeTree(rootNode, str);

	preOrder(rootNode);

	return 0;
}

参考:

[1] https://blog.csdn.net/baiziyuandyufei/article/details/43021011

[2] https://blog.csdn.net/csjapan/article/details/79518061

[3] https://www.jianshu.com/p/a47d88f962e0

  • 7
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值