二叉树BinaryTree的C++实现
需要具备的基础知识
-
C++语法和STL
-
类模板和函数模板
-
二叉树的概念
-
二叉树的先序遍历、中序遍历和后序遍历
需求分析
-
打印:输出树的所有节点数据,如print(),无需输入参数
-
递归法先序遍历、中序遍历和后序遍历
-
迭代法(循环)遍历,stack
-
-
查找:输入val,查找树中是否有相同的节点数据(假设无重复数据),找到则返回目标节点的地址;未找到则返回NULL
-
插入:先查找目标节点,未找到返回false;找到目标节点,明确在目标节点的左或右插入新的节点;左插入新节点前判断目标节点的左指针域是否为NULL,NULL则插入,!NULL返回false;右插入新节点前判断目标节点的左指针域是否为NULL,NULL则插入,!NULL返回false
二叉树的节点定义
定义一个TreeNode的结构体模板,包括数据域、左指针域和右指针域,在结构体中完成节点的构造。
//
//定义一个树的节点模板
//
template<class Elem>
struct TreeNode{
Elem data;
TreeNode<Elem> *left;
TreeNode<Elem> *right;
TreeNode(Elem val){
data = val;
left = right = nullptr;
}
};
二叉树的定义
定义一个二叉树BinTree的模板类,私有成员为树的根节点m_root,无参构造,有参构造。
//
//定义一个二叉树的模板类
//
template<class Elem>
class BinTree{
public:
BinTree(){
m_root = nullptr;
}
BinTree(Elem val){
m_root = new TreeNode<Elem>(val);
}
~BinTree(){
}
private:
TreeNode<Elem> *m_root;
};
打印需求实现
打印树的数据需要遍历所有节点,利用递归法或迭代法都能实现,同时要注意对外提供给用户的公有函数接口要简单。
- 利用递归法实现打印功能
//函数声明
//受保护的内部函数
protected:
void rPreOrder(TreeNode<Elem> *root) const;
void rInOrder(TreeNode<Elem> *root) const;
//对外接口函数调用内部函数
public:
void rPrint() const;
//
//打印函数实现
//
template<class Elem>
void BinTree<Elem>::rPreOrder(TreeNode<Elem> *root) const{
if (root == nullptr){
return ;
}
cout << root->data << ' ';
rPreOrder(root->left);
rPreOrder(root->right);
}
template<class Elem>
void BinTree<Elem>::rInOrder(TreeNode<Elem> *root) const{
if (root == nullptr){
return ;
}
rInOrder(root->left);
cout << root->data << ' ';
rInOrder(root->right);
}
template<class Elem>
void BinTree<Elem>::rPrint() const{
cout << "递归先序遍历:";
rPreOrder(m_root);
cout << endl;
cout << "递归中序遍历:";
rInOrder(m_root);
cout << endl;
}
查找需求实现
输入val,查找树中是否有相同的节点数据(假设无重复数据),找到则返回目标节点的地址;未找到则返回NULL
//函数声明
//受保护的内部函数
protected:
TreeNode<Elem>* rFindVal(TreeNode<Elem> *root, Elem val) const;
//对外接口函数调用内部函数
public:
TreeNode<Elem>* findVal(Elem val) const;
//
//查找函数实现
//
template<class Elem>
TreeNode<Elem>* BinTree<Elem>::rFindVal(TreeNode<Elem> *root, Elem val) const{
if(!root){
return nullptr;
}
//先找根节点的数据是否和val相同
if(val == root->data){
return root;
}
//再从左子树中查找
TreeNode<Elem> *objectNode = rFindVal(root->left, val);
//若在左子树中找到目标节点,返回节点地址;若在左子树中没有找到目标节点,从右子树中查找
return objectNode ? objectNode : rFindVal(root->right, val);
}
template<class Elem>
TreeNode<Elem>* BinTree<Elem>::findVal(Elem val) const{
//调用内部定义的rFindVal
return rFindVal(m_root, val);
}
插入需求实现
-
先查找目标节点,未找到返回false;
-
找到目标节点,明确在目标节点的左或右插入新的节点;
-
左插入新节点前判断目标节点的左指针域是否为NULL,NULL则插入,!NULL返回false;
-
右插入新节点前判断目标节点的左指针域是否为NULL,NULL则插入,!NULL返回false。
-
//函数声明
public:
bool insert(Elem obj, int LeftOrRight, Elem val);;
//
//插入函数实现
//
template<class Elem>
bool BinTree<Elem>::insert(Elem obj, int LeftOrRight, Elem val){
//调用查找函数查找目标节点obj,找到返回地址,没有找到返回false
TreeNode<Elem> *objectNode = findVal(obj);
//如果没有找到目标节点obj,返回false
if (!objectNode){
return false;
}
//找到目标节点后,根据参数LeftOrRight确定在目标节点的左或右插入新的节点
if (LeftOrRight == 0){
//如果目标节点存在左节点,不能插入新节点,返回false
if (objectNode->left){
return false;
}
objectNode->left = new TreeNode<Elem>(val);
}
else{
//如果目标节点存在右节点,不能插入新节点,返回false
if (objectNode->right){
return false;
}
objectNode->right = new TreeNode<Elem>(val);
}
return true;
}
代码测试
int main(){
BinTree<int> bt(11);
bt.insert(11, 0, 22);
bt.insert(11, 1, 33);
bt.insert(22, 0, 44);
bt.insert(22, 1, 55);
bt.insert(33, 0, 66);
bt.insert(33, 1, 77);
bt.rPrint();
}
后续会介绍二叉搜索树和平衡二叉树,敬请期待。
完整的代码后面会上传到github供参考。