• 编程之美问题之二叉树层序遍历多种解法


    二叉树的层序遍历(要求区分层,比如每层遍历完输出换行)


    单单层序遍历很easy,一个队列就搞定了,可是区分层则要麻烦些。总的思路无非就是在每次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,也才知道还有个名词


  • 相关阅读:
    一道网易面试题
    OC的引用计数
    ReplayKit2 采集音视频回调格式分析
    《剑指offer3- 从末尾到头打印链表》
    《剑指offer
    《剑指offer
    ReplayKit2:声音回调时间戳问题
    UILable在Autolayout模式下面自动调节字体大小
    建表手写语句
    oracle创建主键序列和在ibatis中应用
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4351441.html
Copyright © 2020-2023  润新知