每天三道冲刺工作--在二元树中找出和为某一值的所有路径

4.在二元树中找出和为某一值的所有路径
题目:输入一个整数和一棵二元树。
从树的根结点开始往下访问一直到叶结点所经过的所有结点形成一条路径。
打印出和与输入整数相等的所有路径。
例如输入整数22 和如下二元树
10
/ \
5 12
/\
4 7
则打印出两条路径: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

};


/**
 * 
 */
package com.lhp;

import java.util.ArrayList;
import java.util.List;

/**
	4.在二元树中找出和为某一值的所有路径
	题目:输入一个整数和一棵二元树。
	从树的根结点开始往下访问一直到叶结点所经过的所有结点形成一条路径。
	打印出和与输入整数相等的所有路径。
	例如输入整数22 和如下二元树
	10
	/ \
	5 12
	/\
	4 7
	则打印出两条路径: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
	};
 */
 
/**
 * 二叉树
 */
class BinaryTree {
	private BinaryTreeNode root;	// 根

	public BinaryTreeNode getRoot() {
		return root;
	}

	public void setRoot(BinaryTreeNode root) {
		this.root = root;
	}
	
	/**
	 * 增加子节点
	 * @param 节点
	 */
	public synchronized void addNode(BinaryTreeNode node) {
		if (null == this.root) {
			this.root = node;
			return;
		}
		
		BinaryTreeNode tempNode = this.root;
		
		while (true) {
			if (node.getM_nValue() > tempNode.getM_nValue()) {	// 大于父节点
				if (null == tempNode.getM_pRight()) {
					tempNode.setM_pRight(node);
					return;
				} else {
					tempNode = tempNode.getM_pRight();
					continue;
				}
			} else if (node.getM_nValue() < tempNode.getM_nValue()) {	// 小于父节点
				if (null == tempNode.getM_pLeft()) {
					tempNode.setM_pLeft(node);
					return;
				} else {
					tempNode = tempNode.getM_pLeft();
					continue;
				}
			} else {	// 等于父节点
				return;
			}
		}
	}
	
	/**
	 * 输出指定路径和大小的所有路径
	 * @param 路径的和
	 */
	public synchronized void printSumPath(int sumValue) {
		printSumPath(this.root, new ArrayList<Integer>(), 0, sumValue);
	}
	
	/**
	 * @param 节点
	 * @param 路径存储集合
	 * @param 临时路径的和
	 * @param 路径的和
	 */
	private void printSumPath(BinaryTreeNode node, List<Integer> path, int tempSum, int sumValue) {
		if (null == node) {
			return;
		}
		
		tempSum += node.getM_nValue();
		path.add(node.getM_nValue());
		
		boolean isLeaf = (null == node.getM_pLeft() && null == node.getM_pRight());	// 是否为叶子
		
		if (isLeaf && tempSum == sumValue) {	// 满足
			System.out.print("sumPath(" + sumValue + "): ");
			for (int i : path) {
				System.out.print(i + " ");
			}
			System.out.println();
		}
		
		// 《向左走,向右走》 :-)
		printSumPath(node.getM_pLeft(), path, tempSum, sumValue);
		printSumPath(node.getM_pRight(), path, tempSum, sumValue);
		
		// 保证递归完成后返回父节点时路径是根结点到父节点的路径,之后遍历父节点的其他子节点,没有则返回到爷爷节点...
		path.remove(path.size() - 1);	// 删除当前节点
		// 最后补充一下,如果path不是指针而是基本类型的话,这句话就没用了(放在递归调用下面就没用了),算法也废了,比如在这里加入一句tempSum+=XXX;对结果没有任何影响,不会影响递归return时其他函数里的参数
	}
	
	/**
	 * 打印前序遍历
	 */
	public synchronized void print() {
		if (null == this.root) {
			System.out.print("HashCode: " + this.hashCode() +  "; 空树;");
			return;
		}
		System.out.print("HashCode: " + this.hashCode() +  "; 树: ");
		print(this.root);
		System.out.println();
	}
	
	private void print(BinaryTreeNode node) {
		if (null != node) {
			System.out.print(node.getM_nValue() + " ");
			print(node.getM_pLeft());
			print(node.getM_pRight());
		}
	}
}

/**
 * 节点
 */
class BinaryTreeNode {
	private int m_nValue; // value of node
	private BinaryTreeNode m_pLeft; // left child of node
	private BinaryTreeNode m_pRight; // right child of node
	
	BinaryTreeNode(int value) {
		this.m_nValue = value;
	}
	
