您的位置:首页 > 编程语言

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

2016-08-29 17:09 357 查看
本文转载自《编程之美:分层遍历二叉树》的另外两个实现
题目:给定一棵二叉树,要求按分层遍历该二叉树,即从上到下按层次访问该二叉树(每一层将单独输出一行),每一层要求访问的顺序为从左到右,并将节点依次编号。另外写一个函数,打印二叉树中某层次的节点(从左到右),其中根节点为第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]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: