二查找树层序遍历的思路是沿着树中同一深度的节点进行遍历
难点在于如何在同层节点之间移动,一般方法为预先处理,即在处理父节点时将子节点信息保存,而且要注意需要从左向右顺序遍历,很自然的使用FIFO的队列就可以啦~
由于我们在处理当前层时预先将下一层的节点入列,那我们如何知道什么时候处理完当前层了呢?
我们可以在每次处理完当前层时放置一个结束的标识,因为队列节点的键值为TreeNode *,所以我们可以将NULL值当作结束标志在每处理完一层后将其入列~
代码如下:
void PrintNodeByLevel1(Tree T)
{
Queue Q = CreateQueue();
Tree Temp = T;
MemberType mTemp; //typedef TreeNode * MemberType
Enqueue(T, Q); //将根节点入列
Enqueue(NULL, Q);
while (!IsEmpty(Q))
{
while ((mTemp = Dequeue(Q))!=NULL)
{//每次迭代将首元素出列
printf("%d ", mTemp->Element);
//将当前访问的元素的子节点入列
if (mTemp->Left)
Enqueue(mTemp->Left, Q);
if (mTemp->Right)
Enqueue(mTemp->Right, Q);
}
printf("\n");
if (!IsEmpty(Q)) //注意!如果不检查队列是否为空就将NULL入列,会造成死循环!
<span style="white-space:pre"> </span>Enqueue(NULL, Q); //将空值入列代表作为当前行结束标识
}
}
还有第二种层序遍历的方法,是用C++自带的vector容器替代队列,利用了vector容器的自动扩充的能力,这次并没有使用NULL值作为结束标识,而是使用两个int变量,一个指向当前处理的元素,一个指向当前层的尾后位置(有点乱。。)
代码如下:
void PrintNodeByLevel2(Tree T)
{
vector<TreeNode *> vec;
int cur = 0;//当前节点
int last = 1;//当前层尾后游标
Tree Temp = T;
vec.push_back(Temp);
while (cur<vec.size())//当上次迭代中没有子节点入列,说明当前层为叶子层
{
last = vec.size();//将last游标设置在行尾
while (cur < last)
{
printf("%d ",vec[cur]->Element);
//当前访问元素的子节点入列
if (vec[cur]->Left)
vec.push_back(vec[cur]->Left);
if (vec[cur]->Right)
vec.push_back(vec[cur]->Right);
++cur;//当前访问结点后移
}
printf("\n");
}
}
这两个方案并没有谁优谁劣之分,都着O(N)的空间复杂度以及O(N^2)的时间复杂度,在结束标识问题上第一个方案需要占用队列空间,第二个方案使用两个游标,差别不大。