首页 > 代码库 > 编程之美问题之二叉树层序遍历多种解法
编程之美问题之二叉树层序遍历多种解法
二叉树的层序遍历(要求区分层,例如每层遍历完输出换行)
单单层序遍历非常简单,一个队列就搞定了,但是区分层则要麻烦些。总的思路无非就是在每次print的时候,要能通过某个东西
区分出当前节点是否是一层最后一个节点,或者下一层的最后一个节点,感觉有点类似于机器学习中找个区分度明显的特征:
1.自己的解法,在单队列基础上,输入队列的数据添加一个标志 ,LevelHeaded,同时,在后面插入两个孩子的时候,判断是否这次输出的是队头,如果是的话,先插
个队头标志,再插入孩子,而且插入一次之后,后面不能插入,用LevelFirst布尔变量来控制。
代码如下
2.编程之美解法:
解法1:指示当前层的结束位置,判读当前index是否等于结束位置,使用vector来实现。并且里面两重循环,里层表示一层结点的处理,外层表示整个的处理
解法2:先解决访问每层结点,然后遍历层,前提还要知道树高,不过后面发现可以通过前面函数返回状态值免除求树高的过程
再次不赘述,树高也可以用递归来求解
3.某人博客:http://blog.csdn.net/cnclenovo/article/details/17513821
解法1:用两个队列,将取出队列和插入两个儿子到队列分开到两个队列里的操作。
然后一层结束标志是取元素队列为空,然后与下一个队列交换内容,实质是交换指针,Mileho是这么解释的.
解法2:记录当前层在队列中的节点数NodesInCurrentLevel,以及下一层在队列的节点数NodesInNextLevel,判断Current变量是否为0来区分层结束
4.Mileho博客:http://www.cnblogs.com/miloyip/archive/2010/05/12/binary_tree_traversal.html
这个链接还上了编程之美书:
解法1:同上面某人博客解法1,其实应该是这个时间早
解法2:和我的思路一致,加入一个层结束标志,但是程序的逻辑设计的比我的beautiful,少一个bool变量,而且看起来程序短。
总结:1 实现queue的时候,都不是node类型,而是node* 类型,这样插入LevelHead标志都会比较方便,而且当swap两个队列空间复杂度为O(1),之前老师教的时候
好像都没太注意这个地方
2.单队列实现,空间复杂度O(n) 具体为最大长度为结点数最多的一层的结点数,n个节点最大值为(n+1)/2
3.遇到问题,首先是大致思路,确定下来后,设计需要的变量,小心设计逻辑,这里的思路里面 区分层有点类似于ML中的找特征
单单层序遍历非常简单,一个队列就搞定了,但是区分层则要麻烦些。总的思路无非就是在每次print的时候,要能通过某个东西
区分出当前节点是否是一层最后一个节点,或者下一层的最后一个节点,感觉有点类似于机器学习中找个区分度明显的特征:
1.自己的解法,在单队列基础上,输入队列的数据添加一个标志 ,LevelHeaded,同时,在后面插入两个孩子的时候,判断是否这次输出的是队头,如果是的话,先插
个队头标志,再插入孩子,而且插入一次之后,后面不能插入,用LevelFirst布尔变量来控制。
代码如下
void LevelOrder(node* p) { Queue<node *> Q; Bool LevelFirst=false; Q.Enqueue(root); while(quene is not empyty) { Q.Dequeue(p); if(q==LevelHead) { p=Q.Dequeue(p); LevelFirst=true; cout<<endl; cout<<q->data; } else { cout<<q->data; } if(p->left) { if(LevelFirst=true) { Q.Enqueue(LevelHead);LevelFirst=False; } Q.Enqueue(p->left); } if(p->right) { if(LevelFirst=true) { Q.Enqueue(LevelHead);LevelFirst=False; } Q.Enqueue(p->right); } } }
2.编程之美解法:
解法1:指示当前层的结束位置,判读当前index是否等于结束位置,使用vector来实现。并且里面两重循环,里层表示一层结点的处理,外层表示整个的处理
void PrintNodeByLevel(Node* root) { vector<Node*> vec; // 这里我们使用STL 中的vector来代替数组,可利用到其动态扩展的属性 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时,说明该层访问结束,输出换行符 } }
解法2:先解决访问每层结点,然后遍历层,前提还要知道树高,不过后面发现可以通过前面函数返回状态值免除求树高的过程
再次不赘述,树高也可以用递归来求解
3.某人博客:http://blog.csdn.net/cnclenovo/article/details/17513821
解法1:用两个队列,将取出队列和插入两个儿子到队列分开到两个队列里的操作。
然后一层结束标志是取元素队列为空,然后与下一个队列交换内容,实质是交换指针,Mileho是这么解释的.
解法2:记录当前层在队列中的节点数NodesInCurrentLevel,以及下一层在队列的节点数NodesInNextLevel,判断Current变量是否为0来区分层结束
4.Mileho博客:http://www.cnblogs.com/miloyip/archive/2010/05/12/binary_tree_traversal.html
这个链接还上了编程之美书:
解法1:同上面某人博客解法1,其实应该是这个时间早
解法2:和我的思路一致,加入一个层结束标志,但是程序的逻辑设计的比我的beautiful,少一个bool变量,而且看起来程序短。
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()); }
总结:1 实现queue的时候,都不是node类型,而是node* 类型,这样插入LevelHead标志都会比较方便,而且当swap两个队列空间复杂度为O(1),之前老师教的时候
好像都没太注意这个地方
2.单队列实现,空间复杂度O(n) 具体为最大长度为结点数最多的一层的结点数,n个节点最大值为(n+1)/2
3.遇到问题,首先是大致思路,确定下来后,设计需要的变量,小心设计逻辑,这里的思路里面 区分层有点类似于ML中的找特征
4.思路正确,代码逻辑不一定正确,20 80原理
另外看到还有一个求十进制表示的二进制数的1的位数,Hamming_weight,也才知道还有个名词
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。