二叉树的基本操作的实现
前言
本文是基于c/c++的语法,代码实现了二叉树的基本操作。同时全文是个人学习二叉树的认识,可能存在许多不足的地方,还望各位大佬耐心指出。
二叉树的基本操作
- 遍历
- 前序遍历
- 中序遍历
- 后序遍历
- 层序遍历
- 计算层数
- 计算叶节点数
- 获取左右子节点
- 获取双亲节点
- 获取兄弟节点
二叉树的存储结构
数据结构的分为很多种,多数是源自于他的存储结构的差异,所以存储结构对于一个数据结构来说是很重要,他同时决定了后序数据结构的基本操作的实现步骤。这里将属性和方法是分开写的,专门定义一个方法类BinaryTree[1]。
*/
template<typename ElemType>
class BinaryTreeNode {
public:
ElemType val; // 节点的data部分
BinaryTreeNode<ElemType> * left; // 左子结点
BinaryTreeNode<ElemType> * right; // 右子结点
BinaryTreeNode(){}
BinaryTreeNode(ElemType el) :val(el){}
};
遍历
遍历几乎是所有数据结构都有的基本操作,二叉树的遍历是所有数据结构中,遍历方式较多一个,下面分别介绍关于二叉树遍历的四种方式
- 前序遍历
template<typename ElemType>
void BinaryTree<ElemType>::FrontTravelBiTree(BinaryTreeNode<ElemType>* myBinaryTree) {
if (!myBinaryTree) return;
cout << myBinaryTree->val << ' ';
FrontTravelBiTree(myBinaryTree->left);
FrontTravelBiTree(myBinaryTree->right);
}
- 中序遍历
template<typename ElemType>
void BinaryTree<ElemType>::MiddleTravelBiTree(BinaryTreeNode<ElemType>* myBinaryTree) {
if (!myBinaryTree) return;
MiddleTravelBiTree(myBinaryTree->left);
cout << myBinaryTree->val << ' ';
MiddleTravelBiTree(myBinaryTree->right);
}
- 后序遍历
template<typename ElemType>
void BinaryTree<ElemType>::BackTravelBiTree(BinaryTreeNode<ElemType>* myBinaryTree) {
if (!myBinaryTree) return;
BackTravelBiTree(myBinaryTree->left);
BackTravelBiTree(myBinaryTree->right);
cout << myBinaryTree->val << ' ';
}
- 层序遍历
template<typename ElemType>
void BinaryTree<ElemType>::FloorTravelBinaryTree(BinaryTreeNode<ElemType>* myBinaryTree) {
if (!myBinaryTree) return;
queue<BinaryTreeNode<ElemType>*> myQueue;
myQueue.push(myBinaryTree);
while (!myQueue.empty()) {
BinaryTreeNode<ElemType>* el = myQueue.front();
cout << el->val << ' ';
if (el->left) myQueue.push(el->left);
if (el->right) myQueue.push(el->right);
myQueue.pop();
}
}
计算层数
根据层序遍历的思想,进行计算
template<typename ElemType>
int BinaryTree<ElemType>::CalculateFloor(BinaryTreeNode<ElemType>* myBinaryTree) {
if (!myBinaryTree) return 0;
int floor = 0;
queue<BinaryTreeNode<ElemType>*> myQueue;
vector<BinaryTreeNode<ElemType>*> myVector;
myQueue.push(myBinaryTree);
while (!myQueue.empty()) {
while (!myQueue.empty()) {
BinaryTreeNode<ElemType>* el = myQueue.front();
if (el->left) myVector.push_back(el->left);
if (el->right) myVector.push_back(el->right);
myQueue.pop();
}
++floor;
for (int i = 0; i < myVector.size(); ++i) {
myQueue.push(myVector[i]);
}
myVector.clear();
}
return floor;
}
计算叶子节点数
叶节点的特点就是没有子节点,可以根据前面的几种遍历思想解决,这里是根据前序遍历的思想实现的。
template<typename ElemType>
int BinaryTree<ElemType>::CalculateLeaveNode(BinaryTreeNode<ElemType>* myBinaryTree) {
int sum = 0;
if (!myBinaryTree) return 0;
if (!(myBinaryTree->left || myBinaryTree->right)) return 1;
sum += CalculateLeaveNode(myBinaryTree->left);
sum += CalculateLeaveNode(myBinaryTree->right);
return sum;
}
获取左右子节点
这里是先通过节点的val值,找到对应的节点(根据前序遍历的方式寻找), 然后查看是否有左右子节点。这里用一个自定义辅助函数FindNode[1] 查找到相应的节点,然后直接获取子节点。
- 获取左子节点
template<typename ElemType>
BinaryTreeNode<ElemType> * BinaryTree<ElemType>::LeftChild(BinaryTreeNode<ElemType>* myBinaryTree, ElemType e) {
BinaryTreeNode<ElemType> * res = FindNode(myBinaryTree, e);
if (!res) return nullptr;
return res->left;
}
- 获取右子节点
template<typename ElemType>
BinaryTreeNode<ElemType> * BinaryTree<ElemType>::RightChild(BinaryTreeNode<ElemType>* myBinaryTree, ElemType e) {
BinaryTreeNode<ElemType> * res = FindNode(myBinaryTree, e);
if (!res) return nullptr;
return res->right;
}
获取双亲节点
双亲节点其实就是父节点,显然一个二叉树的根节点是没有父节点的,其余节点都存在一个父节点。同样这里也自定义一个辅助函数FindParentNode[3] 实现父节点的查询操作。
template<typename ElemType>
BinaryTreeNode<ElemType> * BinaryTree<ElemType>::Parent(BinaryTreeNode<ElemType>* myBinaryTree, ElemType e) {
if (!myBinaryTree) return nullptr;
return FindParentNode(myBinaryTree, nullptr, e);
}
获取兄弟节点
由于二叉树的父节点最多最有两个子节点,所以一个节点要么有一个左兄弟,要么有一个右兄弟,但是不可能同时存在两个,所以在判断是否存在对应兄弟节点时,需要先知道自己是父节点的左孩子还是右孩子。
- 获取左兄弟节点
template<typename ElemType>
BinaryTreeNode<ElemType> * BinaryTree<ElemType>::LeftSibling(BinaryTreeNode<ElemType>* myBinaryTree, ElemType e) {
if (!myBinaryTree) return nullptr;
BinaryTreeNode<ElemType>* parent = Parent(myBinaryTree, e);
if (parent && e == parent->right->val) return parent->left;
else return nullptr;
}
- 获取右兄弟节点
template<typename ElemType>
BinaryTreeNode<ElemType> * BinaryTree<ElemType>::RightSibling(BinaryTreeNode<ElemType>* myBinaryTree, ElemType e) {
if (!myBinaryTree) return nullptr;
BinaryTreeNode<ElemType>* parent = Parent(myBinaryTree, e);
if (parent && e == parent->left->val) return parent->right;
else return nullptr;
}
测试
BinaryTreeNode<string> *myTreeNode = new BinaryTreeNode<string>;
BinaryTree<string> * myTree = new BinaryTree<string>;
string val, curVal, siblingVal;
// 键盘输入值,前序遍历的方式创建二叉树
myTree->CreateBinaryTree(myTreeNode);
system("cls");
// 遍历结果
cout << "前序遍历:";
myTree->FrontTravelBiTree(myTreeNode);
cout << "\n中序遍历:";
myTree->MiddleTravelBiTree(myTreeNode);
cout << "\n后序遍历:";
myTree->BackTravelBiTree(myTreeNode);
// 计算层数
cout << "\n当前二叉树有" << myTree->CalculateFloor(myTreeNode) << "层" << endl;
// 计算叶结点树
cout << "当前二叉树叶结点有" << myTree->CalculateLeaveNode(myTreeNode) << "个" << endl;
cout << "输入\'0\'进行查询...";
cin >> val;
system("cls");
// 获取左孩子
cout << "请输入要获取左孩子的节点val值:" << endl;
cin >> val;
BinaryTreeNode<string> * leftChild = myTree->LeftChild(myTreeNode, val);
if (leftChild) cout << "val=" << val << "的节点左孩子的val为:" << leftChild->val << endl;
else cout << "查询的节点没有左孩子" << endl;
// 获取右孩子
cout << "请输入要获取右孩子的节点val值:" << endl;
cin >> val;
BinaryTreeNode<string> * rightChild = myTree->RightChild(myTreeNode, val);
if (rightChild) cout << "val=" << val << "的节点右孩子的val为:" << rightChild->val << endl;
else cout << "查询的节点没有右孩子" << endl;
cout << "输入\'0\'进行查询...";
cin >> val;
system("cls");
// 双亲节点
cout << "请输入要获取双亲的节点val值:" << endl;
cin >> curVal;
BinaryTreeNode<string> * parentNode = myTree->Parent(myTreeNode, curVal);
if (parentNode) cout << "查询节点的父节点val为:" << parentNode->val << endl;
else cout << "查询节点为根节点或不存在" << endl;
cout << "输入\'0\'进行查询...";
cin >> val;
system("cls");
cout << "请输入要获取左兄弟的节点val值:" << endl;
cin >> siblingVal;
BinaryTreeNode<string> * leftSibling = myTree->LeftSibling(myTreeNode, siblingVal);
if (leftSibling) cout << "查询节点的左兄弟结点val值为:" << leftSibling->val << endl;
else cout << "查询节点没有左兄弟节点" << endl;
cout << "请输入要获取右兄弟的节点val值:" << endl;
cin >> siblingVal;
BinaryTreeNode<string> * rightSibling = myTree->RightSibling(myTreeNode, siblingVal);
if (rightSibling) cout << "查询节点的右兄弟结点val值为:" << rightSibling->val << endl;
else cout << "查询节点没有右兄弟节点" << endl;
- 运行结果截图
-
创建二叉树:键盘输入val值;
- 二叉树视图
- 二叉树视图
-
遍历结果
-
获取子节点
-
获取双亲节点
-
获取兄弟节点
-
注释
【1】:class BinaryTree;
template<typename ElemType>
class BinaryTree {
public:
BinaryTree() {}
void CreateBinaryTree(BinaryTreeNode<ElemType>*&); // 手动创建二叉树
void FrontTravelBiTree(BinaryTreeNode<ElemType>*); // 前序遍历
void MiddleTravelBiTree(BinaryTreeNode<ElemType>*); // 中序遍历
void BackTravelBiTree(BinaryTreeNode<ElemType>*); // 后序遍历
void FloorTravelBinaryTree(BinaryTreeNode<ElemType>*); // 层序遍历
int CalculateFloor(BinaryTreeNode<ElemType>*); // 计算层数
int CalculateLeaveNode(BinaryTreeNode<ElemType>*); // 计算叶节点数
static BinaryTreeNode<ElemType> * FindNode(BinaryTreeNode<ElemType>*, ElemType); // 寻找节点
BinaryTreeNode<ElemType> * FindParentNode(BinaryTreeNode<ElemType>*, BinaryTreeNode<ElemType>*, ElemType); // 寻找父节点
BinaryTreeNode<ElemType> * LeftChild(BinaryTreeNode<ElemType>*, ElemType); // 寻找左孩子
BinaryTreeNode<ElemType> * RightChild(BinaryTreeNode<ElemType>*, ElemType); // 寻找右孩子
BinaryTreeNode<ElemType> * Parent(BinaryTreeNode<ElemType>*, ElemType); // 寻找双亲节点
BinaryTreeNode<ElemType> * LeftSibling(BinaryTreeNode<ElemType>*, ElemType); // 寻找左兄弟节点
BinaryTreeNode<ElemType> * RightSibling(BinaryTreeNode<ElemType>*, ElemType); // 寻找右兄弟节点
};
【2】FindNode(value1,value2);
template<typename ElemType>
BinaryTreeNode<ElemType> * BinaryTree<ElemType>::FindNode(BinaryTreeNode<ElemType>* myBinaryTree, ElemType e) {
if (!myBinaryTree) return nullptr;
if (e == myBinaryTree->val) return myBinaryTree;
BinaryTreeNode<ElemType> * res = nullptr;
res = FindNode(myBinaryTree->left, e);
if (!res) res = FindNode(myBinaryTree->right, e);
return res;
}
【3】 FindParentNode(value1,value2,value3);
template<typename ElemType>
BinaryTreeNode<ElemType> * BinaryTree<ElemType>::FindParentNode(BinaryTreeNode<ElemType>* curNode, BinaryTreeNode<ElemType>* preNode, ElemType e) {
if (!curNode) return nullptr;
if (curNode && e == curNode->val) return preNode;
BinaryTreeNode<ElemType> * res = FindParentNode(curNode->left, curNode, e);
if(!res) res = FindParentNode(curNode->right, curNode, e);
return res;
}
写在最后
**本文仅供参考,若有不足之处,望各位多多指教,谢谢!**