递归与非递归求二叉树深度

Posted 逆風的薔薇

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了递归与非递归求二叉树深度相关的知识,希望对你有一定的参考价值。

题目


分别用递归与非递归算法求二叉树深度。

分析


方法一: 递归方法大家都很熟悉,如何用非递归求解呢? 我们知道二叉树有层序遍历,利用层序遍历的过程,记录当前层数,那么遍历结束后也就求得二叉树的层数,即深度。
方法二: 层序遍历需要使用一个队列来保存树的节点。初始化讲根节点入队。接着只要队列不为空,则出队,并将出队元素的子节点入队。
当需要记录树的深度时,可以使用两个队列,第一个队列保存当前访问的那一层的节点,讲当前这一层的节点的子节点压入下一队列,这样需要两个队列的额外空间。
若只使用一个队列,则需要一个特殊的标记mark。当我们把某一层的节点入队之后,再压入一个标记mark。当我们在出对是遇到一个标记mark时,我们就知道已经访问完了一层,则当前队列中的元素全部是下一层的节点,我们再压入一个标记mark。用标记mark来标记层数,可以减少一个队列的使用,但是前提是保存队列的数据结构能找到特殊的mark元素。

方法三:利用后序遍历的思想 受后续遍历二叉树思想的启发,想到可以利用后续遍历的方法来求二叉树的深度,在每一次输出的地方替换成算栈S的大小,遍历结束后最大的栈S长度即是栈的深度。
算法的执行步骤如下:
(1)当树非空时,将指针p指向根节点,p为当前节点指针。
(2)将p压入栈S中,0压入栈tag中,并令p执行其左孩子。
(3)重复步骤(2),直到p为空。
(4)如果tag栈中的栈顶元素为1,跳至步骤(6)。从右子树返回
(5)如果tag栈中的栈顶元素为0,跳至步骤(7)。从左子树返回
(6)比较treedeep与栈的深度,取较大的赋给treedeep,对栈S和栈tag出栈操作,p指向NULL,并跳至步骤(8)。
(7)将p指向栈S栈顶元素的右孩子,弹出栈tag,并把1压入栈tag。(另外一种方法,直接修改栈tag栈顶的值为1也可以)
(8)循环(2)~(7),直到栈为空并且p为空
(9)返回treedeep,结束遍历

代码

/*
* 题目:二叉树和为某一值的路径
* 描述:输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。
* 路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
*/

#include <iostream>
#include <cstdlib>
#include <vector>
#include <queue>
#include <stack>
using namespace std;

const int flag = INT_MIN;

struct TreeNode

	int val;
	TreeNode *left;
	TreeNode *right;

	TreeNode(int x) :val(x), left(NULL), right(NULL) 
;


/*递归求二叉树高度*/
int depth(TreeNode *root)

	if (root == NULL)
		return 0;

	int leftDepth = depth(root->left);
	int rightDepth = depth(root->right);

	return max(leftDepth, rightDepth) + 1;


/*非递归求二叉树高度 -- 采用层序遍历的思想,记录树的层数*/
int depth2(TreeNode *root)

	if (root == NULL)
		return 0;
	if (root->left == NULL && root->right == NULL)
		return 1;

	queue<TreeNode *> nodes;
	nodes.push(root);
	int d = 0;
	while (!nodes.empty())
	
		queue<TreeNode *> q;

		while (!nodes.empty())
		
			TreeNode *tmp = nodes.front();
			nodes.pop();

			if (tmp->left != NULL)
				q.push(tmp->left);

			if (tmp->right != NULL)
				q.push(tmp->right);
		//while
		
		++d;
		nodes = q;
	//while
	return d;


//非递归求二叉树高度 -- 利用后序遍历思想
int depth3(TreeNode *root)

	if (root == NULL)
		return 0;
	if (root->left == NULL && root->right == NULL)
		return 1;

	stack<TreeNode *> s;
	stack<int> tag;

	TreeNode *p = root;
	int d = 0;
	while (p != NULL || !s.empty())
	
		while (p != NULL)
		
			s.push(p);
			tag.push(0);

			p = p->left;
		//while

		if (tag.top() == 1)
		
			d = d > s.size() ? d : s.size();
			s.pop();

			tag.pop();

			p = NULL;
		
		else 
			p = s.top();
			p = p->right;
			tag.pop();
			tag.push(1);
		//else
	//while
	return d;


TreeNode *generateTree(vector<int> &nums)

	if (nums.empty())
		return NULL;

	TreeNode *root = new TreeNode(nums[0]);
	queue<TreeNode *> que;
	que.push(root);
	//求出所给元素个数,对应二叉查找树节点个数
	int size = nums.size();
	for (int i = 1; i < size; i += 2)
	
		//处理队首节点的左右子树
		TreeNode *tmp = que.front();
		TreeNode *left = NULL, *right = NULL;
		//定义非空左子树
		if (nums[i] != flag)
		
			left = new TreeNode(nums[i]);
			que.push(left);
		

		//定义非空右子树
		if (i + 1 < size && nums[i + 1] != flag)
		
			right = new TreeNode(nums[i + 1]);
			que.push(right);
		

		tmp->left = left;
		tmp->right = right;
		//弹出当前处理的节点
		que.pop();
	
	return root;


int main()

	vector<int> v =  10, 5, 12, 4, 7 ;
	TreeNode *root = generateTree(v);

	cout << depth(root) << endl;
	cout << depth2(root) << endl;
	cout << depth3(root) << endl;
	system("pause");
	return 0;


以上是关于递归与非递归求二叉树深度的主要内容,如果未能解决你的问题,请参考以下文章

求二叉树的遍历(递归和迭代实现)

求二叉树深度

二叉树的遍历总结

求二叉树中最大的二叉搜索子树的头节点

543-求二叉树直径

基于Java的二叉树的三种遍历方式的递归与非递归实现