树 --- 遍历树

  1. 先序遍历树(递归)
  2. 中序遍历树(递归)
  3. 后序遍历树(递归)
  4. 非递归先序遍历
  5. 非递归中序遍历
  6. 非递归后序遍历
  7. 层序遍历

1、先序遍历树(递归)

思路:

  • 第一次访问节点便进行打印。
  • 递归遍历该节点的左子树
  • 递归遍历该节点的右子树

代码如下:

void PreOrder(Node *tree)
{
	if (tree != NULL)
	{
		cout << tree->val << " ";
		PreOrder(tree->lTree);
		PreOrder(tree->rTree);
	}
}

2、中序遍历树(递归)

思路:

  • 先递归遍历左子树
  • 再打印当前节点
  • 最后递归遍历右子树

代码如下:

void InOrder(Node* tree)
{
	if (tree != NULL)
	{
		InOrder(tree->lTree);
		cout << tree->val << " ";
		InOrder(tree->rTree);
	}
}

3、后序遍历树(递归)

思路:

  • 先递归遍历左子树
  • 再递归遍历右子树
  • 最后打印当前节点

代码如下:

void PastOrder(Node* tree)
{
	if (tree != NULL)
	{
		PastOrder(tree->lTree);
		PastOrder(tree->rTree);
		cout << tree->val << " ";
	}
}

4、非递归先序遍历

方法1(从右到左入栈):利用一个栈,首先将根节点入栈,然后当栈不为空时做如下循环

  • 获取栈顶元素并打印
  • 栈顶元素出栈
  • 判断获取到的栈顶元素右子树是否为空,不为空则入栈右节点
  • 判断获取到的栈顶元素左子树是否为空,不为空则入栈左节点

代码如下:

void NicePreOrderRTL(Node* tree)
{
	stack<Node*> st;
	st.push(tree);
	while (!st.empty())
	{
		Node* p = st.top();
		cout << p->val << " ";
		st.pop();

		if (p->rTree != NULL)
		{
			st.push(p->rTree);
		}
		if (p->lTree != NULL)
		{
			st.push(p->lTree);
		}
	}
}

方法2(从左到右入栈):思路如下:

  • 利用一个栈,首先从根节点一直入栈左子树,并不断打印遇到的节点,直到左子树为NULL
  • 获取并出栈栈顶元素,对获取到的栈顶元素的右子树做如上操作
  • 直到将栈为空,遍历结束

代码如下:

void NicePreOrder(Node* tree)
{
	stack<Node*> st;
	while (tree != NULL || !st.empty())
	{
		while(tree)
		{
			cout << tree->val << " ";
			st.push(tree);
			tree = tree->lTree;
		}
		if (!st.empty())
		{
			tree = st.top();
			tree = tree->rTree;
			st.pop();
		}
	}
	cout << endl;
}

5、非递归中序遍历

方法1:很显然中序遍历是当第二次访问到某个节点时打印(或其他操作),因此可以利用出栈的次数来进行打印。

  • 首先定义一个存储节点访问次数的结构体,此时栈里存储的不光是节点,还有节点对应的出栈次数。如下:
typedef struct stkNode
{
	Node* node;//节点
	int num;//节点对应的出栈次数
public:
	stkNode(Node* n)
	{
		node = n;
		num = 0;
	}
}stkNode;
  • 首先入栈根节点。
  • 获取栈顶元素,判断如果该节点出栈次数,如果为2则打印,然后判断右子树是否为NULL,不为空入栈右子树
  • 如果该节点出栈次数不为2则继续将该节点入栈,然后判断该节点左子树是否为NULL,不为空则入栈左子树
  • 直到栈空,否则重复上述操作

代码如下:

void NiceInOrdernum(Node* tree)
{
	if (tree == NULL)
	{
		return;
	}
	stack<stkNode> st;
	st.push(tree);
	while (!st.empty())
	{
		stkNode stk = st.top();
		st.pop();
		if (++stk.num == 2)
		{
			cout << stk.node->val << " ";
			if (stk.node->rTree != NULL)
			{
				st.push(stkNode(stk.node->rTree));
			}
		}
		else
		{
			st.push(stk);
			if (stk.num == 1 && stk.node->lTree != NULL)
			{
				st.push(stkNode(stk.node->lTree));
			}
		}
	}
	cout << endl;
}

方法2:该方法和从左到右入栈先序非递归遍历相似,只是在入栈左子树的过程中不打印所遇到的节点,而是等到出栈的时候再打印。思路如下

  • 利用一个栈,首先从根节点一直入栈左子树,直到左子树为NULL。
  • 获取并出栈栈顶元素并打印,对获取到的栈顶元素的右子树做如上操作
  • 直到将栈为空,遍历结束

代码如下:

void NiceInOrder(Node* tree)
{
	stack<Node*> st;
	while (tree != NULL || !st.empty())
	{
		while (tree != NULL)
		{
			st.push(tree);
			tree = tree->lTree;
		}
		if (!st.empty())
		{
			tree = st.top();
			st.pop();
			cout << tree->val << " ";
			tree = tree->rTree;
		}
	}
	cout << endl;
}

6、非递归后序遍历

方法1:后序遍历和中序遍历一样,也可以利用出栈次数的方式来做,只不过后序遍历是第三次出栈进行打印。

代码如下:

void NiceLastOrdernum(Node* tree)
{
	if (tree == NULL)
	{
		return;
	}
	stack<stkNode> st;
	st.push(tree);
	while (!st.empty())
	{
		stkNode stk = st.top();
		st.pop();
		if (++stk.num == 3)
		{
			cout << stk.node->val << " ";
		}
		else
		{
			st.push(stk);
			if (stk.num == 1 && stk.node->lTree != NULL)
			{
				st.push(stk.node->lTree);
			}
			else if (stk.num == 2 && stk.node->rTree != NULL)
			{
				st.push(stk.node->rTree);
			}
		}
	}
	cout << endl;
}

7、层序遍历

      层序遍历顾名思义就是一层一层的打印。

      第一步:首先我们完成一个小目标,打印某一层的元素。可以利用递归的方式进行。每向下递归一层则离我们的目标层近一层。直到距目标层为1的时候打印元素,即为第k层的元素。

代码如下:

void PrintLevel_K(Node* tree, int k)
{
	if (tree == NULL || k < 0)
	{
		return;
	}
	
	if (k == 0)
	{
		cout << tree->val << " ";
	}
	else
	{
		PrintLevel_K(tree->lTree, k - 1);
		PrintLevel_K(tree->rTree, k - 1);
	}
}

第二步:求树的深度,即树有多少层。

思路:树的深度即为左子树和右子树深度较大的深度加上1,因此我们也可以利用递归来做。

代码如下:

int Depth(Node* tree)
{
	if (tree == NULL)
	{
		return 0;
	}
	else
	{
		return max(Depth(tree->lTree), Depth(tree->rTree)) + 1;
	}
}

第三步:层序打印。

思路:我们已经知道了树有多少层,也可以对树的某一层进行打印。因此循环打印每一层即可

代码如下:

void LevelPrint(Node* tree)
{
	int depth = Depth(tree);
	for (int i = 0; i < depth; i++)
	{
		PrintLevel_K(tree, i);
		cout << endl;
	}
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值