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

转载 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: 从左到右输出二叉树中某一层的节点值。分析与解法:【解法一】 使用递归的方法。先解问题2,然后用问题2的解法依次遍...
  • zengzhen_CSDN
  • zengzhen_CSDN
  • 2015年11月16日 19:28
  • 336

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

这个代码基本是照着书本的思想写的,其实就是用容器数组类这样的一个数据结构,比使用队列简单多了,单纯的使用队列的话,会繁琐一些。这个程序很巧妙精炼,如果是自己不看书手动写代码,估计还会出现许多小的bug...
  • wangzhewang
  • wangzhewang
  • 2011年10月02日 19:53
  • 705

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

层序遍历一颗二叉树。给定一颗二叉树如下: 输出结果: 1 2 3 4 5 6 7 8 给出书上的两种实现: #include #include #include using n...
  • xiaozhuaixifu
  • xiaozhuaixifu
  • 2013年07月20日 13:28
  • 894

编程之美读书笔记_3.10 分层遍历二叉树

3.10 分层遍历二叉树 看到Milo写的这篇文章,又翻了下书,发现书的代码(P253)有个瑕疵,每个节点值后面都会显示一个空格,如果将间隔字符改为“-”,输出的每行最后都有一个“-”,不能达到要求。...
  • flyinghearts
  • flyinghearts
  • 2010年05月25日 23:55
  • 1471

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

一、题目 问题1—— 给定一个棵二叉树,要求分层遍历该二叉树,即从上而下按层次访问该二叉树(每一层单独输出一行),每一层要求访问的顺序是从左到右,并将结点依次编号,如遍历如下的二叉树,输出顺序应该...
  • linfeng24
  • linfeng24
  • 2014年06月25日 23:55
  • 609

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

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

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

问题描述 一棵二叉树,按从上到下,从左到右的方式进行遍历,打印它的所有的节点。 例如二叉树 输出的结果为 a bc def   思路: 二叉树遍历的方式为分层方式 ...
  • wangzhiyu1980
  • wangzhiyu1980
  • 2016年10月31日 15:46
  • 734

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

编程之美提供了两个方法:递归和用vector来保存遍历结果;但是第二种用vector的方法需要保存下所有节点,是o(n)的空间复杂度。 下面是自己的一个的方法,利用与BFS类似的思想,借助一个栈可以...
  • a83610312
  • a83610312
  • 2013年01月29日 14:29
  • 461

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

一、问题描述 将一棵二叉树按层遍历,并将结点依次编号,如下面二叉树的分层遍历结果为: 2 4   6 5  3  7 8  1 并编程函数打印指定层结点,根结点为第...
  • sophistcxf
  • sophistcxf
  • 2013年08月01日 16:58
  • 680

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

学过数据结构我们很容易知道如何进行宽度优先遍历树,那么这道题就是对宽度优先遍历树的算法进行改进。          1        /    \      2      3    /   \...
  • Ididcan
  • Ididcan
  • 2012年09月16日 21:56
  • 942
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:编程之美读书笔记-分层遍历二叉树
举报原因:
原因补充:

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