先看实验要求:
项目名称:基于二叉树的家谱系统
项目内容:采用一棵二叉树来表示一个家谱关系,一个家谱可表示为一颗树,首先将其转换成一颗二叉树表示,如下图为红楼梦家谱的一部分:
图1.1 家谱的树形表示
图1.2 家谱的二叉树表示
要求完成的功能如下:
(1)输入一颗二叉树的括号表示法,完成树的构建
(2)使用后序遍历递归算法遍历二叉树并输出
(3)使用先序遍历非递归算法遍历二叉树并输出
(4)指定家谱中的某一成员,输出其所有长辈
由题目可见,我们需要将这个族谱先转化为字符串表示的二叉树,然后再用代码的方式来建立对应的二叉树。
我们先把对应的字符串表示的树表示出来:
然后将已知的图和字符串放在一起:
我们观察其中的规律:
发现:右子树的都是同一个辈分的,左子树的每次有一个分叉,它的辈分就低一级,如:BDE是同一个辈分的,假设我们规定根节点的辈分为1,辈分数依次递增,表示它的实际辈分等级越低的话,那么,BDE处在辈分为2的层次,其中C的辈分为3,最低;
为了方便观察,我们再添加几个节点来理解:
可知:AFH在同一个辈分为1的级别上;
BDEGLM都在辈分为2的级别上;
CK都在辈分为3的级别上;
这样,我们就对这个二叉树的表示家谱的方法有了基本的规律认识,下面就是开始建立我们的族谱二叉树了:
在建立之前,笔者在之前写过一将字符串表示的二叉树转化为代码实现的二叉树的博客,为了更好地理解二叉树的建立,请查看原博文:
字符串转化为二叉树的diam实现和图解过程
与该博文中讲解的字符串转化为二叉树的过程相似,只不多这个家谱的二叉树要比普通的字符串建立的二叉树的节点中要多一个成员变量:表示该节点的辈分级别 int generationLevel;
此次笔者将使用通用类的模板来创建二叉树和节点类:
下面是节点类:
#pragma once
template<class T>
class BNode
{
public:
BNode();
BNode(T t);
~BNode();
public:
/*左孩子*/
BNode<T> *leftChild;
/*右孩子*/
BNode<T> *rightChild;
/*节点的值*/
T t;
/*该节点所在的辈分级数*/
int generationLevel;
};
template<class T>
inline BNode<T>::BNode()
{
}
template<class T>
inline BNode<T>::BNode(T t)
{
this->t = t;
}
template<class T>
inline BNode<T>::~BNode()
{
}
二叉树类的模板:
#include"BNode.hpp"
#include"TempNode.hpp"
#include<string>
using namespace std;
template<class T>
class BinaryTree
{
public:
BinaryTree(const char* str);
/*后序遍历非递归*/
void PosOrder();
/*后序遍历递归*/
void PosOrderRe(BNode<T>* root);
/*中序遍历非递归实现*/
void InOrder();
/*先序遍历非递归第一种实现*/
void PreOrderNotRe();
/*先序遍历非递归第二种实现*/
void PreOrderNotRe2();
/*输出节点obj的所有长辈*/
void FindAllAncestor(T obj);
/*输出节点ancestor的值及同辈的值,这里的T是默认为输入一个字符char,如果T是一个节点的话那么在比较相等的时候就要注意对应的转换,适当地改改这个函数就可以了*/
void ShowAncestor(T t);
/*二叉树的析构函数,用于销毁二叉树的节点*/
void destroyTree(BNode<T>* root);
~BinaryTree();
public:
BNode<T>* root = NULL; //树的根节点指针
};
下面是主要函数以及代码的实现:
(1)建立二叉树
template<class T>
inline BinaryTree<T>::BinaryTree(const char* str)
{
const char * p = str; //临时字符串指针
BNode<char>* node = NULL; // 临时节点指针
int k = 1; //判定是左孩子还是右孩子的标识:1为左孩子,2为右孩子
Stack<BNode<char>*> *stack = new Stack<BNode<char>*>(); //用于装取每个二叉树节点的栈
while (*p != '\0')
{
switch (*p)
{
case '(':
stack->push(node); //遇到‘('说明node节点为根节点
k = 1; //遇到‘(’说明下一个节点为左节点
break;
case ',':
k = 2; //遇到‘,’说明下一个节点为右节点
break;
case ')':
stack->pop(); //遇到‘)’弹出栈顶元素的根节点
break;
default:
node = new BNode<char>(*p); //创建节点
if (root == NULL) //第一个节点即为根节点
{
node->generationLevel = 1; //根节点的父辈级数为1
root = node;
}
else if (k == 1) //左节点
{
BNode<char>* topNode = stack->getTop(); //获取栈顶的根节点
node->generationLevel = topNode->generationLevel + 1;//该节点为左子树的节点,则辈分级别加1
topNode->leftChild = node; //根节点的左孩子
}
else if (k == 2) { //右节点
BNode<char>* topNode = stack->getTop(); //获取栈顶的根节点
node->generationLevel = topNode->generationLevel; //该节点为右孩子,则辈分级别和父节点一样
topNode->rightChild = node; //根节点的右孩子
}
break;
}
p++; //字符指针移动到下一个字符的位置
}
}
在建立二叉树的时候,要注意给每个节点的辈分级别赋值,具体是:
根节点的辈分为1;
之后,左孩子节点辈分比父结点低一级,那么她的辈分级别就等于父节点的辈分级别加一;右孩子节点与父结点是兄弟辈分,所以它的辈分级别和父节点的辈分级别相同。
下面我用图解的方式讲解一下前几个节点的创建过程:
第一步:
第二步:
第三步;
第四步:
第五步;
第六步;
第七步:
之后的步骤依次类推,注意每次新节点的创建的时候它的辈分级别要分清楚是左孩子节点还是右孩子节点,如果是左孩子节点,那么它的辈分级别就等于父节点的辈分级别加一,如果是右孩子节点,那就它的辈分级别就等于父节点的辈分级别;
由此,我们就创建好了对应的二叉树。
最终的二叉树为:
建好了二叉树后,我们便开始实现它的遍历所有节点的功能;
首先是
/后序遍历非递归/
void PosOrder();的实现,在这个非递归算法中,采用两个栈的方式来依次实现:
template<class T>
inline void BinaryTree<T>::PosOrder()
{
//使用两个栈来实现遍历
Stack<BNode<T>*> *stack = new Stack<BNode<T>*>();
//用于输出的栈
Stack<BNode<T>*> *outStack = new Stack<BNode<T>*>();
BNode<T>* node = root;
while (node != nullptr || stack->getSize() != 0)
{
if (node != NULL)
{
//父节点入栈
stack->push(node);
//节点入栈
outStack->push(node);
//临时节点指向父节点的右孩子
node = node->rightChild;
}
else
{
//弹出父节点
node = stack->pop();
//临时节点指向弹出的父节点的左孩子
node = node->leftChild;
}
}
//输出所有的节点,逆序输出
while (outStack->getSize() != 0)
{
BNode<T>* node = outStack->pop();
cout << node->t;
}
}
/后序遍历递归/
void PosOrderRe(BNode* root)的具体实现代码比较简单,也容易理解:
template<class T>
inline void BinaryTree<T>::PosOrderRe(BNode<T>* root)
{
//结束递归
if (root == NULL)
{
return;
}
//递归左子树
this->PosOrderRe(root->leftChild);
//递归右子树
this->PosOrderRe(root->rightChild);
//打印节点信息
cout << root->t;
}
先序遍历的非递归具体的实现;
/先序遍历非递归第一种实现/
void PreOrderNotRe();
template<class T>
inline void BinaryTree<T>::PreOrderNotRe()
{
//使用栈装取存有BNode节点和特定标识的临时节点
Stack<TempNode<T>*> *stack = new Stack<TempNode<T>*>();
//先将头结点入栈,并且设定标识为false
stack->push(new TempNode<T>(root, false));
while (stack->getSize() > 0)
{
//先将栈顶元素弹出
TempNode<T>* tempNode = stack->pop();
//如果临时节点中的BNode节点为空则跳过此次循环
if (tempNode->bnode == NULL)
{
continue;
}
//如果临时节点的标识为true则打印输出该节点的值
if (tempNode->fla == true)
{
cout << tempNode->bnode->t;
}
else {
//先将右节点的包装后的临时节点入栈
stack->push(new TempNode<T>(tempNode->bnode->rightChild, false));
//再将左节点的包装后的临时节点入栈
stack->push(new TempNode<T>(tempNode->bnode->leftChild, false));
//修改此刻临时节点的标识
tempNode->fla = true;
//将该临时节点重新入栈
stack->push(tempNode);
}
}
}
当然,先序遍历的非递归也还有另外一种实现:
/先序遍历非递归第二种实现/
void PreOrderNotRe2();`
template<class T>
inline void BinaryTree<T>::PreOrderNotRe2()
{
if (root == NULL)
{
return;
}
BNode<T>* node = root;
Stack<BNode*> *stack = new Stack<BNode*>();
while (stack->getSize()>0||node!=NULL)
{
//对每一棵树而言,都一直向左下走,直到走到最左下的叶子结点
while (node!=NULL)
{
//先序遍历是第一次遇到该结点的时候输出,即结点入栈
cout << node->tl;
stack->push(node);
node = node->leftChild;
}
if (stack->getSize()>0)
{
//进入最左下叶子结点的右孩子
node = stack->pop();
node = node->rightChild;
}
//进入新一轮循环
}
}
/中序遍历非递归实现/
void InOrder();
中序遍历的非递归实现:
template<class T>
inline void BinaryTree<T>::InOrder()
{
BNode<T>* node = root;
Stack<BNode<T>*> *stack = new Stack<BNode<T>*>();
while (node!=NULL||stack->getSize()>0)
{
//对每一棵树而言,都一直向左下走,直到走到最左下的叶子结点
while (node!=NULL)
{
stack->push(node);
node = node->leftChild;
}
if (stack->getSize()>0)
{
//中序遍历是第二次遇到该结点的时候输出,即结点出栈
node = stack->pop();
//进入最左下叶子结点的右孩子
cout << node->t;
//进入新一轮循环
node = node->rightChild;
}
}
}
下面是查找某个成员的所有兄弟辈分并输出:其实这个问题就是转化为了查找辈分级别相同的二叉树的节点并输出节点的值。那么我们就先要从根节点开始遍历,首先找到该成员对应的节点,然后获得该节点的辈分级别,并输出辈分级别和该成员辈分级别相同的节点值。具体的代码如下:
template<class T>
inline void BinaryTree<T>::ShowAncestor(T target)
{
//target元素对应的目标节点
BNode<T>* targetNode = NULL;
//临时节点,用于遍历所有的树节点
BNode<T>* node = root;
//临时装载父节点的栈
Stack<BNode<T>*>* stack = new Stack<BNode<T>*>();
//用于装取后序遍历顺序的节点的栈
Stack<BNode<T>*>* outstack = new Stack<BNode<T>*>();
BNode<T>* temp =NULL;
while (node!=NULL||stack->getSize()> 0)
{
if (node!= NULL)
{
//找到T元素对应的树节点
if (node->t== target)
{
targetNode = node;
}
//父节点入栈
stack->push(node);
//节点入栈
outstack->push(node);
//临时节点指向弹出的父节点的右孩子
node = node->rightChild;
}
else
{
//弹出父节点
node = stack->pop();
//临时节点指向弹出的父节点的左孩子
node = node->leftChild;
}
}
while (outstack->getSize() > 0) {
//逆序打印
BNode<T>* bNode = outstack->pop();
//打印输出与T元素节点相同辈分级别的节点的元素值
if (bNode->generationLevel==targetNode->generationLevel)
{
cout << bNode->t;
}
}
}
接下来我们就开始实现查找某成员的所有长辈的功能,这个功能和寻找兄弟辈分的节点一样,我们先找到目标节点,然后输出比目标节点辈分级别低的节点即可。下面是具体的代码实现:
template<class T>
inline void BinaryTree<T>::FindAllAncestor(T target)
{
//target元素对应的目标节点
BNode<T>* targetNode = NULL;
//临时节点,用于遍历所有的树节点
BNode<T>* node = root;
//临时装载父节点的栈
Stack<BNode<T>*>* stack = new Stack<BNode<T>*>();
//用于装取后序遍历顺序的节点的栈
Stack<BNode<T>*>* outstack = new Stack<BNode<T>*>();
BNode<T>* temp = NULL;
while (node != NULL || stack->getSize() > 0)
{
if (node != NULL)
{
//找到T元素对应的树节点
if (node->t == target)
{
targetNode = node;
}
//父节点入栈
stack->push(node);
//节点入栈
outstack->push(node);
//临时节点指向弹出的父节点的右孩子
node = node->rightChild;
}
else
{
//弹出父节点
node = stack->pop();
//临时节点指向弹出的父节点的左孩子
node = node->leftChild;
}
}
while (outstack->getSize() > 0) {
//逆序打印
BNode<T>* bNode = outstack->pop();
//打印输出辈分级别小于target对应节点辈分级别的树节点的元素值
//比如target节点的辈分为3,那么就要打印输出辈分为1或2的节点的值
if (bNode->generationLevel < targetNode->generationLevel)
{
cout << bNode->t;
}
}
}
实现了所有要求的功能,最后不要忘记了销毁二叉树,释放空间,防止内存泄露。这里采用了递归遍历实现释放功能:
template<class T>
inline void BinaryTree<T>::destroyTree(BNode<T>* root)
{
if (root!=nullptr)
{
//递归销毁左子树
destroyTree(root->leftChild);
//递归销毁右子树
destroyTree(root->rightChild);
//释放根节点
delete root;
}
}
到此,我们的主体代码基本都完成了,现在开始测试:
测试代码为;
#include<iostream>
#include"Stack.hpp"
#include<string>
#include"BNode.hpp"
#include"BinaryTree.hpp"
using namespace std;
int main()
{
const char* p = "A(B(C,D(,E)),)";
BinaryTree<char> *tree = new BinaryTree<char>(p);
cout << "后序遍历非递归:";
tree->PosOrder();
cout << endl;
cout << "后序遍历递归:";
tree->PosOrderRe(tree->root);
cout << endl;
cout << "先序遍历非递归:";
tree->PreOrderNotRe();
cout << endl;
cout << "中序遍历非递归:";
tree->InOrder();
cout << endl;
cout << "B的兄弟:";
tree->ShowAncestor('B');
cout << endl;
cout << "E的兄弟:";
tree->ShowAncestor('E');
cout << endl;
cout << "C的长辈:";
tree->FindAllAncestor('C');
cout << endl;
cout << "E的长辈:";
tree->FindAllAncestor('E');
system("pause");
return 0;
}
运行结果:
下面附上完整的代码(使用自定义的栈,通用模板类,以.hpp结尾);
#pragma once
#include<iostream>
#include<string>
#include"LNode.hpp"
using namespace std;
template<class T>
class Stack
{
public:
Stack();
Stack(Stack<T> &list);
void push(T element);
T pop();
LNode<T>* getButton();
int getSize();
void clear();
Stack<T>& operator=(Stack<T> &list);
T getTop();
bool isEmpty();
~Stack();
private:
LNode<T> *buttom;
LNode<T> *top;
int size;
T element;
};
template<class T>
Stack<T>::Stack()
{
this->size = 0;
}
template<class T>
inline Stack<T>::Stack(Stack<T>& list)
{
int listsize = list.getSize();
LNode<T> *temp = list.getButton();
while (temp != NULL)
{
LNode<T> *node = new LNode<T>(temp->element);
if (this->size == 0)
{
top = node;;
buttom = node;
}
else {
top->next = node;
top = node;
}
this->size++;
temp = temp->next;
}
}
template<class T>
Stack<T>::~Stack()
{
this->clear();
if (this->buttom != NULL) {
delete this->buttom;
}
if (this->top != NULL) {
delete this->top;
}
}
template<class T>
inline void Stack<T>::push(T element)
{
LNode<T> *node = new LNode<T>(element);
if (this->size == 0)
{
top = node;
buttom = node;
}
else {
top->next= node;
top = node;
}
this->size++;
}
template<class T>
inline T Stack<T>::pop()
{
if (this->size == 0) {
return T();
}
else
{
T t = top->element;
this->size--;
LNode<T> *temp = buttom;
for (int i = 1; i < this->size; i++)
{
temp = temp->next;
}
top = temp;
return t;
}
}
template<class T>
inline LNode<T>* Stack<T>::getButton()
{
return buttom;
}
template<class T>
inline int Stack<T>::getSize()
{
return this->size;
}
template<class T>
inline void Stack<T>::clear()
{
LNode<T> *temp1 = buttom;
LNode<T> *temp2 = temp1;
while (temp1 != NULL)
{
temp1 = temp1->next;
delete temp2;
temp2 = temp1;
}
buttom = new LNode<T>();
top = new LNode<T>();
this->size = 0;
}
template<class T>
inline Stack<T>& Stack<T>::operator=(Stack<T> &list)
{
if (list == NULL)
{
return;
}
if (this->size != 0)
{
this->clear();
}
int listsize = list.getSize();
LNode<T> *temp = list.getButton();
while (temp != NULL)
{
LNode<T> *node = new LNode<T>(temp->element);
if (this->size == 0)
{
top = node;;
buttom = node;
}
else {
top->next = node;
top = node;
}
this->size++;
temp = temp->next;
}
return this;
}
template<class T>
inline T Stack<T>::getTop()
{
return top->element;
}
template<class T>
inline bool Stack<T>::isEmpty()
{
return this->size == 0;
}
#pragma once
#include<iostream>
using namespace std;
template<class T>
class LNode
{
public:
LNode();
LNode(T element);
~LNode();
public :
T element;
LNode<T>* next;
};
template<class T>
LNode<T>::LNode()
{
}
template<class T>
LNode<T>::LNode(T element)
{
this->element = element;
}
template<class T>
inline LNode<T>::~LNode()
{
}
#pragma once
template<class T>
class BNode
{
public:
BNode();
BNode(T t);
~BNode();
public:
/*左孩子*/
BNode<T> *leftChild;
/*右孩子*/
BNode<T> *rightChild;
/*j节点的值*/
T t;
/*该节点所在的辈分级数*/
int generationLevel;
};
template<class T>
inline BNode<T>::BNode()
{
}
template<class T>
inline BNode<T>::BNode(T t)
{
this->t = t;
}
template<class T>
inline BNode<T>::~BNode()
{
}
#pragma once
#include<iostream>
#include"BNode.hpp"
using namespace std;
template<class T>
class TempNode
{
public:
TempNode(BNode<T>* bnode,bool fla);
~TempNode();
BNode<T>* bnode;
bool fla;
};
template<class T>
inline TempNode<T>::TempNode(BNode<T>* bnode, bool fla)
{
this->bnode = bnode;
this->fla = fla;
}
template<class T>
inline TempNode<T>::~TempNode()
{
}
#pragma once
#include"Stack.hpp"
#include"BNode.hpp"
#include"TempNode.hpp"
#include<string>
using namespace std;
template<class T>
class BinaryTree
{
public:
BinaryTree(const char* str);
/*后序遍历非递归*/
void PosOrder();
/*后序遍历递归*/
void PosOrderRe(BNode<T>* root);
/*中序遍历非递归实现*/
void InOrder();
/*先序遍历非递归第一种实现*/
void PreOrderNotRe();
/*先序遍历非递归第二种实现*/
void PreOrderNotRe2();
/*输出节点obj的所有长辈*/
void FindAllAncestor(T obj);
/*输出节点ancestor的值及同辈的值,这里的T是默认为输入一个字符char,如果T是一个节点的话那么在比较相等的时候就要注意对应的转换,适当地改改这个函数就可以了*/
void ShowAncestor(T t);
/*二叉树的析构函数,用于销毁二叉树的节点*/
void destroyTree(BNode<T>* root);
~BinaryTree();
public:
BNode<T>* root = NULL; //树的根节点指针
};
template<class T>
inline BinaryTree<T>::BinaryTree(const char* str)
{
const char * p = str; //临时字符串指针
BNode<char>* node = NULL; // 临时节点指针
int k = 1; //判定是左孩子还是右孩子的标识:1为左孩子,2为右孩子
Stack<BNode<char>*> *stack = new Stack<BNode<char>*>(); //用于装取每个二叉树节点的栈
while (*p != '\0')
{
switch (*p)
{
case '(':
stack->push(node); //遇到‘('说明node节点为根节点
k = 1; //遇到‘(’说明下一个节点为左节点
break;
case ',':
k = 2; //遇到‘,’说明下一个节点为右节点
break;
case ')':
stack->pop(); //遇到‘)’弹出栈顶元素的根节点
break;
default:
node = new BNode<char>(*p); //创建节点
if (root == NULL) //第一个节点即为根节点
{
node->generationLevel = 1; //根节点的父辈级数为1
root = node;
}
else if (k == 1) //左节点
{
BNode<char>* topNode = stack->getTop(); //获取栈顶的根节点
node->generationLevel = topNode->generationLevel + 1;//该节点为左子树的节点,则辈分级别加1
topNode->leftChild = node; //根节点的左孩子
}
else if (k == 2) { //右节点
BNode<char>* topNode = stack->getTop(); //获取栈顶的根节点
node->generationLevel = topNode->generationLevel; //该节点为右孩子,则辈分级别和父节点一样
topNode->rightChild = node; //根节点的右孩子
}
break;
}
p++; //字符指针移动到下一个字符的位置
}
}
template<class T>
inline void BinaryTree<T>::PosOrder()
{
//使用两个栈来实现遍历
Stack<BNode<T>*> *stack = new Stack<BNode<T>*>();
//用于输出的栈
Stack<BNode<T>*> *outStack = new Stack<BNode<T>*>();
BNode<T>* node = root;
while (node != nullptr || stack->getSize() != 0)
{
if (node != NULL)
{
//父节点入栈
stack->push(node);
//节点入栈
outStack->push(node);
//临时节点指向父节点的右孩子
node = node->rightChild;
}
else
{
//弹出父节点
node = stack->pop();
//临时节点指向弹出的父节点的左孩子
node = node->leftChild;
}
}
//输出所有的节点,逆序输出
while (outStack->getSize() != 0)
{
BNode<T>* node = outStack->pop();
cout << node->t;
}
}
template<class T>
inline void BinaryTree<T>::PosOrderRe(BNode<T>* root)
{
//结束递归
if (root == NULL)
{
return;
}
//递归左子树
this->PosOrderRe(root->leftChild);
//递归右子树
this->PosOrderRe(root->rightChild);
//打印节点信息
cout << root->t;
}
template<class T>
inline void BinaryTree<T>::InOrder()
{
BNode<T>* node = root;
Stack<BNode<T>*> *stack = new Stack<BNode<T>*>();
while (node!=NULL||stack->getSize()>0)
{
//对每一棵树而言,都一直向左下走,直到走到最左下的叶子结点
while (node!=NULL)
{
stack->push(node);
node = node->leftChild;
}
if (stack->getSize()>0)
{
//中序遍历是第二次遇到该结点的时候输出,即结点出栈
node = stack->pop();
//进入最左下叶子结点的右孩子
cout << node->t;
//进入新一轮循环
node = node->rightChild;
}
}
}
template<class T>
inline void BinaryTree<T>::PreOrderNotRe()
{
//使用栈装取存有BNode节点和特定标识的临时节点
Stack<TempNode<T>*> *stack = new Stack<TempNode<T>*>();
//先将头结点入栈,并且设定标识为false
stack->push(new TempNode<T>(root, false));
while (stack->getSize() > 0)
{
//先将栈顶元素弹出
TempNode<T>* tempNode = stack->pop();
//如果临时节点中的BNode节点为空则跳过此次循环
if (tempNode->bnode == NULL)
{
continue;
}
//如果临时节点的标识为true则打印输出该节点的值
if (tempNode->fla == true)
{
cout << tempNode->bnode->t;
}
else {
//先将右节点的包装后的临时节点入栈
stack->push(new TempNode<T>(tempNode->bnode->rightChild, false));
//再将左节点的包装后的临时节点入栈
stack->push(new TempNode<T>(tempNode->bnode->leftChild, false));
//修改此刻临时节点的标识
tempNode->fla = true;
//将该临时节点重新入栈
stack->push(tempNode);
}
}
}
template<class T>
inline void BinaryTree<T>::PreOrderNotRe2()
{
if (root == NULL)
{
return;
}
BNode<T>* node = root;
Stack<BNode*> *stack = new Stack<BNode*>();
while (stack->getSize()>0||node!=NULL)
{
//对每一棵树而言,都一直向左下走,直到走到最左下的叶子结点
while (node!=NULL)
{
//先序遍历是第一次遇到该结点的时候输出,即结点入栈
cout << node->tl;
stack->push(node);
node = node->leftChild;
}
if (stack->getSize()>0)
{
//进入最左下叶子结点的右孩子
node = stack->pop();
node = node->rightChild;
}
//进入新一轮循环
}
}
template<class T>
inline void BinaryTree<T>::ShowAncestor(T target)
{
//target元素对应的目标节点
BNode<T>* targetNode = NULL;
//临时节点,用于遍历所有的树节点
BNode<T>* node = root;
//临时装载父节点的栈
Stack<BNode<T>*>* stack = new Stack<BNode<T>*>();
//用于装取后序遍历顺序的节点的栈
Stack<BNode<T>*>* outstack = new Stack<BNode<T>*>();
BNode<T>* temp =NULL;
while (node!=NULL||stack->getSize()> 0)
{
if (node!= NULL)
{
//找到T元素对应的树节点
if (node->t== target)
{
targetNode = node;
}
//父节点入栈
stack->push(node);
//节点入栈
outstack->push(node);
//临时节点指向弹出的父节点的右孩子
node = node->rightChild;
}
else
{
//弹出父节点
node = stack->pop();
//临时节点指向弹出的父节点的左孩子
node = node->leftChild;
}
}
while (outstack->getSize() > 0) {
//逆序打印
BNode<T>* bNode = outstack->pop();
//打印输出与T元素节点相同辈分级别的节点的元素值
if (bNode->generationLevel==targetNode->generationLevel)
{
cout << bNode->t;
}
}
}
template<class T>
inline void BinaryTree<T>::FindAllAncestor(T target)
{
//target元素对应的目标节点
BNode<T>* targetNode = NULL;
//临时节点,用于遍历所有的树节点
BNode<T>* node = root;
//临时装载父节点的栈
Stack<BNode<T>*>* stack = new Stack<BNode<T>*>();
//用于装取后序遍历顺序的节点的栈
Stack<BNode<T>*>* outstack = new Stack<BNode<T>*>();
BNode<T>* temp = NULL;
while (node != NULL || stack->getSize() > 0)
{
if (node != NULL)
{
//找到T元素对应的树节点
if (node->t == target)
{
targetNode = node;
}
//父节点入栈
stack->push(node);
//节点入栈
outstack->push(node);
//临时节点指向弹出的父节点的右孩子
node = node->rightChild;
}
else
{
//弹出父节点
node = stack->pop();
//临时节点指向弹出的父节点的左孩子
node = node->leftChild;
}
}
while (outstack->getSize() > 0) {
//逆序打印
BNode<T>* bNode = outstack->pop();
//打印输出辈分级别小于target对应节点辈分级别的树节点的元素值
//比如target节点的辈分为3,那么就要打印输出辈分为1或2的节点的值
if (bNode->generationLevel < targetNode->generationLevel)
{
cout << bNode->t;
}
}
}
template<class T>
inline void BinaryTree<T>::destroyTree(BNode<T>* root)
{
if (root!=nullptr)
{
//递归销毁左子树
destroyTree(root->leftChild);
//递归销毁右子树
destroyTree(root->rightChild);
//释放根节点
delete root;
}
}
template<class T>
inline BinaryTree<T>::~BinaryTree()
{
this->destroyTree(root);
}
温馨提示:通用的模板类和普通的类不一样,不能.h和cpp文件分离实现,要在同一个文件中书写声明和实现,否则就会在编译的时候发生错误。常用的通用模板的命名规范是以.hpp结尾文件,这样别人一看就知道这是一个模板类了。
欢迎各位指出其中的不足!