C++用一个函数解决二叉树节点查找、求高度、求父节点
写代码的原因和思路:
原因:网上好多关于二叉树的节点查找、求高度、求父节点都是分开的,在求父节点的时候,甚至用到了栈,这样很麻烦。这里推荐一种合体式的解决方法。
思路:首先,以下代码都是在已经成功创建一棵二叉树的情况下进行的。
引导:首先是节点查找。只需要在使用先序、中序、后序遍历的任何一种方法的时候,将访问函数visit()设置为比对即可:
这里以先序遍历为例子:
查找节点
void BiTree::preTraverse(Binode*&root)//先序遍历
{
if (root != NULL)
{
visit();
preTraverse(root->lChild);
preTraverse(root->rChild);
}
}
void visit()
{
if (root->data == x)//找到了所需要的节点
{
needed = root;//把所需要的节点返回回去,注意needed是后来引入的,前面没写
return;//结束
}
}
注意:以上代码是不能直接运行的,只是帮助分析
这样节点查找的功能就完成了。
求高度
前期我尝试过引入一个int型的变量,然后每次遍历的时候加1,但是很快发现这样会把高度多算。
尝试代码如下:
void visit()//假设在原来的基础上 引用& 了一个int型的height=1
{
if (root->data == x)//找到了所需要的节点
{
needed = root;//把所需要的节点返回回去,注意needed是后来引入的,前面没写
return;//结束
}
height++;//高度增加
}
这样写的错误在于:由F到G的时候,高度还在增加,但是此时不应该变化。(如图)
解决方法是不要使用“引用&”而在每次遍历的时候,在函数头上增加高度。如图:
void BiTree::findnode(char x, Binode * root,Binode *&needed,int height,int &height_need)
//height是一个中间量,而height_need是你需要的最终结果
{
if (root != NULL)
{
if (root->data == x)
{
needed = root;
height_need=height;//如果找到了节点,就把 中间量 赋值给 所需量
return;
}
findnode(x, root->lChild, needed, height + 1,height_need);//注意,高度是在头函数增加的!
findnode(x, root->rChild, needed, height + 1,height_need);
}
}
以上代码的不同之处在于,中途引入的height只是一个中间变量,而且不会随着一直增加,因为直接使用int型,所以每次遍历实际上是复制了上一次的结果,所以说——对于此图:
在F处的height是上一个D的height+1=3+1=4;而到G的时候,因为F时函数内的height并不影响G时函数内的height,所以G内的height依旧是D的height+1=4.
因此,高度问题也解决了。
求父节点
根据上面同样的道理,我们很容易就想到:在遍历的时候,如果没有找到需要的点,就把该节点保留成父节点。
例如:遍历到A,A不是所需要的,下一个将遍历B,此时保存A就是父节点。
这样的思路同样有一个问题,就是由F到G时,会得到G的父节点是F,这显然是错的,应该是F的前一个D。
和求高度同样的方法:可以设置一个中间量,而不使用“引用&”,这样就能得到所需的父节点,实现代码如下:
void BiTree::findnode(char x, Binode * root,Binode *&needed,Binode *father,Binode*&father_need)
//father是中间变量,father_need是最终所需要的父节点
{
if (root != NULL)
{
if (root->data == x)
{
needed = root;
father_need = father;
return;
}
else//如果没找到,就记录该节点为父节点
{
father = root;
}
findnode(x, root->lChild, needed, father, father_need);//左右遍历
findnode(x, root->rChild, needed, father, father_need);
}
}
这样就完成了父节点的确定。
将以上代码整合到一起:
完整可行代码:
void BiTree::findnode(char x, Binode * root,Binode *&needed,Binode *father,Binode*&father_need,int height,int &height_need)
{
if (root != NULL)
{
if (root->data == x)
{
needed = root;
height_need=height;
father_need = father;
return;
}
else
{
father = root;
}
findnode(x, root->lChild, needed, father, father_need,height + 1,height_need);
findnode(x, root->rChild, needed, father, father_need,height + 1,height_need);
}
}
分析:
该函数的缺点是引入了六个参数,参数很多,容易出错。
该函数的优点是仅使用了一个函数就同时求得了待求节点,高度,父节点。
实现:
cout << "请输入要查找的数据:" << endl;
cout << "要输入几次数据:" << endl;
int n; cin >> n;
cout << "请输入数据:" << endl;
for (int i = 0; i < n; i++)
{
Binode*father = NULL;//重点在于先将父节点置空
Binode*needed = NULL;//将待查节点置空
int height = 0;//高度初始化为0
char x;
cin >> x;
a.findnode(x, root, needed, NULL, father,1, height);//使用查找函数
if (needed != NULL)//判断待查节点是否存在
{
cout << "数据" << x << "存在!" << endl;
cout << "此数据在第" << height << "层!" << endl;
if (father == NULL)//无父节点的情况
cout << "无父节点!" << endl;
else//输出兄弟节点
{
if (father->lChild != NULL && father->rChild != NULL)
{
if (father->lChild = needed)
cout << "存在右兄弟:" << father->rChild->data << endl;
else
cout << "存在左兄弟:" << father->lChild->data << endl;
}
else
cout << "无兄弟节点!" << endl;
}
}
else//待查祭奠不存在的情况
cout << "数据" << x << "不存在!" << endl;
}
截图说明:
对于此二叉树:
感谢阅读!