/*!
\author LiuBao
\date 2011/3/29
\brief 在二元树中找出和为某一值的所有路径
输入一个整数和一棵二元树。
从树的根结点开始往下访问一直到叶结点所经过的所有结点形成一条路径。
打印出和与输入整数相等的所有路径。
例如输入整数22 和如下二元树
10
/ \
5 12
/ \
4 7
则打印出两条路径:10, 12 和10, 5, 7。
*/
#include <stdio.h>
#include <stdlib.h>
/*!
静态栈声明(简单栈实现)
\param name 栈变量名
\param type 栈元素类型
\param size 栈大小(所能容纳的元素个数)
*/
#define STATIC_DECLARE_STACK(name, type, size) \
static int name##_i = -1; static type name[size]
/*!
把元素val压入栈name
\param name 栈名
\param val 元素
*/
#define PUSH(name, val) \
name[++name##_i] = val
/*!
从栈name中弹出元素
\param name 栈名
\return 弹出的元素
*/
#define POP(name) \
name[name##_i--]
/*!
当前栈元素个数
\param name 栈名
\return 当前栈中元素个数
*/
#define COUNT(name) \
(name##_i + 1)
/*!
访问栈name的第i个元素
\param name 栈名
\param i 栈元素下标(0 ~ 栈容量-1)
\return 第i个栈元素
*/
#define ITEM(name, i) \
name[i]
struct BSTreeNode /// 二叉树节点
{
int m_nValue; ///< 节点值
struct BSTreeNode *m_pLeft; ///< 左儿子指针
struct BSTreeNode *m_pRight; ///< 右儿子指针
};
enum ChildPosition /// 儿子节点插入位置
{
Left, ///< 插入为左儿子
Right ///< 插入为右儿子
};
/*!
创建值为child_value的节点,并插入为parent的pos儿子
\param parent 待插入儿子节点的父节点指针
\param pos 儿子节点插入位置
\param child_value 儿子节点的值
\return 返回新插入的儿子节点的指针
*/
struct BSTreeNode *add_child_to_tree(struct BSTreeNode *parent,
enum ChildPosition pos,
int child_value)
{
struct BSTreeNode *retVal = NULL;
if(parent)
{
struct BSTreeNode *child = malloc(sizeof(struct BSTreeNode));
if(child)
{
child->m_nValue = child_value;
child->m_pLeft = NULL;
child->m_pRight = NULL;
if(pos == Left)
parent->m_pLeft = child;
else
parent->m_pRight = child;
retVal = child;
}
}
return retVal;
}
/*!
创建一个二元查找树,并返回树根指针
\return 二元查找树的根指针
*/
struct BSTreeNode *create_tree()
{
struct BSTreeNode *root = malloc(sizeof(struct BSTreeNode));
if(root)
{
root->m_nValue = 10;
root->m_pLeft = NULL;
root->m_pRight = NULL;
}
{
struct BSTreeNode *lChild = add_child_to_tree(root, Left, 5);
(void)add_child_to_tree(root, Right, 12);
(void)add_child_to_tree(lChild, Right, 7);
lChild = add_child_to_tree(lChild, Left, 4);
lChild = add_child_to_tree(lChild, Right, 3);
(void)add_child_to_tree(lChild, Left, 5);
}
return root;
}
/*!
使用局部静态栈后根递归遍历二叉树,计算叶节点路径和,并打印路径和等于
path_sum的叶节点路径(不可重入)
\param tree 二叉树根
\param path_sum 指定的路径和
*/
void print_path(const struct BSTreeNode *tree, int path_sum)
{
STATIC_DECLARE_STACK(stack, int , 100); //声明局部静态栈
static int curr_path_sum = 0;
if(tree)
{
curr_path_sum += tree->m_nValue; //添加当前节点值到路径和
PUSH(stack, tree->m_nValue); //压入当前节点值
print_path(tree->m_pLeft, path_sum); //左递归遍历
print_path(tree->m_pRight, path_sum); //右递归遍历
/* 如果当前路径是叶节点路径,且路径和等于path_sum,打印路径 */
if(curr_path_sum == path_sum && !tree->m_pLeft && !tree->m_pRight)
{
int i;
printf("path: ");
for(i = 0; i < COUNT(stack); ++i)
printf("%d ", ITEM(stack, i));
printf("\n");
}
curr_path_sum -= tree->m_nValue; //从路径和中减去当前节点值
(void)POP(stack); //从节点栈中弹出节点值
}
}
int main()
{
const struct BSTreeNode *root = create_tree();
print_path(root, 22);
return 0;
}