在二元树中找出和为某一值的所有路径(树),满足一下要求:
*该路径是从树的根节点到叶节点的一条路径
* 路径之和恰好等于一个给定的整数,路径的定义是节点的data值之和,允许有负数。
* 打印所有满足条件的路径
其实这是某公司电话面试我的一道题,自己当时答得不是很好,思考一番之后想到了比较完善的解法。可惜面试已经过去了,算了,当做是一种经历的记录吧~一共有三种,下面来一一给出。其实就是树的后序遍历。
1、作为一个二逼青年,首先想到的是递归吧,好吧,我连二逼青年都不如,因为我当时压根没往这方面想啊!!太紧张了,伤不起啊。在这一节,为了后序代码更简洁,也给出一些公共的函数,后面将不会再给了。
#include<stdio.h> #include<string.h> struct NODE { int data; NODE *Left; NODE *Right; }; const int N = 30; NODE node[N]; NODE *stack[N]; int top; int goal;//目标数值 //往二叉查找树里面加节点,公共函数1 void Add(NODE *root, int v) { if(!root) return; if(root->data < v) { if(root->Right) Add(root->Right, v); else { root->Right = &node[++top]; node[top].data = v; } } else if(root->data > v) { if(root->Left) Add(root->Left, v); else { root->Left = &node[++top]; node[top].data = v; } } else printf("重复加入节点%d\n", v); } //打印路径,公共函数2 void Print(NODE **stack, int top) { if(!stack) return; for(int i = 0; i <= top; ++i) printf("%d ", stack[i]->data); printf("\n"); } //递归得到路径 void GetPath(NODE *root, int sum) { if(!root) return; stack[++top] = root;//将根节点压到栈中 sum += root->data; if(!root->Left && !root->Right) { if(sum == goal)//goal为全局变量 Print(stack, top); } else { if(root->Left) GetPath(root->Left, sum); if(root->Right) GetPath(root->Right, sum); } --top; }
2、好吧,文艺一点的解法是什么呢??肯定是用栈来解决啦,但是栈来实现树的后序遍历需要flag标记,所以把NODE的数据结构重新定义一下。
struct NODE { int data; NODE *Left; NODE *Right; bool flag; }; //用栈来得到路径,NODE的定义中包含flag标记 void GetPath(NODE *root) { NODE *p = root; top = -1;//重置栈顶 int sum = 0; while(p != NULL || top > -1) { while(p != NULL) { stack[++top] = p; sum += p->data;//入栈的时候加 p = p->Left; } if(stack[top]->Right == NULL && sum == goal)//是叶节点并且满足条件 { Print(stack, top); sum -= stack[top]->data;//出栈的时候减 --top; } while(top > -1 && stack[top]->flag) { sum -= stack[top]->data;//出栈的时候减 --top; } if(top > -1) { p = stack[top]->Right; stack[top]->flag = true;//标记左子树已访问完毕 } } }
3、更高富帅的版本呢?在节点的定义中加入flag,这就使得定义的数据类型比较大,OK,不加就不加呗!那用什么方法来标记已经访问过左子树的节点呢?用一个辅助栈就可以啦!辅助栈的栈顶元素对应stack的栈顶元素的访问情况,下面给出代码:
//用辅助栈来标记节点,NODE节点的定义中不需要flag void GetPathWithStack(NODE *root) { NODE *p = root; top = -1;//重置栈顶 int sum = 0; memset(FlagStack, 0, sizeof(FlagStack)); while(p != NULL || top > -1) { while(p != NULL) { stack[++top] = p; sum += p->data;//入栈加 p = p->Left; } if(stack[top]->Right == NULL && sum == goal) { Print(stack, top); sum -= stack[top]->data;//退栈减 --top; } while(top > -1 && FlagStack[top]) { sum -= stack[top]->data;//退栈减 --top; } if(top > -1) { p = stack[top]->Right; FlagStack[top] = true; } } }
4、下面给出各种方法的main函数调用,如果不需要的,可以直接pass
int main() { int n,i,v; while(scanf("%d", &n) != EOF) { memset(node, 0, sizeof(node)); top = 0;//top是node数组的顶 scanf("%d", &v); node[0].data = v; for(i = 1; i < n; ++i) { scanf("%d", &v); Add(&node[0], v); } printf("输入需要查找的路径长度:"); scanf("%d",&goal); //top = -1;//方法1的调用 //GetPath(&node[0],0);//方法1的调用 //GetPath(&node[0]);//方法2的调用 GetPathWithStack(&node[0]);//方法3的调用 } }