使用队列层序遍历,序列化二叉树

                                           序列化二叉树

题目描述:

1.将二叉树以一定的规则(先序、中序、后续、层序)进行遍历,将节点数据保存到字符串中,每个节点数据保存到字符串中用"!“分割,空节点用”#"代替。

2.将得到的字符串按照一定的规则(先序、中序、后续、层序)构建二叉树。

题解
对于第一题,本文以层序遍历为例进行讲解:
层序遍历二叉树,首先考虑使用什么工具保存遍历的到的数据,层序遍历是从根节点开始,每层从左到右依次访问,直至遍历整个二叉树,其中最适合的便是队列,先进先出。
对于第一题的解题思路与代码,我详细的加到了代码段中,如下所示:

//这是定义二叉树的结构体,以及构造函数
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
char* Serialize(TreeNode *root) {   
	//定义结构体类型的队列,用来存储得到的二叉树节点数据
    queue<TreeNode*> q;
    //定义一个字符串,保存遍历的节点数据
    string s;
    //使用层序遍历得到字符串
	//由于节点为空需要返回#,因此需要考虑为空的情况
	//首先,根节点进队
	q.push(root);
	//循环的进队和出队操作,直到队列为空结束循环
	while (!q.empty()) {
		//将队头出队
		TreeNode *head = q.front();
		//删除队头的元素
		q.pop();
		//判断出队的是个空节点,还是有左右子节点,有左右子节点的话需要对左右子节点进队操作
		//为空的情况
		if (head == nullptr) {
			s.push_back('#');
			s.push_back('!');
			continue;
		}
		//不为空的情况,把存取的数据提出来
		s = s + to_string(head->val);
        s.push_back('!');
		//有左子树
		q.push(head->left);
		//有右子树
		q.push(head->right);
	}
	//函数是char类型,最后需要把string转换为char
	char *str = new char[s.length() + 1];
	strcpy(str, s.c_str());
	return str;
    }

对于第二个题目,本文仍然使用层序遍历,但不同于直接构造二叉树的是需要对字符串进行分割,按照第一个题目中的分割标记"!",将字符串中的数字取出转换为整数类型,然后才能给节点赋值数据。

TreeNode* Deserialize(char *str) {
    //拷贝一个串备用,别后面把值改没了
	string ss(str);
	//搞一个二叉树节点类型的队列,存储恢复出来的节点
	queue<TreeNode *>node;
	//重构二叉树要确定两个标志,#和!
	//先看一下字符串是否为空
	if (str == nullptr)return nullptr;
	//确定返回的字符串是不是有根节点,没有根节点同样为空
	if (str[0] == '#')return nullptr;
	//程序能到这里就说明返回的字符串不为空,可以构建二叉树
	//首先,构建二叉树的根节点,开始还在考虑如何依据结束符取值,没想到c++有可以用的函数
	//接用构造函数直接初始化
	//atoi(s.c_str())直接取出第一个!号之前的数组,省时省力。
	TreeNode *root = new TreeNode(atoi(ss.c_str()));
	//既然前面的已经赋值,可以舍取,得到除去第一个节点值的剩下值
	ss = ss.substr(ss.find_first_of('!') + 1);
	//根节点进队
	node.push(root);
	//只要字符串不为空,就循环处理吧,至于后面那个条件暂时没看明白
	while (!ss.empty() && !node.empty()) {
		TreeNode *temp = node.front();
		node.pop();
		//这里就不用判断字符串是不是空了,要是空的他也进不来
		//根节点没有左子树
		if (ss[0] == '#') {
			temp->left = nullptr;
			//里面放2是为了跳过结束标识符
			ss = ss.substr(2);
		}
		else {
			//把左子树进队
			temp->left = new TreeNode(atoi(ss.c_str()));
			node.push(temp->left);
			ss = ss.substr(ss.find_first_of('!') + 1);
		}
		//处理右子树的情况
		if (ss[0] == '#') {
			temp->right = nullptr;
			ss = ss.substr(2);
		}
		else {
			temp->right = new TreeNode(atoi(ss.c_str()));
			node.push(temp->right);
			ss = ss.substr(ss.find_first_of('!') + 1);
		}
	}
	return root;
    }

代码可以直接copy,在主函数中调用即可,主要是理解层序遍历的原理。目前我也在学习的路上探索,如果有理解错误的地方,希望看到的大佬能给本文指出,我一定抓紧改正。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是小峰呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值