面试经典(11)--二叉树层次遍历

本文详细介绍了层次遍历二叉树的两种方法:递归实现打印指定层次节点和非递归实现从上到下按层次访问二叉树。通过代码示例和分析,阐述了每种方法的实现原理和效率对比。

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

层次遍历二叉树是面试中经常被要求手写的算法,下面来分析遍历过程。

1.先来写一个算法,打印二叉树中某层次的节点(从左到右),其中根节点为第0层。

函数原型:int PrintNodeAtLevel(Node *pRoot,int level),成功返回1,失败返回0。

        10   
      / \   
     5  12   
      / \    
      4    7

打印第1层节点输出:5,12。

思路分析:

肯定要使用先序遍历,考虑使用递归方式,每当递归深入一层level减1,当level=0时输出相应节点。但是这个方法效率比较低,后面我们会改进。

多次强调,递归的退出条件是需要仔细考虑的地方。如果pRoot=NULL或者level<0 这个时候要返回0,如果level=0,要输出节点并返回1。如果上面两点都没有返回,那么就进入递归。

int PrintNodeAtLevel(Node *pRoot,int level)
{
	//返回0不在往更深层递归
	if(pRoot==NULL || level<0)
	{
		return 0;
	}
	//满足条件,输出返回,不在往深层递归
	if(level==0)
	{
		cout<<pRoot->m_chValue<<" ";
		return 1;
	}
	return PrintNodeAtLevel(pRoot->m_pLeft,level-1)+PrintNodeAtLevel(pRoot->m_pRight,level-1);
}
从上面的代码我们可以看出来,假如树的深度是depth,打印level层的节点,如果depth>=level,那么PrintNodeAtLevel返回值肯定大于0,如果depth<level,返回值是0。根据这个规律,我们可以写出如下递归的分层遍历。

void printNode(Node *root)
{
	for(int level=0;;level++)
	{
		if(!PrintNodeAtLevel(root,level))
			break;
		cout<<endl;
	}
}

上述算法每一层的访问都是重新从根节点开始的,知道访问完所有的层次。这样的做法,效率实在不高。下面我们就来讨论非递归的方法。


2.非递归层次遍历

要求:从上到下按层次访问该二叉树,每一层要求访问的顺序从左到右。

void PrintNodeByLevel(Node *pRoot)
{
	if(pRoot==NULL)
	{
		return;
	}
	vector<Node*> vec;
	vec.push_back(pRoot);
	int cur=0,last=1;
	while(cur<vec.size())
	{
		last=vec.size();
		while(cur<last)
		{
			cout<<vec[cur]->m_chValue<<" ";
			if(vec[cur]->m_pLeft)
				vec.push_back(vec[cur]->m_pLeft);
			if(vec[cur]->m_pRight)
				vec.push_back(vec[cur]->m_pRight);
			cur++;
		}
		cout<<endl;
	}
}


编程之美最后说叶劲峰提出一种方法,我看了下比较给力,这个帮助我们更好理解层次遍历。学过数据结构的都学过图的广度遍历,用到了一个队列。二叉树可以使用这种方法,本题关键点是需要再每一层之间输出空行,这就要求我们识别一层的结束。叶劲峰的方法是,在一层结束之后,在队列插入一个结束信号(NULL指针),关键点是我们要想到什么时候插入这个NULL。应该在遇到NULL时,为什么如此?因为我们在队列中遇到NULL,表明本层的遍历已经结束,下层的所有节点已经入队,所以要将NU L入队。

代码:

void PrintNodeByLevel(Node* root) {
    queue<Node*> Q;
    Q.push(root);
    Q.push(0);
    do {
        Node* node = Q.front();
        Q.pop();
        if (node) {
            cout << node->data << " ";
            if (node->pLeft)
                Q.push(node->pLeft);
            if (node->pRight)
                Q.push(node->pRight);
        }
        else if (!Q.empty()) {
            Q.push(0);
            cout << endl;
        }
    } while (!Q.empty());
}


参考:http://www.cnblogs.com/miloyip/archive/2010/05/12/binary_tree_traversal.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值