之前转载过二叉树的层次/宽度遍历文章,这里再提出一些更有趣的想法。
说到宽度遍历,很多人就会想到queue,而说到遍历,大家就会想到stack。看看下面宽度遍历的代码
void breadthFirstSearch(Tree root){
queue<Node *> nodeQueue; //使用C++的STL标准模板库
nodeQueue.push(root);
Node *node;
while(!nodeQueue.empty()){
node = nodeQueue.front(); //将访问过的节点弹出队列
nodeQueue.pop();
printf(format, node->data);
if(node->lchild){
nodeQueue.push(node->lchild); //先将左子树入队
}
if(node->rchild){
nodeQueue.push(node->rchild); //再将右子树入队
}
}
}
为什么队列可以实现层次遍历呢?因为利用队列先进先出的特点,依次将每一层的节点的放入队列,然后从头到尾访问。有点就是,为什么遍历的过程中需要将访问过的元素弹出呢?这里很有意思,通过弹出访问过的元素,那么程序永远都可以找到最新没访问过的元素。当然,我们也可以引出一个新变量,来记录当前访问的位置,如果有效设计,该变量还可以有效的体现出层次关系!(这是队列实现没有的特征)
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int> > levelOrderBottom(TreeNode *root) {
vector<TreeNode*> tmp;
vector<vector<int> > res;
if(root==NULL) return res;
int cur, last;
cur=0;
tmp.push_back(root);
while(cur<tmp.size()){
last=tmp.size();
vector<int> v;
//add all nodes in the current level
while(cur<last){
v.push_back(tmp[cur]->val);
if(tmp[cur]->left) tmp.push_back(tmp[cur]->left);
if(tmp[cur]->right) tmp.push_back(tmp[cur]->right);
cur++;
}
res.push_back(v);
}
reverse(res.begin(), res.end()); //将结果倒转!
return res;
}
};
这里是用数值vector实现的,cur表示新一层中第一个未访问的元素,last表示新一层中最后一个元素。
除了使用游标的方式,也有人才有NULL作为标记的方式来体现层次的信息。例如下面的代码
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->pLeft)
Q.push(node->pLeft);
if (node->pRight)
Q.push(node->pRight);
}
else if (!Q.empty()) {
Q.push(0);
cout << endl;
}
} while (!Q.empty());
}
思路是
是把一个结束信号放进队列里。
注意一点,当发现空指针(结束信号)时,要检查队列内是否还有节点,如果没有的话还插入新的结束信号,则会做成死循环。