从二叉树的根节点到所有叶子节点,对应着多条路径。一个根节点对应着其中的唯一的一条路径。要求输出所有的从根节点到叶子节点的路径。
分析思路和走迷宫的方法差不多。前面文章里也尽我所能详细讲过如何用栈的方法遍历迷宫问题的所有路径:探索到一条路径后,开始原路返回,对应着退栈,同时沿固定的一个方向,查找半路上的方块的剩下方向中是否有合适的方向,即对应的新方向是路,非障碍物。然后新路径入栈,接着往出口查找。如此循环重复直至原路返回到出发点。返回路途中所有的路线分叉也已访问完,出发点也没有剩余的合适方向时,查找结束,至此已经得到了迷宫里的所有路径。
这里二叉树也是一样,从根节点开始,分支节点至多有两个方向通往叶子节点,沿左子树前往叶子节点,或者沿右子树去往叶子节点。遇到节点没有左右子节点时,其实就是叶子节点,表示已得到一条从根节点到叶子节点的完整路径,输出即可。路径中的每个节点用栈保存,这是我们查找路径和输出路径的依据。输出后,原路返回,对应着退栈,如果某个分支节点有剩余新的分支(其实只能是右子节点),则入栈其新分支,继续往叶子节点方向查找。我们用栈保存每一步的节点信息,而这个每一步的信息,也得用结构体变量表示,其有一个二叉树节点成员,还有一个方向成员,表示路径查找的选择方向,比如用1 表示后面的节点是前面节点的左子节点,2表示后面的节点是前面节点的右子节点。这个方向成员的取值,应该与栈里路径节点的选择关系严格对应,同步更新,这样才可以保证路径查找的不重不漏。我们用两个循环,分别对应进栈前进操作和退栈返回操作。
我们按从上往下,先左后右的规定方向查找。
如果左子树不为空,则接着沿左子树查找,直至栈顶为叶子节点。
如果左子节点为空,则direction++,沿右子树开始查找。
如果右子节点为空,且左子节点也为空,则表示找到叶子节点,输出即可。
如果右子节点不为空,则这是一条可以查找的方向,右子节点入栈。
如果右子节点为空,而左子节点非空,这种情况只有在退栈返回尝试新路径时候会出现,且该分支节点没有新的可用分支,应继续退栈该中间节点。
总共以上五种选择。
以上相当于文档,以易于程序的阅读,描述了程序的功能。完整代码如下:
#include<iostream>
#include<stdio.h>
using namespace std;
#define STACKDEPTH 15
struct BiTreeNode {
char value;
BiTreeNode* leftChild;
BiTreeNode* rightChild;
};
struct Step{
BiTreeNode* node;
int direction;// 1 is left child ,2 is right child,choose path
};
struct StackStep {
Step steps[STACKDEPTH];
int indexTop = -1;
};
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 findAllPath(BiTreeNode *biTreeRoot) {
if (biTreeRoot == NULL)
return;
int pathNumber = 0;
int direction;
StackStep stack;
stack.indexTop++;
stack.steps[stack.indexTop].node = biTreeRoot;
stack.steps[stack.indexTop].direction = 0;
Step stepNow, stepNext;
while (stack.indexTop > -1) {
stepNow = stack.steps[stack.indexTop];
direction = ++(stack.steps[stack.indexTop].direction);
//成员指向运算符,优先于自增自减运算符
while (direction <= 2)
if (direction == 1 && stepNow.node->leftChild == NULL) {
direction++;
stack.steps[stack.indexTop].direction++;
}
else if (direction == 1 && stepNow.node->leftChild != NULL) {
stepNext.node = stepNow.node->leftChild;
stepNext.direction = 1;
stack.indexTop++;
stack.steps[stack.indexTop] = stepNext;
stepNow = stepNext;
direction = 1;
}
else if (direction == 2 && stepNow.node->leftChild == NULL &&
stepNow.node->rightChild == NULL) {
pathNumber++;
cout << "the " << pathNumber << "th path : ";
for (int i = 0; i <= stack.indexTop; i++)
cout << stack.steps[i].node->value << ' ';
cout << endl;
break;
}
else if (direction == 2 && stepNow.node->rightChild != NULL) {
stepNext.node = stepNow.node->rightChild;
stepNext.direction = 1;
stack.indexTop++;
stack.steps[stack.indexTop] = stepNext;
stepNow = stepNext;
direction = 1;
}
else if (direction == 2 && stepNow.node->rightChild == NULL &&
stepNow.node->leftChild != NULL)
break;
stack.indexTop--;
}
}
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 <<endl<<"all path from root to leaf :" << endl;
findAllPath(biTreeRoot);
return 0;
}
测试结果如下:
对应二叉树为:
对应二叉树为:
谢谢阅读。