算法 二叉树的遍历、查找与判断

非递归中序遍历

void NiceInOrder(BtNode* ptr) //非递归中序遍历
{
	if(ptr == nullptr) return;
	std::stack<BtNode*> st;

	while (ptr != nullptr || !st.empty())
	{
		while (ptr != NULL)
		{
			st.push(ptr);
			ptr = ptr->leftchild;
		}
		ptr = st.top(); st.pop();
		cout << ptr->data;
		ptr = ptr->rightchild;
	}
	cout << endl;
}

在这里插入图片描述
非递归中序遍历中,首先第一步是将左子树进行入栈,当没有左子树的时候,进行出栈

接着去查看有没有右子树,若有则继续将左子树进行入栈,若没有则继续出栈

非递归后续遍历

  • 方法一
void NicePastOrder(BtNode* ptr)
{
	if (ptr == nullptr) return;
	std::stack<BtNode*> st;
	BtNode* tag = nullptr;
	while (ptr != nullptr || !st.empty())
	{
		while (ptr != nullptr) //不断将左子树入栈
		{
			st.push(ptr);
			ptr = ptr->leftchild;
		}
		ptr = st.top(); st.pop(); //左子树为空 进行出栈与判断
		if (ptr->rightchild == nullptr || ptr->rightchild == tag)
		{
			cout << ptr->data;
			tag = ptr;
			ptr = nullptr; //不进行此步骤 则会不断打印该结点
		}
		else
		{
			st.push(ptr);
			ptr = ptr->rightchild;
		}
	}
	cout << endl;
	
}

在这里并没有使用常规的两个栈实现后续遍历,而是使用一个tag标记位

当该结点左子树为空的时候,首先出栈,然后去查看右子树,若右子树也为空则对该节点标记tag,若不为空则将该结点重新入栈

当我们tag结点出栈后,回到上一层结点也出栈后就可以根据tag结点是否需要再次入栈还是之间进行打印,继而实现非递归后续遍历

  • 方法二
struct StkNode
{
	BtNode* pnode;
	int pos;
public:
	StkNode(BtNode* p) :pnode(p), pos(0) {}
};
void StkNicePastOrder(BtNode* ptr)
{
	if (ptr == nullptr) return;
	stack<StkNode> st;
	st.push(StkNode(ptr));
	while (!st.empty())
	{
		StkNode node = st.top(); st.pop();
		if (++node.pos == 3) //第三次出栈
		{
			cout << node.pnode->data;
		}
		else
		{
			st.push(node);
			if (node.pos == 1 && node.pnode->leftchild != nullptr) //有左孩子
			{
				st.push(StkNode(node.pnode->leftchild));
			}
			else if (node.pos == 2 && node.pnode->rightchild != nullptr) //有右孩子
			{
				st.push(StkNode(node.pnode->rightchild));
			}
		}
	}
	cout << endl;
}

这里通过计数来进行出栈入栈,首先第一步将A入栈;进入循环将A出栈,进行判断 ++node.pos == 3,此时A的++pos应该为1,接着又把A入栈随后判断是否有左子树,有则将左子树入栈

接着进入一样的操作,直到为C时,对C左子树判断为否,则进行出栈并++node.pos,此时pos为2,将C入栈,紧接着判断右子树,右子树也为空,进入下一轮循环,此时++pos == 3 将其进行输出

通过++pos == 3 的方式来分辨是否对其左子树与右子树进行了判断,也就是只有当++pos为3的情况,左右子树都已经考虑完毕,可以之间进行打印
在这里插入图片描述
当我们对上面代码进行一部分修改,很轻松就将其变为中序遍历

void StkNiceInOrder(BtNode* ptr)
{
	if (ptr == nullptr) return;
	stack<StkNode> st;
	st.push(StkNode(ptr));
	while (!st.empty())
	{
		StkNode node = st.top(); st.pop();
		if (++node.pos == 2) 
		{
			cout << node.pnode->data;
			if (node.pnode->rightchild != nullptr) //有右孩子
			{
				st.push(StkNode(node.pnode->rightchild));
			}
		}
		else
		{
			st.push(node);
			if (node.pos == 1 && node.pnode->leftchild != nullptr) //有左孩子
			{
				st.push(StkNode(node.pnode->leftchild));
			}
			
		}
	}
	cout << endl;
}

非递归先序遍历

void NicePreOrder(BtNode* ptr)
{
	if (ptr == nullptr) return;
	stack<BtNode*> st;
	st.push(ptr);
	while (!st.empty())
	{
		ptr = st.top(); st.pop();
		cout << ptr->data;
		if (ptr->rightchild != nullptr)  //先右入栈后左入栈
		{
			st.push(ptr->rightchild);
		}
		if (ptr->leftchild != nullptr)
		{
			st.push(ptr->leftchild);
		}
	}
	cout << endl;
}

需要注意的是遵循栈先入后出的规则,将右子树先入栈再将左子树入栈

二叉树层次遍历

void LevelOrder(BtNode* ptr)
{
	if (ptr == nullptr) return;
	queue<BtNode*> qu;
	qu.push(ptr);
	while (!qu.empty())
	{
		ptr = qu.front(); qu.pop();
		cout << ptr->data;
		if (ptr->leftchild != nullptr)
		{
			qu.push(ptr->leftchild);
		}
		if (ptr->rightchild != nullptr)
		{
			qu.push(ptr->rightchild);
		}
	}
}

入队结点,出队后将左右子树进行入队

