二叉树的基本操作的实现

二叉树的基本操作的实现

前言

本文是基于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值;
      创建二叉树,键盘输入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;
}

写在最后

**本文仅供参考,若有不足之处,望各位多多指教,谢谢!**
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值