数据结构之二叉树

二叉树

二叉树是每个节点最多有两个子树的树结构,不存在度大于2的结点。
在这里插入图片描述
它有以下五种形态
在这里插入图片描述

二叉树的性质

  1. 二叉树的第i层至多有2i个结点;

  2. 深度为k的二叉树至多有2k-1个结点;

  3. 对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1。

  4. 包含n个节点的二叉树的高度至少为log2 (n+1)。
    在这里插入图片描述

斜树

所有结点都只有左子树或右子树的二叉树被称为斜树。
在这里插入图片描述

满二叉树

满二叉树:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点。它只有度为0和度为2的节点,没有度为1的节点,并且所有的度为0的节点都在同一层上。
在这里插入图片描述
假设一棵满二叉树的高度为h,则它的总节点数为奇数,为2i-1,叶子节点数为2h,第k层的结点数是:2k-1。

完全二叉树

一颗二叉树中,只有最下面两层节点的度可以小于2,并且最下层的叶节点集中在靠左的若干位置上。
在这里插入图片描述
若设二叉树的深度为h,除第 h 层外,其它各层 (1~(h-1)层) 的结点数都达到最大个数,第h层所有的结点都连续集中在最左边。当结点的度为 1 时,该结点只能拥有左子树。

二叉树的节点定义

每一个节点在保存自身数据的同时,拥有指向左右子树的指针

class TreeNode
{
public:
	BiTreeNode(int v=0, TreeNode* l = nullptr, TreeNode* r = nullptr):val(v),left(l),right(r)
	{
	
	}
	int val;
	TreeNode* left;
	TreeNode* right;
};

二叉树的定义

每棵树都会有一个根节点root

class BinaryTree{
public:
	BinaryTree(TreeNode* r=nullptr):root(r)
	{
	}
	~BinaryTree()
	{
		clearNode(root);
		root=nullptr;
	}

private:
	void BinaryTree::clearNode(TreeNode* p)
	{
		if (p != nullptr)
		{
			clearNode(p->left);
			clearNode(p->right);
			delete p;
		}
	}
	TreeNode* root;
}

树的前序遍历

在这里插入图片描述
前序遍历的顺序是:根左右
上述图片的前序遍历:12457368
在这里插入图片描述
从根节点1出发,按照根左右的顺序,访问左节点2,得到1->2,再将左节点2当作根节点,访问节点2的左节点,得到1->2->4,将4当作根节点,左右节点为空,则节点2的左子树访问完成,接着访问节点2的右子树,得到1->2->4->5

//递归
void preorder(TreeNode* root, vector<int>& res) {
	if (root == nullptr) return;
	res.push_back(root->val);
	preorder(root->left);
	preorder(root->right);
}

//非递归
vector<int> preorder(TreeNode* root) {
	if (root == nullptr) return {};
	vector<int> res;
	stack<TreeNode*> st;
	st.push(root);
	while (!st.empty())
	{
		root = st.top();
		res.push_back(root->val);
		st.pop();
		if (root->right != nullptr) st.push(root->right);
		if (root->left != nullptr) st.push(root->left);
	}
	return res;
}

二叉树的中序遍历

仍采用前序遍历的图
中序遍历的顺序:左根右
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
从最下面一层开始,将左节点合并到父节点的左边,右节点合并到父节点的右边,然后整体作为一个节点,不断重复这个操作,直到根节点
中序遍历的结果:42751683

//递归
void inorder(TreeNode* root, vector<int>& res) {
	if (root == nullptr) return;
	inorder(root->left);
	res.push_back(root->val);
	inorder(root->right);
}
//非递归
vector<int> inorder(TreeNode* root) {
	if (root == nullptr) return {};
	stack<TreeNode*> st;
	vector<int> res;
	while (root || !st.empty())
	{
		while (root != nullptr)
		{
			st.push(root);
			root = root->left;
		}
		root = st.top();
		st.pop();
		res.push_back(root->val);
		root = root->right;
	}
	return res;
}

二叉树的后序遍历

