编程之美:第三章 结构之法 3.10分层遍历二叉树

/*
分层遍历二叉树:
1给定一颗二叉树,要求按分层遍历该二叉树,即从上到下按层次访问该二叉树(每一层将单独输出一行),每一层要求访问的顺序为从左到右,并将节点依次编号,
那么分层遍历如下的二叉树,正确的输出应该为
1
2 3
4 5 6
7 8

                       1
			2                    3
	 4            5                     6
	            7    8

2写另外一个函数,打印二叉树中某层次的节点(从左到右),其中根节点为第0层,函数原型为int PrintNodeAtLevel(Node* root,int level),成功返回1,
失败返回0

假设要求放分二叉树中第k层的节点,那么其实可以把它转换成分别访问"以该二叉树根节点的左右子节点为根节点的两棵子树"中层次为k-1的节点,如题目中的
二叉树,给定k=2,即要求访问原二叉树中第2层的节点(根节点为第0层),可把它转换成分别访问以节点2,3为根节点的两棵子树中第k-1 = 1层的节点

                                                              1
								2                                                            3
				4                              5                             0                                    0
		6               7             8                 9
	0        0      0       0    0         0       0          0


输入:
19
1 2 4 6 0 0 7 0 0 5 8 0 0 9 0 0 3 0 0
输出:
1 
2 3
4 5
6 7 8 9 
*/

/*
关键:
1 	if(!pRoot || iLevel < 0)
	{
		return 0;//这个返回值,非常有用,用于无法知道树的深度的情况下,当无法遍历某一层次的输出
2 	if(iLevel == 0)//递归出口
	{
		printf("%d ",pRoot->_iVal);
		return 1;
	}
3 return printNodeAtLevel(pRoot->_pLeft,iLevel-1) + printNodeAtLevel(pRoot->_pRight,iLevel-1);//注意返回的是当前层次下所有子节点个数
4 	for(int iLevel = 0 ; ; iLevel++)//效率差,每次访问都需要从根节点重新遍历
	{
		if(!printNodeAtLevel(pRoot,iLevel))//当访问到某一层次失败就可以退出了。当level小于0的时候
		{
			break;
5 在访问第k层的时候,我们需要知道第k-1层的节点信息,所以再访问第k层的时候,要是知道第k-1层的节点信息,就不需要从根节点开始遍历
可以从根节点除法,将每一层的节点从左到右压入一个数组,并用一个游标cur记录当前访问的节点,另一个游标last表示当前层次最后一个节点的下一个位置。
以cur = last表示当前层次访问结束,在访问某一层的同时将该层所有节点的子节点压入数组,在访问完某一层之后,检查是否还有新的层次可以访问,直到
访问完所有的层次。
6 int iCur = 0,iLast = 1;//初始化游标起始位置和当前层结束位置的下一个位置
7 while(iCur < vecNode.size())//这里应该是层结束位置等于数组大小的时候结束循环
8 		iLast = vecNode.size();//牛逼,直接用当前层结束位置的下一位置 等于 向量大小 来解决了每次的更新层结束位置的问题
		while(iCur < iLast)
*/

#include <stdio.h>
#include <string.h>
#include <vector>

using namespace std;

const int MAXSIZE = 10000;
typedef struct Node
{
	int _iVal;
	Node* _pLeft,*_pRight;
}Node;
Node g_nodeArr[MAXSIZE];
int g_iIndex;


Node* createNode()
{
	++g_iIndex;
	g_nodeArr[g_iIndex]._pLeft = g_nodeArr[g_iIndex]._pRight = NULL;
	return &g_nodeArr[g_iIndex];
}

Node* buildTree(int* pArr,int iLen,int& iPos)
{
	if(!pArr || iLen < 0 || iPos < 0)
	{
		return NULL;
	}
	Node* pRoot;
	if(pArr[iPos] == 0)//如果是叶节点
	{
		iPos++;
		return NULL;
	}
	if(iPos < iLen)//如果还没有超过长度,持续建立
	{
		pRoot = createNode();
		pRoot->_iVal = pArr[iPos++];
		pRoot->_pLeft = buildTree(pArr,iLen,iPos);
		pRoot->_pRight = buildTree(pArr,iLen,iPos);
	}
	return pRoot;
}

