二叉树

本文详细介绍了二叉树的性质,包括层序、递归与非递归遍历方法,以及如何利用遍历函数计算结点数量和深度。此外,还探讨了二叉树的建立和线索化二叉树的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二叉树

1. 性质

(1)从上往下第i层,最多有2^(i-1)个结点。
(2)深度为k的二叉树,最少有k个结点,最多有2^k - 1个结点。
(3)假设叶结点有n0个,度为2的非叶结点有n2个,则n0 = n2+1。
(4)完全二叉树,深度为k,则 2 k − 1 − 1 < n < = 2 k − 1 2^{k-1}-1<n<=2^k-1 2k11<n<=2k1。n个结点,则 k = l o g 2 n + 1 k=log_2^{n+1} k=log2n+1 取上限。

2. 递归遍历

在这里插入图片描述

(1)中序遍历(左根右,从左往右看的顺序)
a + b ∗ c − d − e / f a+b*c-d-e/f a+bcde/f

void inorder(TreeNode* root)
{
	if(root == NULL) return;
	
	inorder(root->left);
	cout<<root->val<<" ";
	inorder(root->right);
}

(2)前序遍历(根左右)
− + a ∗ b − c d / e f -+a*b-cd/ef +abcd/ef

void preorder(TreeNode* root)
{
	if(root == NULL) return ;

	cout<<root->val<<" ";
	preorder(root->left);
	preorder(root->right);
}

(3)后序遍历(左右根)
a b c d − ∗ + e f / − abcd-*+ef/- abcd+ef/

void postOrder(TreeNode* root)
{
	if(root==NULL) return;
	postOrder(root->left);
	postOrder(root->right);
	cout<<root->val<<" ";
}

(4)层次遍历
− + / a ∗ e f b − c d -+/a*efb-cd +/aefbcd

void levelOrder(TreeNode* root)
{
	if(root == NULL) return;
	queue<TreeNode*> q;
	q.push(root);  
	while(!q.empty())
	{
		TreeNode* node = q.front(); q.pop();
		cout<<node->val<<" ";
		if(node->left) q.push(node->left);
		if(node->right) q.push(node->right);
	}
}

3. 非递归遍历

(1)前序遍历:直接输出当前结点(根),将当前结点的右节点入栈,令当前结点等于左结点或栈顶,然后不断循环,直到栈为空。

void preOrder(TreeNode* root)
{
	stack<TreeNode* n> s;
	while(root)
	{
		cout<<root->val <<" "; //根
		if(root->right) s.push_back(root->right); //右结点压栈
		if(root->left) root = root->left; //访问左结点
		else {
				if(!s.empty()) {
				root = s.top(); 
				s.pop();
				}
				else return;
			}
	}
}

(2)中序遍历:将当前结点和它的左结点全部入栈,然后访问最左结点,再访问该最左结点的右节点,将该右节点的全部左结点入栈,不断循环,直到栈为空并且没有左结点。

void inOrder(TreeNode* root)
{
	stack<TreeNode*> s;
	while(root || !s.empty())
	{
		while(root->left) //当前结点的左结点全部压栈
		{
			s.push(root->left);
			root = root->left;
		}
		if(!s.empty())
		{
			root = s.top(); s.pop(); cout << root->val << " "; //访问最左的结点
			root = root->right; //当前结点等于右结点,继续访问所有的左结点
		}
	}
}

(3)后序遍历:先访问左边,右边,再访问根结点,因此要区分两种情况:访问完左边和访问完右边。首先将当前节点的全部左结点入栈,然后访问最左结点,对该最左结点更改状态为R,然后访问该最左结点的右结点,将该右结点的全部左结点入栈。当访问到的最左结点的状态为R,说明其左边的结点都访问过了,此时可以弹出该结点并打印。

struct Node
{
	TreeNode* root;
	enum tag{L,R};
	Node(TreeNode* r = NULL) {root = r; tag = L; }
};
void postOrder(TreeNode* root)
{
	stack<Node*> s; Node* n;
	while(root || !s.empty())
	{
		while(root) //当前全部左结点入栈
		{
			n->root = root; n->tag = L; s.push(n);
			root = root->left;
		}
		int continue1 = 1;
		while(continue1 && !s.empty()) 
		{
			n = s.top(); s.pop(); root = n.root; //访问最左边结点
			switch(n.tag)
			{
				case L: //访问完左边,访问root
					n.tag = R; s.push(n);
					root = root->right;
					continue1 = 0; //将该右节点的全部左结点压栈
					break;
				case R: //访问完右边,访问root
					cout<<root->val<<" "; //右边的结点依次弹栈打印,直到栈空
					break;
			}
		}
	}
}

4. 利用二叉树遍历的函数

(1)计算二叉树结点的个数

int count(TreeNode* root)
{
	if(root==NULL) return 0;
	return 1 + count(root->left) + count(root->right);
}

(2)计算二叉树的深度

int depth(TreeNode* root)
{
	if(root == NULL) return 0;
	return 1 + max(depth(root->left), depth(root->right));
}

5.二叉树的建立

(1)前序建立
在这里插入图片描述

void preCreate(string s, int &i, TreeNode* &root)
{
	if(s[i] == ''@') {
		root = NULL;
		return;
	}
	root = new TreeNode(s[i]);
	create(s, ++i, root->left);
	create(s, ++i, root->right);
}

(2)中序后序建立类似

6. 线索化二叉树

(1)应用
查找结点q的父节点:先假设q是父节点的左孩子,则找到q的最右的结点,该节点的后继应该为父节点;若不是,则q是父结点的右孩子,则找到该节点最左边的结点,该结点的前继为父结点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值