二叉树的基本操作C++

本文用C++语言写了二叉树的基本操作,包括二叉树的四种遍历方式的递归和非递归写法,二叉查找树的插入,删除,构建,路径搜索,序列化和反序列化,是否镜像等操作,仅供参考。 

#include<iostream>
#include<stack>
#include<queue>
#include<vector>
#include<string>
using namespace std;
struct TreeNode
{
	TreeNode *left, *right;
	int val;
	TreeNode(int x) :val(x), left(NULL), right(NULL){}
};
//前序遍历的递归写法
void helper1(TreeNode *root, vector<int> &res)
{
	if (!root) return;
	res.push_back(root->val);
	helper1(root->left, res);
	helper1(root->right, res);
}
vector<int> preTraversalRecur(TreeNode *root)
{
	vector<int> res;
	helper1(root, res);
	return res;
}
//前序遍历的非递归写法
vector<int> preTraversalNonrecur(TreeNode *root)
{
	vector<int> res;
	if (!root) return res;
	stack<TreeNode *> s;
	TreeNode *p = root;
	while (!s.empty() || p != NULL)
	{
		while (p != NULL)
		{
			res.push_back(p->val);
			s.push(p);
			p = p->left;
		}
		if (!s.empty())
		{
			p = s.top();
			s.pop();
			p = p->right;
		}
	}
	return res;
}

//中序遍历的递归写法
void helper2(TreeNode *root, vector<int> &res)
{
	if (!root) return;
	helper2(root->left, res);
	res.push_back(root->val);
	helper2(root->right, res);
}
vector<int> inTraversalRecur(TreeNode *root)
{
	vector<int> res;
	helper2(root, res);
	return res;
}
vector<int> inTraversalNonrecur(TreeNode *root)
{
	vector<int> res;
	if (!root) return res;
	TreeNode *p = root;
	stack<TreeNode *> s;
	while (!s.empty() || p != NULL)
	{
		while (p != NULL)
		{
			s.push(p);
			p = p->left;
		}
		if (!s.empty())
		{
			p = s.top();
			s.pop();
			res.push_back(p->val);
			p = p->right;
		}
	}
	return res;
}
//后序遍历递归写法
void helper3(TreeNode *root, vector<int> &res)
{
	if (!root) return;
	helper3(root->left, res);
	helper3(root->right, res);
	res.push_back(root->val);
}
vector<int> postTraversalRecur(TreeNode *root)
{
	vector<int> res;
	helper3(root, res);
	return res;
}
//后序遍历非递归写法
vector<int> postTraversalNonrecur(TreeNode *root)
{
	vector<int> res;
	if (!root) return res;
	stack<TreeNode *> s;
	TreeNode *pre=NULL, *cur;
	s.push(root);
	while (!s.empty())
	{
		cur = s.top();
		//如果当前节点是叶子节点或者当前节点的左右子节点都被访问过了,可以用前驱节点是其左右子节点来判断
		if ((cur->left == NULL && cur->right == NULL) || (pre != NULL && (pre == cur->left || pre == cur->right)))
		{
			res.push_back(cur->val); //访问该节点
			pre = cur; // 使得该节点成为前驱结点
			s.pop(); //将该节点从栈中弹出
		}
		//如果当前节点现在不能被访问,则将其右节点和左子节点依次放进栈中
		else
		{
			if(cur->right!=NULL) s.push(cur->right);
			if(cur->left!=NULL) s.push(cur->left);
		}
	}
	return res;
}
//层序遍历,基本思想是队列,一层一层地遍历
vector<int> fromToptoBottom(TreeNode *root)
{
	vector<int> res;
	queue<TreeNode *> q;
	if (!root) return res;
	q.push(root);
	while (!q.empty())
	{
		TreeNode *p = q.front();
		q.pop();
		res.push_back(p->val);
		if (p->left) q.push(p->left);
		if (p->right) q.push(p->right);
	}
	return res;
}
//二叉查找树的查找,保存路径到数组中,找到返回true,没找到就返回false
bool bstSearch(TreeNode *root, int value, vector<int> &res)
{
	if (root == NULL) return false; //如果根节点为空,则返回false
	res.push_back(root->val); //将根节点的值放到结果数组中
	if (value == root->val) return true; //根节点的值等于该值,返回true;
	else if (value < root->val) 
	{
		return bstSearch(root->left, value, res);
	}
	else 
	{
		return bstSearch(root->right, value, res);
	}
}
//二叉树的查找,注意,不是二叉查找树,因此没有大小比较的关系
bool getPathFromRoot(TreeNode *root, int value, vector<int> &path)
{
	if (root == NULL) return false;
	path.push_back(root->val);
	if (root->val == value) return true;
	if (getPathFromRoot(root->left, value, path)) //如果左子树走通了,返回true;
		return true;
	if (getPathFromRoot(root->right, value, path)) //如果右子树走通了,返回true;
		return true;
	path.pop_back();
	return false;
}
//二叉查找树的插入
bool bstInsert(TreeNode *&root, int value)
{
	if (root == NULL)
	{
		root = new TreeNode(value);
		return true;
	}
	else if (value < root->val)
	{
		return bstInsert(root->left, value);
	}
	else if (value > root->val)
	{
        return bstInsert(root->right, value);
	}
	return false;
}
//用数组构建二叉查找树
TreeNode *createBST(vector<int> &list)
{
	int n = list.size();
	if (n == 0) return NULL;
	TreeNode *root = NULL;
	for (int i = 0; i < n; i++)
	{
		if (!bstInsert(root, list[i]))
		{
			cout << list[i] << "已经存在在二叉查找树中了" << endl;
		}
	}
	return root;
}
//二叉查找树的删除
/*
需要删除的节点下面没有子节点,则直接删除
删除节点下面有一个左子节点/右子节点:删除该节点,并将左/右子树连接在其父节点上
删除节点的左右子节点都存在:找出此节点右子树中的最小节点,替换该节点,然后删除该最小节点。
*/
TreeNode *removeBST(TreeNode *root, int value)
{
	if (value < root->val)
		root->left = removeBST(root->left, value);
	else if (value>root->val)
		root->right = removeBST(root->right, value);
	else
	{
		if (root->left == NULL || root->right == NULL)
		{
			root = root->left == NULL ? root->right : root->left;
		}
		else //左右子树都不为空
		{
			TreeNode *p = root->right;
			while (p->left != NULL)
			{
				p = p->left;
			}
			root->val = p->val;
			root->right = removeBST(root->right, p->val);
		}
	}
	return root;
}
//二叉树序列化,将一棵树序列化为一个字符串,先序遍历,递归来做
string treetoString(TreeNode *root)
{
	string res = "";
	if (root == NULL)
	{
		res += "#,";
		return res;
	}
	res += to_string(root->val);
	res += ',';
	res += treetoString(root->left);
	res += treetoString(root->right);
	return res;
}
//序列化之后返回的是char * 该咋办?
char *serialize(TreeNode *root)
{
	string s = treetoString(root);
	char *res = new char[s.size() + 1];
	strcpy(res, s.c_str()); // c_str()的方法把这个string转换成 const char*类型
	return res;
}