计算二叉树的个数与深度

int Count(BtNode* ptr) //计算二叉树个数
{
	if (ptr == nullptr) return 0;
	else return Count(ptr->leftchild) + Count(ptr->rightchild) + 1;
}
int  Depth(BtNode* ptr) //计算二叉树的深度
{
	if (ptr == nullptr) return 0;
	else return std::max(Depth(ptr->leftchild), Depth(ptr->rightchild)) + 1;
}

Z字形遍历

在这里插入图片描述

void ZlevelOrder(BtNode* ptr)
{
	if (ptr == nullptr) return;
	stack<BtNode*> ast;
	stack<BtNode*> bst;
	ast.push(ptr);
	while (!ast.empty() || !bst.empty())
	{
		while (!ast.empty())
		{
			ptr = ast.top(); ast.pop();
			cout << ptr->data;
			if (ptr->leftchild != nullptr) //b栈 先入左后入右
			{
				bst.push(ptr->leftchild);
			}
			if (ptr->rightchild != nullptr)
			{
				bst.push(ptr->rightchild);
			}
		}
		while (!bst.empty())
		{
			ptr = bst.top(); bst.pop();
			cout << ptr->data;
			if (ptr->rightchild != nullptr) //a栈 先入右后入左
			{
				ast.push(ptr->rightchild);
			}
			if (ptr->leftchild != nullptr)
			{
				ast.push(ptr->leftchild);
			}
		}
	}
}

判断是否为满二叉树

bool Is_FullBinaryTree1(BtNode* ptr) //判断是否为满二叉树
{
	return (Count(ptr) == (pow(2, Depth(ptr)) - 1));
}
bool Is_FullBinaryTree(BtNode* ptr)
{
	int s = 1;
	if (ptr == nullptr) return false;
	queue<BtNode*> aqu;
	queue<BtNode*> bqu;
	aqu.push(ptr);
	while (!aqu.empty() || !bqu.empty())
	{
		if (aqu.size() == s)
		{
			while (!aqu.empty())
			{
				ptr = aqu.front(); aqu.pop();
				if (ptr->leftchild != nullptr)
				{
					bqu.push(ptr->leftchild);
				}
				if (ptr->rightchild != nullptr)
				{
					bqu.push(ptr->rightchild);
				}
			}

		}
		else return false;
		s += s;
		if (bqu.size() == s)
		{
			while (!bqu.empty())
			{
				ptr = bqu.front(); bqu.pop();
				if (ptr->leftchild != nullptr)
				{
					aqu.push(ptr->leftchild);
				}
				if (ptr->rightchild != nullptr)
				{
					aqu.push(ptr->rightchild);
				}
			}

		}
		else return false;
		s += s;
		
	}
	return true;
}

第一种方法为常规使用深度与个数进行计算来判断是否为满二叉树
第二种方法为使用两个队列进行判断是否为满二叉树

二叉树的清除

void ClearBinaryTree(BtNode* ptr)
{
	if (ptr != nullptr)
	{
		ClearBinaryTree(ptr->leftchild);
		ClearBinaryTree(ptr->rightchild);
		delete[]ptr;
	}
}

判断是否为满二叉树

bool Is_FullBinaryTree1(BtNode* ptr) //判断是否为满二叉树
{
	return (Count(ptr) == (pow(2, Depth(ptr)) - 1));
}
bool Is_FullBinaryTree(BtNode* ptr)
{
	int s = 1;
	if (ptr == nullptr) return false;
	queue<BtNode*> aqu;
	queue<BtNode*> bqu;
	aqu.push(ptr);
	while (!aqu.empty() || !bqu.empty())
	{
		if (aqu.size() == s)
		{
			while (!aqu.empty())
			{
				ptr = aqu.front(); aqu.pop();
				if (ptr->leftchild != nullptr)
				{
					bqu.push(ptr->leftchild);
				}
				if (ptr->rightchild != nullptr)
				{
					bqu.push(ptr->rightchild);
				}
			}

		}
		else return false;
		s += s;
		if (bqu.size() == s)
		{
			while (!bqu.empty())
			{
				ptr = bqu.front(); bqu.pop();
				if (ptr->leftchild != nullptr)
				{
					aqu.push(ptr->leftchild);
				}
				if (ptr->rightchild != nullptr)
				{
					aqu.push(ptr->rightchild);
				}
			}

		}
		else return false;
		s += s;
		
	}
	return true;
}

第一种方法为常规使用深度与个数进行计算来判断是否为满二叉树
第二种方法为使用两个队列进行判断是否为满二叉树

在二叉树中按值查找结点

BtNode* FindValue(BtNode* ptr,ElemType val)
{
	if (ptr == nullptr || ptr->data == val)
	{
		return ptr;
	}
	else
	{
		BtNode* p = FindValue(ptr->leftchild, val); //先找左边后找右边
		if (p == nullptr)
		{
			p = FindValue(ptr->rightchild, val);
		}
		return p;
	}
}

在二叉树中搜索父结点

BtNode* FindParent(BtNode* ptr, BtNode* child)
{
	if (ptr == nullptr || child == ptr || child == nullptr) return nullptr;
	if (ptr->leftchild == child) return ptr;
	else if (ptr->rightchild == child) return ptr;
	else
	{
		BtNode* p = FindParent(ptr->leftchild, child);
		if (p == nullptr)
		{
			p = FindParent(ptr->rightchild, child);
		}
		return p;
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值