前面我们写过一篇,讨论如何用栈的方法找到从根节点到叶子节点的路径。其实用递归的方法也可以。但递归也要用到数组来保存已经访问过的路径节点。当根节点等于叶子节点时,表示已经找到了一条从根节点到叶子节点的完整路径。
查找函数findAllPathAndLongest,从根节点开始,查找其左右子节点,若其有左右子节点,则说明根节点是分支节点,把根节点存入路径数组,并先后以其左右子节点为新的根节点,递归调用函数本身。如此循环地递归调用,当新的根节点等于叶子节点时,表示已经找到了一条从二叉树根节点到叶子节点的完整路径,并且已经保存在了节点数组里,数组保存路径中的每一个节点,根据此数组,我们可以输出路径,还可以找出最长路径。
我们定义了一个变量 int stepNumber 来表示固定长度的路径数组steps[]里存入的已经走过的路径节点的最后一个节点的数组下标,数组里存入的已经走过的路径节点信息,存储在数组下标从0到下标stepNumber,此变量以值传递的形式,在调用函数与被调用子函数间传递。所以在调用函数里,可以两次调用函数本身,递归嘛,分别传入左子节点和右子节点为新的根结点,但stepNumber可以给两个被调函数传入相同的值。因为它们对应一模一样的已走过的路径。这里是巧妙的运用了函数的值传递。我们不能任何地方都使用地址传递或者引用传递(c++),如果调用函数并不想使用被改变的实参值的话。
这刚好解决了递归调用结束时伴随的数组存储路径回溯的问题,因为查找到一条路径后,我们还要接着找到剩余的所有路径,数组数据要回溯,查看路径中的分支节点是否还有新的我们没有访问过的子节点,以此为新的根节点,继续查找。层层递归,直到二叉树的根节点的俩子节点都访问完,说明递归已彻底完成,对路径的查找也做到了不重不漏。
在昨天还有一篇文章,讨论了迷宫问题的递归解法,两者非常的相似。读者可以参考迷宫问题那篇文章。所以知识真的可以在原有基础上再生根发芽长叶子,举一反三,融会贯通。
完整代码如下(包含建立二叉树createBTree,输出二叉树displayBTree的逗号表达式形式,查找所有路径并顺带找出最长路径的函数findAllPathAndLongest,再就是main主函数):
#include<iostream>
#include<stdio.h>
using namespace std;
#define STACKDEPTH 15
struct BiTreeNode {
char value;
BiTreeNode* leftChild;
BiTreeNode* rightChild;
};
void createBTree(BiTreeNode *&biTreeRoot,char *&ptChar) {
struct {
BiTreeNode* ptsBiTree[STACKDEPTH];
int indexTop = -1;
}sequStack;
BiTreeNode* ptNew = NULL;
char s ;
int leftRight;//1 is left 2 is right
while (*ptChar != '\0') {
s = *ptChar;
if ('A' <= s && s <= 'Z') {
ptNew = new BiTreeNode;
ptNew->value = s;
ptNew->leftChild = ptNew->rightChild = NULL;
if (biTreeRoot == NULL)
biTreeRoot = ptNew;
else if (leftRight == 1)
sequStack.ptsBiTree[sequStack.indexTop]->leftChild = ptNew;
else if (leftRight == 2)
sequStack.ptsBiTree[sequStack.indexTop]->rightChild = ptNew;
}
else if (s == '(') {
sequStack.indexTop++;
sequStack.ptsBiTree[sequStack.indexTop] = ptNew;
leftRight = 1;
}
else if (s == ',')
leftRight = 2;
else if (s == ')')
sequStack.indexTop--;
ptChar++;
}
}
void displayBTree(BiTreeNode *&biTreeRoot) { // 本查找方法是先序遍历
if (biTreeRoot == NULL)
return;//if binary tree does not exsit,return
cout << biTreeRoot->value;
if (biTreeRoot->leftChild != NULL || biTreeRoot->rightChild != NULL) {
cout << '(';
displayBTree(biTreeRoot->leftChild);
if (biTreeRoot->rightChild != NULL) {
cout << ',';
displayBTree(biTreeRoot->rightChild);
}
cout << ')';
}
}
void findAllPathAndLongest(BiTreeNode* steps[STACKDEPTH],int stepNumber,
BiTreeNode *& biTreeRoot,BiTreeNode* stepLongest[STACKDEPTH],
int &stepNumMax,int &pathNumber) {
if (biTreeRoot == NULL)
return;
else {
stepNumber++;
steps[stepNumber] = biTreeRoot;
}
if (biTreeRoot->leftChild == NULL && biTreeRoot->rightChild == NULL) {
pathNumber++;
cout << "the " << pathNumber<<"th path : ";
for (int i = 0; i <= stepNumber; i++)
cout << steps[i]->value << ' ';
cout << endl;
if (stepNumMax < stepNumber) {
stepNumMax = stepNumber;
for (int i = 0; i <= stepNumMax; i++)
stepLongest[i] = steps[i];
}
}
else {
findAllPathAndLongest(steps,stepNumber,biTreeRoot->leftChild,
stepLongest,stepNumMax,pathNumber);
findAllPathAndLongest(steps,stepNumber,biTreeRoot->rightChild,
stepLongest,stepNumMax,pathNumber);
}
}
int main() {
char array[] = "A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))";
char* ptChar = array; //c++里只能这样分开定义,要不会出错。
BiTreeNode* biTreeRoot = NULL;
createBTree(biTreeRoot,ptChar);
cout << "the char array is :";
for (int i = 0; array[i] != '\0'; i++)
cout << array[i];
cout<< endl<< "binary tree is :";
displayBTree(biTreeRoot);
cout << endl;
BiTreeNode *steps[STACKDEPTH],*stepsLongest[STACKDEPTH];
int stepNumMax = 0;
int pathNumber = 0;
findAllPathAndLongest(steps,-1,biTreeRoot,stepsLongest,stepNumMax,pathNumber);
if (stepNumMax != -1) {
cout << "the longest path has " << stepNumMax+ 1 << " steps : ";
for (int i = 0; i <= stepNumMax; i++)
cout << stepsLongest[i]->value << ' ';
}
return 0;
}
测试的二叉树和对应结果如下:
可见测试结果是对的。谢谢阅读