题目:输入一个整数和一棵二元树,从树的根结点开始往下访问一直到叶结点所经过的所有结点形成一条路径,打印出和与输入整数相等的所有路径。
例如:输入整数22和如下二元树
10
/ /
5 12
/ /
4 7
/
3
则打印出三条路径:10, 12和10, 5, 7和10, 5, 4, 3。
题目来源于:http://topic.csdn.net/u/20101011/16/2befbfd9-f3e4-41c5-bb31-814e9615832e.html
思路一:
首先看到这样的问题的时候,我最先的想法是用前序遍历该二叉树,遍历的过程中不断的记录当前节点和以前走过路径的和,当和等于我们输入的值的时候就是我们所要求的合适路径,如果大于的话就剪枝,小于的话就不断的往下递归。
代码如下:
- /*----------------------------------
- Copyright by yuucyf. 2011.04.27
- -----------------------------------*/
- #include "stdafx.h"
- #include <assert.h>
- #include <iostream>
- using namespace std;
- #define MAX_DEPTH 256
- typedef struct tagBSTreeNode
- {
- int nValue;
- tagBSTreeNode *psLeft;
- tagBSTreeNode *psRight;
- tagBSTreeNode *psParent;
- tagBSTreeNode()
- {
- nValue = 0;
- psParent = psLeft = psRight = NULL;
- }
- }
- S_BSTreeNode;
- S_BSTreeNode* AddBSTreeNode(S_BSTreeNode *& psRootNode, int nValue, S_BSTreeNode *psParentNode)
- {
- if (NULL == psRootNode)
- {
- psRootNode = new S_BSTreeNode;
- assert(NULL != psRootNode);
- psRootNode->nValue = nValue;
- psRootNode->psParent = psRootNode->psLeft = psRootNode->psRight = NULL;
- if (psParentNode != NULL)
- {
- psRootNode->psParent = psParentNode;
- }
- return psRootNode;
- }
- if (psRootNode->nValue > nValue)
- {
- return AddBSTreeNode(psRootNode->psLeft, nValue, psRootNode);
- }
- else if (psRootNode->nValue < nValue)
- {
- return AddBSTreeNode(psRootNode->psRight, nValue, psRootNode);
- }
- else
- {
- cout << "Not Insert the equally item." << endl;
- return NULL;
- }
- }
- void FindAllPath(const S_BSTreeNode* psRootNode, int nCurValue, int nSum)
- {
- if (NULL == psRootNode) return;
- int nValue = nCurValue + psRootNode->nValue;
- if (nValue == nSum)
- {
- int aryPath[MAX_DEPTH] = {0};
- int nIndex = MAX_DEPTH;
- while (psRootNode)
- {
- aryPath[--nIndex] = psRootNode->nValue;
- psRootNode = psRootNode->psParent;
- }
- printf("Path => ( ");
- for (int i32I = nIndex; i32I < MAX_DEPTH; i32I++)
- {
- printf("%d ", aryPath[i32I]);
- }
- printf(")/n");
- return;
- }
- else if (nValue < nSum)
- {
- FindAllPath(psRootNode->psLeft, nValue, nSum);
- FindAllPath(psRootNode->psRight, nValue, nSum);
- }
- //如果nValue > nSum,那么就剪枝。
- }
- void DeleteAllItem(S_BSTreeNode *psRoot)
- {
- if (NULL == psRoot) return;
- DeleteAllItem(psRoot->psLeft);
- DeleteAllItem(psRoot->psRight);
- delete psRoot;
- }
- int _tmain(int argc, _TCHAR* argv[])
- {
- S_BSTreeNode *psRoot = NULL;
- S_BSTreeNode *psCurNode = NULL;
- psCurNode = AddBSTreeNode(psRoot, 10, NULL);
- psCurNode = AddBSTreeNode(psRoot, 5, psCurNode);
- psCurNode = AddBSTreeNode(psRoot, 12, psCurNode);
- psCurNode = AddBSTreeNode(psRoot, 4, psCurNode);
- psCurNode = AddBSTreeNode(psRoot, 7, psCurNode);
- psCurNode = AddBSTreeNode(psRoot, 3, psCurNode);
- FindAllPath(psRoot, 0, 22);
- DeleteAllItem(psRoot);
- return 0;
- }
- 总结:
但是以上算法找出的结果均是必须带有根节点,但是如果题目稍微改动为:找出该二叉树中任意一条路径中和与输入整数相同的路径,路径的起始节点不一定是根节点。明显以上的算法不能符合要求,比如我们要找的是和为12的路径,如果依照上面的算法就会找不到,而实际上该路径是存在的,而且是两条,分别是5,4,3和12。尽管以上的算法不符合我们现在所说的要求,但是用上面提供的算法来改变成我们目前所需要的算法是非常简单的,也就是在FindAllPath的剪枝部分加上以下几行Code就可以了。(当然在打印出结果的时候也要做一些改变)
- FindAllPath(psRootNode->psLeft, psRootNode->nValue, nSum);
- FindAllPath(psRootNode->psRight, psRootNode->nValue, nSum);
总结:
该题目是考察二叉排序树的建立和遍历的掌握程度.
理解:
对于主函数的调用
- psCurNode = AddBSTreeNode(psRoot, 10, NULL); //psRoot = NULL
- psCurNode = AddBSTreeNode(psRoot, 5, psCurNode); //psRoot = node(10) 改变了psRoot->left = node(5)
- psCurNode = AddBSTreeNode(psRoot, 12, psCurNode); //psRoot = node(10) 改变了psRoot->right = node(12)
- psCurNode = AddBSTreeNode(psRoot, 4, psCurNode); //psRoot = node(10)
- psCurNode = AddBSTreeNode(psRoot, 7, psCurNode); //psRoot = node(10)
- psCurNode = AddBSTreeNode(psRoot, 3, psCurNode); //psRoot = node(10)
其中参数S_BSTreeNode *& psRootNode 的意思是S_BSTreeNode*psRootNode 的地址,如果在函数中改变psRootNode,调用结束后传入的实参的值也会改变。