编程之美读书笔记-分层遍历二叉树

转载 2016年08月29日 17:09:28

本文转载自《编程之美:分层遍历二叉树》的另外两个实现
题目:给定一棵二叉树,要求按分层遍历该二叉树,即从上到下按层次访问该二叉树(每一层将单独输出一行),每一层要求访问的顺序为从左到右,并将节点依次编号。另外写一个函数,打印二叉树中某层次的节点(从左到右),其中根节点为第0层,函数原型为int PrintNodeAtLevel(Node* root,int level),成功返回1,失败则返回0。

输出:
1
2 3
4 5 6
7 8
结点定义为:

struct Node 
{
	Node *lChild;
	Node *rChild;
	int data;
};

解析:假设要求访问二叉树中第k层的节点,那么其实可以把它转换成分别访问以该二叉树根节点的左右子节点为根节点的两棵子树中层次为k-1的节点。

int PrintNodeAtLevel(Node* root, int level)
{
	if (!root || level < 0) return 0;
	if (level == 0)
	{
		cout << root->data << endl;
		return 1;
	}
	return PrintNodeAtLevel(root->lChild, level - 1) + PrintNodeAtLevel(root->rChild, level - 1);
}
只需要调用n次PrintNodeAtLevel()就可以分层遍历二叉树。
#include<iostream>
using namespace std;

struct Node 
{
	Node *lChild;
	Node *rChild;
	int data;
};

void Link(Node* nodes, int parent, int left, int right) 
{
	if (left != -1)
		nodes[parent].lChild = &nodes[left];
	if (right != -1)
		nodes[parent].rChild = &nodes[right];
}

int PrintNodeAtLevel(Node* root, int level)
{
	if (!root || level < 0) return 0;
	if (level == 0)
	{
		cout << root->data << " ";
		return 1;
	}
	return PrintNodeAtLevel(root->lChild, level - 1) + PrintNodeAtLevel(root->rChild, level - 1);
}

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

int main()
{
	Node nodes[9] = { 0 };
	for (int i = 1; i < 9; i++) nodes[i].data = i;
	Link(nodes, 1, 2, 3);
	Link(nodes, 2, 4, 5);
	Link(nodes, 3, -1, 6);
	Link(nodes, 5, 7, 8);
	PrintNodeByLevel(&nodes[1]);
}
上面的解法对二叉树中每一层的访问都需要重新从根节点开始,直到访问完所有的层次。其实在访问第k层的时候,我们只需要知道第k-1层的节点信息就足够了。可以从根节点出发,依次将每层的节点从左到右压入一个数组,并用一个游标Cur记录当前访问的节点,另一个游标Last指示当前层次的最后一个节点的下一个位置,以Cur==Last作为当前层次访问结束的条件,在访问某一层的同时将该层的所有节点的子节点压入数组,在访问完某一层之后,检查是否还有新的层次可以访问,直到访问完所有的层次。
#include<vector>
#include<iostream>
using namespace std;

struct Node 
{
	Node *lChild;
	Node *rChild;
	int data;
};

void Link(Node* nodes, int parent, int left, int right) 
{
	if (left != -1)
		nodes[parent].lChild = &nodes[left];
	if (right != -1)
		nodes[parent].rChild = &nodes[right];
}

void PrintNodeByLevel(Node* root) 
{
	vector<Node*> vec; 
	vec.push_back(root);
	int cur = 0;
	int last = 1;
	while (cur < vec.size()) 
	{
		last = vec.size(); 
		// 新的一行访问开始,重新定位last于当前行最后一个节点的下一个位置
		while (cur < last) 
		{
			cout << vec[cur]->data << " "; 
			// 访问节点
			if (vec[cur]->lChild) // 当前访问节点的左节点不为空则压入
				vec.push_back(vec[cur]->lChild);
			if (vec[cur]->rChild) // 当前访问节点的右节点不为空则压入
				vec.push_back(vec[cur]->rChild);
			cur++;
		}
		cout << endl;
		// 当cur == last时,说明该层访问结束,输出换行符
	}
}

int main()
{
	Node nodes[9] = { 0 };
	for (int i = 1; i < 9; i++) nodes[i].data = i;
	Link(nodes, 1, 2, 3);
	Link(nodes, 2, 4, 5);
	Link(nodes, 3, -1, 6);
	Link(nodes, 5, 7, 8);
	PrintNodeByLevel(&nodes[1]);
}

如果我们用队列实现,可以把空间复杂度降为o(1),关键问题在于如何处理换行。可以利用两个队列,一个储存本层的节点,另一个储存下层的节点。遍历本层的节点,把其子代节点排入下层队列。本层遍历完毕后,就可换行,并交换两个队列。使用deque而不是queue,因为deque才支持swap()操作。注意,swap()是O(1)的操作,实际上只是交换指针。

#include<queue>
#include<iostream>
using namespace std;

struct Node 
{
	Node *lChild;
	Node *rChild;
	int data;
};