//二叉树的反序列化
/*
atoi()和stoi()的区别----数字字符串的处理
相同点:
①都是C++的字符处理函数,把数字字符串转换成int输出
②头文件都是#include<cstring>
不同点:
①atoi()的参数是 const char* ,因此对于一个字符串str我们必须调用 c_str()的方法把这个string转换成 const char*类型的,而stoi()的参数是const string*,不需要转化为 const char*;
*/
TreeNode *stringToTree(string &s)
{
	if (s.empty())
	{
		return NULL;
	}
	if (s[0] == '#') //根节点为NULL,则这棵树为空
	{
		s = s.substr(2); //删除两个字符#,
		return NULL;
	}
	TreeNode *node = new TreeNode(stoi(s));//将数字字符转换为数字,遇到!停下来
	s = s.substr(s.find_first_of(',') + 1); //截取!之后的字符串部分
	node->left = stringToTree(s);
	node->right = stringToTree(s);
	return node;
}
TreeNode *Deserialize(char *str)
{
	string s(str);
	return stringToTree(s);
}
//判断一棵树是不是镜像对称的
bool symmetric(TreeNode *p, TreeNode *q)
{
	if (p == NULL && q == NULL) return true;
	if (!p || !q) return false;
	return (p->val == q->val && (symmetric(p->left, q->right) && symmetric(p->right, p->left)));
}
bool isSymmetric(TreeNode *root)
{
	if (root == NULL) return true;
	return symmetric(root->left, root->right);
}
int main()
{
	vector<int> list = { 4, 1, 5, 6, 2, 3, 8, 9 };
	TreeNode *root = createBST(list);
	string s = treetoString(root);
	cout << s << endl;
	root = stringToTree(s);
	vector<int> res;
	if (getPathFromRoot(root, 8, res))
	{
		for (int i = 0; i < res.size(); i++)
			cout << res[i] << " ";
		cout << endl;
	}
	vector<int> temp;
	if (bstSearch(root, 8, temp))
	{
		for (int i = 0; i < temp.size(); i++)
			cout <<temp[i] << " ";
		cout << endl;
	}

	system("pause");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值