//返回的是某一层下面的节点总数
int printNodeAtLevel(Node* pRoot,int iLevel)
{
	if(!pRoot || iLevel < 0)
	{
		return 0;//这个返回值,非常有用,用于无法知道树的深度的情况下,当无法遍历某一层次的输出
	}
	if(iLevel == 0)//递归出口
	{
		printf("%d ",pRoot->_iVal);
		return 1;
	}
	return printNodeAtLevel(pRoot->_pLeft,iLevel-1) + printNodeAtLevel(pRoot->_pRight,iLevel-1);//注意返回的是当前层次下所有子节点个数
}

void printLevelNode_withoutDepth(Node* pRoot)//访问二叉树某一层次失败的时候返回就可以了
{
	for(int iLevel = 0 ; ; iLevel++)//效率差,每次访问都需要从根节点重新遍历
	{
		if(!printNodeAtLevel(pRoot,iLevel))//当访问到某一层次失败就可以退出了。当level小于0的时候
		{
			break;
		}
		printf("\n");
	}
}

void printLevelNode(Node* pRoot,int iDepth)
{
	for(int i = 0 ; i < iDepth ; i++)//打印每一层的节点
	{
		printNodeAtLevel(pRoot,iDepth);
	}
}

/*
在访问第k层的时候,我们需要知道第k-1层的节点信息,所以再访问第k层的时候,要是知道第k-1层的节点信息,就不需要从根节点开始遍历
可以从根节点除法,将每一层的节点从左到右压入一个数组,并用一个游标cur记录当前访问的节点,另一个游标last表示当前层次最后一个节点的下一个位置。
以cur = last表示当前层次访问结束,在访问某一层的同时将该层所有节点的子节点压入数组,在访问完某一层之后,检查是否还有新的层次可以访问,直到
访问完所有的层次。

首先将根节点1压入数组,将游标cur置为0,游标last置为1,因为当cur = last = 1时,第0层访问结束。当cur < last,说明此层尚未被访问完,因此依次访问
cur到last之间的所有节点,并依次将被访问节点的左右子节点压入数组,当放完问第一层时,cur = 1,
cur == last ,盖层访问完,此时数组中还有尚未被访问到的节点,则输出换行符(为输出新的一行做准备),并将Last定位与新一行的末尾(即数组当前最后一个
元素的下一位),继续依次访问其他层次的节点,知道所有层次访问结束。
*/
void printLevelNode_index(Node* pRoot)
{
	int iCur = 0,iLast = 1;//初始化游标起始位置和当前层结束位置的下一个位置
	vector<Node*> vecNode;
	vecNode.push_back(pRoot);
	while(iCur < vecNode.size())//这里应该是层结束位置等于数组大小的时候结束循环
	{
		iLast = vecNode.size();//牛逼,直接用当前层结束位置的下一位置 等于 向量大小 来解决了每次的更新层结束位置的问题
		while(iCur < iLast)
		{
			Node* pNode = vecNode[iCur];
			printf("%d ",pNode->_iVal);//应该先打印出当前节点值
			if(pNode->_pLeft)
			{
				vecNode.push_back(pNode->_pLeft);
			}
			if(pNode->_pRight)
			{
				vecNode.push_back(pNode->_pRight);
			}
			iCur++;
		}
		printf("\n");
	}
}

void process()
{
	int n;
	while(EOF != scanf("%d",&n))
	{
		int iArr[MAXSIZE];
		for(int i = 0 ; i < n ; i++)
		{
			scanf("%d",&iArr[i]);
		}
		int iPos = 0;
		g_iIndex = 0;
		memset(g_nodeArr,NULL,sizeof(g_nodeArr));
		Node* pRoot = buildTree(iArr,n,iPos);
		//printLevelNode_withoutDepth(pRoot);
		printLevelNode_index(pRoot);
	}
}

int main(int argc,char* argv[])
{
	process();
	getchar();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值