void Link(Node* nodes, int parent, int left, int right) 
{
	if (left != -1)
		nodes[parent].lChild = &nodes[left];
	if (right != -1)
		nodes[parent].rChild = &nodes[right];
}

void PrintNodeByLevel(Node* root) 
{
	deque<Node*> Q1, Q2;
	Q1.push_back(root);
	do {
		do {
			Node* node = Q1.front();
			Q1.pop_front();
			cout << node->data << " ";
			if (node->lChild)
				Q2.push_back(node->lChild);
			if (node->rChild)
				Q2.push_back(node->rChild);
		} while (!Q1.empty());
		cout << endl;
		Q1.swap(Q2);
	} while (!Q1.empty());
}

int main()
{
	Node nodes[9] = { 0 };
	for (int i = 1; i < 9; i++) nodes[i].data = i;
	Link(nodes, 1, 2, 3);
	Link(nodes, 2, 4, 5);
	Link(nodes, 3, -1, 6);
	Link(nodes, 5, 7, 8);
	PrintNodeByLevel(&nodes[1]);
}

另一个办法是把一个结束信号放进队列里,插入一个空指针去表示一层的结束。只用一个循环、一个队列即可。

#include<queue>
#include<iostream>
using namespace std;

struct Node 
{
	Node *lChild;
	Node *rChild;
	int data;
};

void Link(Node* nodes, int parent, int left, int right) 
{
	if (left != -1)
		nodes[parent].lChild = &nodes[left];
	if (right != -1)
		nodes[parent].rChild = &nodes[right];
}

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->lChild)
				Q.push(node->lChild);
			if (node->rChild)
				Q.push(node->rChild);
		}
		else if (!Q.empty())
		{
			Q.push(0);
			cout << endl;
		}
	} while (!Q.empty());
}

int main()
{
	Node nodes[9] = { 0 };
	for (int i = 1; i < 9; i++) nodes[i].data = i;
	Link(nodes, 1, 2, 3);
	Link(nodes, 2, 4, 5);
	Link(nodes, 3, -1, 6);
	Link(nodes, 5, 7, 8);
	PrintNodeByLevel(&nodes[1]);
}



相关文章推荐

编程之美读书笔记---分层遍历二叉树

层序遍历一颗二叉树。给定一颗二叉树如下: 输出结果: 1 2 3 4 5 6 7 8 给出书上的两种实现: #include #include #include using n...

编程之美读书笔记3:3.10分层遍历二叉树

按照编程之美课本上给出的c语言写法,转化成了java语法。以前觉得层次的话都是用队列,看到这个题之后,才知道用递归的方法解也行,开阔了思路。 import java.util.Scanner;...

《编程之美:分层遍历二叉树》的另外两个实现(叶劲峰 HK)

之前重温本书写书评时,也尝试找寻更好的编程解法。今天把另一个问题的实现和大家分享。 问题定义 给定一棵二叉树,要求按分层遍历该二叉树,即从上到下按层次访问该二叉树(每一层将单独输出一行),每一层要...
  • jw903
  • jw903
  • 2014年08月06日 10:03
  • 1419

[编程之美] PSet3.10 分层遍历二叉树

问题描述:         给定         1.

编程之美(分层遍历二叉树》的另外两个实现)

转自http://www.cnblogs.com/miloyip/archive/2010/05/12/binary_tree_traversal.html   之前重温本书写书评时,也尝试找寻更...
  • xjbzju
  • xjbzju
  • 2011年10月24日 12:37
  • 450

[编程之美3.10]分层遍历二叉树

题目1描述:给定一棵二叉树,要求分层遍历该二叉树,即从上到下按层次访问该二叉树(每层将单独输出一行),每层要求访问的顺序从左到右,并将节点依次编号。正确输出为: ——————————————————...

编程之美-分层遍历二叉树方法整理

【试题描述】 递归程序: 上述程序的缺点是递归函数的调用效率较低,我们知道二叉树的深度n,则只需要调用n次PrintNodeAtLevel(): 更好的算法:...

编程之美:分层遍历二叉树

问题定义 给定一棵二叉树,要求按分层遍历该二叉树,即从上到下按层次访问该二叉树(每一层将单独输出一行),每一层要求访问的顺序为从左到右,并将节点依次编号。下面是一个例子: 输出: 1 2 3...

编程之美 3.10: 分层遍历二叉树

缘由 看到这本书就有一直哦 题干 我的思路 使用循环队列 首先,看到问题1我首先想到了图的广度优先搜索遍历算法,后来一查书(数据结构高分笔记),才想起来树本来就有一种遍历...

《编程之美:分层遍历二叉树》的另外两个实现

问题定义 给定一棵二叉树,要求按分层遍历该二叉树,即从上到下按层次访问该二叉树(每一层将单独输出一行),每一层要求访问的顺序为从左到右,并将节点依次编号。下面是一个例子: 输出: 1 2 3...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:编程之美读书笔记-分层遍历二叉树
举报原因:
原因补充:

(最多只允许输入30个字)