	public int getM_nValue() {
		return m_nValue;
	}
	public void setM_nValue(int mNValue) {
		m_nValue = mNValue;
	}
	public BinaryTreeNode getM_pLeft() {
		return m_pLeft;
	}
	public void setM_pLeft(BinaryTreeNode mPLeft) {
		m_pLeft = mPLeft;
	}
	public BinaryTreeNode getM_pRight() {
		return m_pRight;
	}
	public void setM_pRight(BinaryTreeNode mPRight) {
		m_pRight = mPRight;
	}
}

public class Four {
	public static void main(String[] args) {
		BinaryTree tree = new BinaryTree();
		tree.addNode(new BinaryTreeNode(10));
		tree.addNode(new BinaryTreeNode(5));
		tree.addNode(new BinaryTreeNode(12));
		tree.addNode(new BinaryTreeNode(4));
		tree.addNode(new BinaryTreeNode(7));
		tree.addNode(new BinaryTreeNode(9));
		tree.addNode(new BinaryTreeNode(3));
		tree.print();
		tree.printSumPath(22);
		tree.printSumPath(31);
	}
}
 

#include <stdafx.h>
#include<stdlib.h>
#define MAX 20
/**
 * <span style="font-size:14px;">分析:看到该题目的第一反应是:递归+回溯。首先当然要保存搜索的路径,并记录当前路径上所有元素的和。
如果累积和与当前节点值的和大于输入的整数data,则将不进行加法运算,直接回退;如果与当前节点值的和刚好等于sum,
且当前节点为叶子节点,则打印该路径,然后回退;如果与当前节点值得和小于data,则继续向下计算……,这样的做法似乎很合理,
其实呢?很显然,如果这样做,我们就为问题添加了一个条件:即二元树上的元素值均为正数!!!
题目显然没有给出这个条件。自然算法就错了……</span><p><span style="font-size:14px;">    正确的做法应该是这样的:首先当然仍要保存搜索的路径,并记录当前路径上所有元素的和sum。如果当前节点为叶子节点,</span></p><p><span style="font-size:14px;">并且当前节点值与sum的和等于data,则满足条件,打印后递归返回到父节点,注意在打印后、递归返回之前要先减去当前节点元素</span></p><p><span style="font-size:14px;">的值;如果当前节点不是叶子节点,则不必判断当前节点值与sum的和是否等于data,继续访问子节点……</span></p><p><span style="font-size:14px;">    另一种类似的方法不用录当前路径上所有元素的和sum,</span></p><p><span style="font-size:14px;">而是使用期望的和依次减去访问到的节点的值……最后是判断到达叶子节点时期望和是否减为0,其实时类似的……看代码实现:</span></p>
 */
struct BiTreeNode
{
	int data;
	struct BiTreeNode *left;
	struct BiTreeNode *right;
};

/*递归创建二叉排序树,以'-1'结束*/
BiTreeNode * CreateBSTree(int *data,int pos,int len)
{
	BiTreeNode * tr;
	if(pos>=len)
	{
		return NULL;
	}
	else
	{
		tr = (BiTreeNode *)malloc(sizeof(BiTreeNode));
		tr->data=data[pos];
		tr->left = CreateBSTree(data,2*pos+1,len);
		tr->right = CreateBSTree(data,2*pos+2,len);  
		
		return tr;
	}
}

//中序遍历二叉树
void InOrderTraverse(BiTreeNode * root)
{
	if(root!=NULL)
	{
		InOrderTraverse(root->left);	
		printf("%d  ",root->data);
		InOrderTraverse(root->right);
	}
}

//打印路径
void printPath(int path[],int top)
{
	printf("第一组:");
	for(int i=0;i<top;i++)
		printf("%d ",path[i]);
	printf("\n");
}

//查找和为sum的路径,path数组存放路径的值,top代表每个可行的路径中的元素个数
void findPath(BiTreeNode *root, int sum,int top,int path[])
{
	path[top++] = root->data;
	sum -= root->data;
	
	if (root->left == NULL && root->right==NULL) 
	{
		if (sum == 0) 
		{
			printPath(path, top);
		}
	} 
	else 
	{
		if (root->left != NULL) 
			findPath(root->left, sum, top,path);
		if (root->right!=NULL) 
			findPath(root->right, sum, top,path);
	}
	top --;
	sum += root->data;
}

int main()
{
	int data[]={1,2,3,1,2,3,2,1,3,2,1,2,1,2,1};
	int len=sizeof(data)/sizeof(int);

	BiTreeNode * root=CreateBSTree(data,0,len);	
	InOrderTraverse(root);
	printf("\n");
	
	int sum=6;
	int top=0;
	int path[MAX]={0};
	findPath(root,sum,top,path);
	
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值