zoukankan      html  css  js  c++  java
  • 二元树中和为某一值的全部路径

                 近期在这里看到一道面试题,看了题目和作者的解答后,感觉真是强大。

         题目:输入一个整数和一棵二元树。从树的根结点開始往下訪问一直到叶结点所经过的全部结点形成一条路径。打印出和与输入整数相等的全部路径。

         比如输入整数22和例如以下二元树

                                          

        则打印出两条路径:10, 12和10, 5, 7。

        二元树结点的数据结构定义为:

    struct BinaryTreeNode // a node in the binary tree
    {
          int              m_nValue; // value of node
          BinaryTreeNode  *m_pLeft;  // left child of node
          BinaryTreeNode  *m_pRight; // right child of node
    };

            作者的解答为:

    ///////////////////////////////////////////////////////////////////////
    // Find paths whose sum equal to expected sum
    ///////////////////////////////////////////////////////////////////////
    void FindPath
    (
          BinaryTreeNode*   pTreeNode,    // a node of binary tree
          int               expectedSum,  // the expected sum
          std::vector<int>& path,         // a path from root to current node
          int&              currentSum    // the sum of path
    )
    {
          if(!pTreeNode)
                return;
    
          currentSum += pTreeNode->m_nValue;
          path.push_back(pTreeNode->m_nValue);
    
          // if the node is a leaf, and the sum is same as pre-defined, 
          // the path is what we want. print the path
          bool isLeaf = (!pTreeNode->m_pLeft && !pTreeNode->m_pRight);
          if(currentSum == expectedSum && isLeaf)
          {    
               std::vector<int>::iterator iter = path.begin();
               for(; iter != path.end(); ++ iter)
                     std::cout << *iter << '	';
               std::cout << std::endl;
          }
    
          // if the node is not a leaf, goto its children
          if(pTreeNode->m_pLeft)
                FindPath(pTreeNode->m_pLeft, expectedSum, path, currentSum);
          if(pTreeNode->m_pRight)
                FindPath(pTreeNode->m_pRight, expectedSum, path, currentSum);
    
          // when we finish visiting a node and return to its parent node,
          // we should delete this node from the path and 
          // minus the node's value from the current sum
          currentSum -= pTreeNode->m_nValue;
          path.pop_back();
    } 
          细致看代码,你会发现,这样的方法遍历了解空间树,全部的叶子节点都会訪问到,

            假设二叉树是这种呢:

            

           依照这样的方法,20的两个孩子都会訪问到,可是,这在做无用功,由于,题目要求的是从根节点到叶子节点的路径和为22,当訪问到20的时候,路径和已是30了(大于22),再訪问20的孩子,路径和也会大于22,这样就没有必要再訪问20的孩子了。

           所以,应该避免这样的无效搜索,在遍历每一个节点的时候,先推断路径和是否大于目标值,假设大于的话,则不要遍历该节点的孩子,而且回溯。

          优化后的代码为:

    void FindPath(
    	 BinaryTreeNode* pTreeNode, // a node of binary tree
    	 int expectedSum, // the expected sum
    	 std::vector<int>& path, // a path from root to current node
    	 int& currentSum // the sum of path
    	 )
    {
    	if(!pTreeNode)
    		return;
    	currentSum += pTreeNode->m_nValue;
    	if(currentSum > expectedSum){  //推断路径和是否会超出目标值,超出则回溯
    		currentSum -= pTreeNode->m_nValue;
    		return;
    	}
    	path.push_back(pTreeNode->m_nValue);
    		// if the node is a leaf, and the sum is same as pre-defined,
    		// the path is what we want. print the path
    	bool isLeaf = (!pTreeNode->m_pLeft && !pTreeNode->m_pRight);
    	if(currentSum == expectedSum && isLeaf)
    	{
    		std::vector<int>::iterator iter = path.begin();
    		for(; iter != path.end(); ++ iter)
    		std::cout << *iter << '	';
    		std::cout << std::endl;
    	}
    	// if the node is not a leaf, goto its children
    	if(pTreeNode->m_pLeft)
    		FindPath(pTreeNode->m_pLeft, expectedSum, path, currentSum);
    	if(pTreeNode->m_pRight)
    		FindPath(pTreeNode->m_pRight, expectedSum, path, currentSum);
    	// when we finish visiting a node and return to its parent node,
    	// we should delete this node from the path and
    	// minus the node's value from the current sum
    	currentSum -= pTreeNode->m_nValue;
    	path.pop_back();
    }
    
            在原来的代码里添加�了例如以下代码:

    if(currentSum > expectedSum){  //推断路径和是否会超出目标值,超出则回溯
    		currentSum -= pTreeNode->m_nValue;
    		return;
    	}
            剪去无效的子树,避免无效搜素,提高效率。


    參考:

    http://zhedahht.blog.163.com/blog/static/254111742007228357325/





  • 相关阅读:
    PHP microtime() 函数
    PHP localtime() 函数
    PHP idate() 函数
    PHP gmstrftime() 函数
    Orchestrator安装
    [BJOI2017]开车
    cant found Microsoft.VSSDK.BuildTools.15.0.26201
    如何移动 nuget 缓存文件夹
    如何移动 nuget 缓存文件夹
    如何移动 nuget 缓存文件夹
  • 原文地址:https://www.cnblogs.com/yxwkf/p/3861443.html
Copyright © 2011-2022 走看看