九度OJ-题目1368:二叉树中和为某一值的路径

题目链接地址:

九度OJ-题目1368:二叉树中和为某一值的路径


题目描述:
输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。

输入:
每个测试案例包括n+1行:
第一行为2个整数n,k(1<=n<=10000),n表示结点的个数,k表示要求的路径和,结点编号从1到n。
接下来有n行。这n行中每行为3个整数vi,leftnode,rightnode,vi表示第i个结点的值,leftnode表示第i个结点的左孩子结点编号,rightnode表示第i个结点的右孩子结点编号,若无结点值为-1。编号为1的结点为根结点。

输出:
对应每个测试案例,先输出“result:”占一行,接下来按字典顺序输出满足条件的所有路径,这些路径由结点编号组成,输出格式参照输出样例。

样例输入:
5  22
10  2  3
5  4  5
12  -1  -1
4  -1  -1
7  -1  -1
1  5
1  -1  -1

样例输出:
result:
A path is found: 1 2 5
A path is found: 1 3
result:


解题思路:

看到题目的标题时,我是有些害怕的,感觉这题有难度,但是仔细分析题意后发现其实没有我想的那么难。
符合要求的路径需要同时满足以下两个条件:
(1) 路径为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径;
(2) 路径和等于k。
我的想法是先序遍历二叉树,在遍历的过程中,记录根结点到当前被遍历结点的路径和sum,如果当前被遍历的结点是叶子结点,则比较当前的路径和sum与所要求的路径和k,如果二者相等就输出根结点到当前结点所经过的结点形成的路径。有以下几个地方需要注意:
   1) 因为需要按字典顺序输出满足条件的所有路径,所以在先序遍历二叉树时,如果结点有左右两个孩子结点时,需要按照优先遍历编号小的结点的规则来进行先序遍历,而不是按照传统的“中左右”顺序进行先序遍历。
   2) 因为路径是从根结点到叶子结点,所以需要在二叉树结点中添加一个指向父结点的指针parent。当找到满足条件的路径时,将叶子结点至根结点所经过的结点依次压入到栈中,然后再输出栈中的所有元素,就能够输出满足条件的路径了。
AC代码如下:

#include<stdio.h>
#include<stack>
using namespace std;
#define MAX 10001
 
// 采用三叉链表来存储二叉树的结点
typedef struct Node
{
   bool isRoot;    // 标记该结点是否为根结点
   int data;       // 数据
   int number;     // 编号
   Node * parent;  // 父指针
   Node * lchild;  // 左孩子指针
   Node * rchild;  // 右孩子指针
}BinaryTreeNode;
 
BinaryTreeNode binaryTreeNode[MAX];
 
/**
* 初始化二叉树,将二叉树中的每个结点都看成是只有一个根结点而左右子树为空的二叉树
* @param n  二叉树的结点个数
* @return void
*/
void initBinaryTree(int n)
{
  int i;
  for(i = 1;i <= n;i++)
  {
     binaryTreeNode[i].isRoot = true;
     binaryTreeNode[i].lchild = NULL;
     binaryTreeNode[i].rchild = NULL;
     binaryTreeNode[i].parent = NULL;
  }
}//initBinaryTree
 
/**
* 构造有n个结点的二叉树,结点编号从1到n。
* @param n  二叉树的结点个数
* @return root  返回二叉树的根结点
*/
BinaryTreeNode * createBinaryTree(int n)
{
  BinaryTreeNode * root = NULL;
  int i;
  int vi;
  int leftnode;
  int rightnode;
  //(1)销毁上一次生成的二叉树结构
  initBinaryTree(n);
  //(2)构造各个二叉树结点的值,编号,左右子树等信息
  for(i = 1;i <= n;i++)
  {
      scanf("%d%d%d",&vi,&leftnode,&rightnode);
      binaryTreeNode[i].data = vi;
      binaryTreeNode[i].number = i;
      if(leftnode != -1)            // 如果结点i存在左子树,则构造其左子树
      {
          binaryTreeNode[i].lchild = &binaryTreeNode[leftnode];
          binaryTreeNode[leftnode].isRoot = false;
          binaryTreeNode[leftnode].parent = &binaryTreeNode[i];
      }
      if(rightnode != -1)            // 如果结点i存在右子树,则构造其右子树
      {
          binaryTreeNode[i].rchild = &binaryTreeNode[rightnode];
          binaryTreeNode[rightnode].isRoot = false;
          binaryTreeNode[rightnode].parent = &binaryTreeNode[i];
      }
  }//for
  //(3)确定二叉树的根结点
  for(i = 1;i <= n;i++)
  {
     if(true == binaryTreeNode[i].isRoot)
     {
        root = &binaryTreeNode[i];
        break;
     }
  }
  return root;
}//createBinaryTree
 
/**
* 采用先序遍历的方式得到二叉树中所有和为k的路径
* @param root  当前被遍历的二叉树的结点
* @param sum  从二叉树根结点到当前正在被遍历的结点的路径和
* @param k  表示要求的路径和
* @return void
*/
void getSumEqualsKPathInBinaryTree(BinaryTreeNode * root,int sum,int k)
{
   if(NULL == root)
      return ;
   sum = sum + (root -> data);
   // root结点有左右两棵子树 则按照优先遍历编号小的子树的规则来进行先序遍历
   // 如果左子树的编号小于右子树的编号,则遍历顺序为"中左右"
   // 如果左子树的编号大于右子树的编号,则遍历顺序为"中右左"
   if(root->lchild != NULL && root->rchild != NULL)
   {
      if((root -> lchild -> number) < (root -> rchild -> number))
      {
          getSumEqualsKPathInBinaryTree(root -> lchild,sum,k);
          getSumEqualsKPathInBinaryTree(root -> rchild,sum,k);
      }
      else
      {
          getSumEqualsKPathInBinaryTree(root -> rchild,sum,k);
          getSumEqualsKPathInBinaryTree(root -> lchild,sum,k);
      }
   }
   // 如果root结点的子树数目不足两棵,则直接按"中左右"的顺序进行遍历
   else
   {
     if(NULL == root -> lchild && NULL == root -> rchild) // 如果root是叶子结点,则判断sum是否等于k
     {
       if(sum == k)                    // 表示找到了和等于k的路径,将该路径打印出来
       {
          BinaryTreeNode * p = root;   // p指针遍历寻找二叉树的根结点
          stack <int> pathStack;       // 用于存放路径的栈
          while(p != NULL)
          {
            pathStack.push(p -> number); // 将结点编号压入到用于存放路径的栈中
            p = p -> parent;
          }
          // 从根结点开始,向下打印路径
          printf("A path is found:");
          while(false == pathStack.empty())
          {
            printf(" %d",pathStack.top());
            pathStack.pop();
          }
          printf("\n");
       }
     }
     getSumEqualsKPathInBinaryTree(root -> lchild,sum,k);
     getSumEqualsKPathInBinaryTree(root -> rchild,sum,k);
   }
}//getSumEqualsKPathInBinaryTree
 
int main()
{
    int n,k,sum;
    BinaryTreeNode * root;
    while(EOF != scanf("%d%d",&n,&k))
    {
       root = createBinaryTree(n);
       sum = 0;
       printf("result:\n");
       getSumEqualsKPathInBinaryTree(root,sum,k);
    }
    return 0;
}
 
/**************************************************************
    Problem: 1368
    User: blueshell
    Language: C++
    Result: Accepted
    Time:40 ms
    Memory:1444 kb
****************************************************************/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值