后序遍历的顺序是:左右根
在这里插入图片描述
从节点1开始,按照左右根的顺序,找到节点1的左节点(节点2),将节点2当作根节点,找到节点2的左节点(节点4),将节点4作为根节点,找寻左节点,左节点为空,找寻节点4的右节点,右节点为空,则轮到了节点4,以节点2作为根节点的左子树遍历完毕,则遍历节点2的右节点,以节点5作为根节点继续遍历。
结果:47528631

//递归
void postorder(TreeNode* root, vector<int>& res) {
	if (root == nullptr) return;
	postorder(root->left);
	postorder(root->right);
	res.push_back(root->val);
}
//非递归
vector<int> postorderTraversal(TreeNode* root) {
	stack<TreeNode*> st;
	vector<int> res;
	if (root == nullptr) return res;
	st.push(root);
	while (!st.empty())
	{
		root = st.top();
		st.pop();
		res.push_back(root->val);
		if (root->left) st.push(root->left);
		if (root->right) st.push(root->right);
	}
	reverse(res.begin(), res.end());
	return res;

}

层序遍历

在这里插入图片描述
判断根节点是否为空,不为空则可以将根节点放进队列里,根节点此时存储着第1层的所有节点,通过遍历的方式获取此时的queue的所有结点的左右结点就可以得到第2层的所有结点,重复此操作,直到队列为空

vector<vector<int>> levelOrder(TreeNode* root) {
	vector<vector<int>> res;
	if (root == nullptr)
	{
		return res;
	}
	queue<TreeNode*> q;
	q.push(root);
	while (!q.empty())
	{
		int sz = q.size();
		vector<int> tmp;
		for (int i = 0; i < sz; i++)
		{
			root = q.front();
			q.pop();
			tmp.push_back(root->val);
			if (root->left) q.push(root->left);
			if (root->right) q.push(root->right);
		}
		res.push_back(tmp);
	}
	return res;
}

通过前序和中序数组建立二叉树

在这里插入图片描述
前序数组按照根左右的原则遍历,排在左边的为根节点,中序遍历的根节点在中间,我们找到根节点后,查找根节点在中序数组的位置,左边则为树的左子树的节点,右边的则为树的右子树的节点,通过递归的方式不断建立当前节点的左右子树,直到达到终止节点

TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
	//用哈希数组存储中序数组的元素对应的的下标
	unordered_map<int, int> mp;
	for (int i = 0; i < inorder.size(); i++)
	{
		mp[inorder[i]] = i;
	}
	return createTree(preorder, mp,0, preorder.size() - 1, 0, preorder.size() - 1);
}
//pl,pr为此次操作建立子树的元素对应的先序数组的下标,il,ir则为中序数组的
TreeNode* createTree(vector<int>& preorder, unordered_map<int, int>& mp,
	int pl, int pr, int il, int ir)
{
	if (pl > pr) return nullptr;
	TreeNode* root = new TreeNode(preorder[pl]);
	//从哈希数组获取根节点对应的下标
	int index = mp[preorder[pl]];
	//左子树的节点数量index-il,所以左子树在先序数组的范围是[pl+1,pl+index-il]
	root->left = createTree(preorder, mp, pl + 1, pl + index - il, il, index - 1);
	root->right = createTree(preorder, mp, pl + index - il + 1, pr, index + 1, ir);
	return root;

}

通过中序和后序数组建立二叉树

思路与前面的一样,只是根节点在最右边

TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
	unordered_map<int, int> mp;
	for (int i = 0; i < postorder.size(); i++)
	{
		mp[inorder[i]] = i;
	}
	TreeNode* root = createTree(postorder, mp, 0, inorder.size() - 1, 0, postorder.size() - 1);
	return root;
}
TreeNode* createTree(vector<int>& postorder, unordered_map<int, int>& mp, int sl, int sr, int il, int ir)
{
	if (sl > sr) return nullptr;
	TreeNode* root = new TreeNode(postorder[sr]);
	int index = mp[postorder[sr]];
	root->left = createTree(postorder, mp, sl, sl + index - il - 1, il, index - 1);
	root->right = createTree(postorder, mp, sl + index - il, sr - 1, index + 1, ir);
	return root;
}
  • 27
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值