C++(数据结构与算法):37---二叉树的实现(链表形式)

一、二叉树的常用操作

  • 确定高度
  • 确定元素数目
  • 复制
  • 显示或打印二叉树
  • 确定两棵二叉树是否一样
  • 删除整棵树

二、二叉树抽象数据类型(ADT)

三、二叉树的抽象类(binaryTree)

  • 根据上面的抽象数据类型,我们定义了如下的抽象类
template<class T>
class binaryTree
{
public:
	virtual ~binaryTree() = 0;

	virtual bool empty()const = 0; //二叉树是否为空
	virtual int size()const = 0;   //二叉树大小

	virtual void preOrder(void(*)(T*)) = 0;   //前序遍历二叉树
	virtual void inOrder(void(*)(T*)) = 0;    //中序遍历二叉树
	virtual void postPOrder(void(*)(T*)) = 0; //后续遍历二叉树
	virtual void levelOrder(void(*)(T*)) = 0; //层数遍历二叉树
};

四、编码实现

头文件定义 

#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <functional>
#include <queue>
#include <exception>
#include <stdexcept>

using std::cout;
using std::cin;
using std::endl;
using std::string;
using std::max;
using std::pair;
using std::function;
using std::queue;

异常类定义

class treeEmpty
{
public:
	treeEmpty(const char* theMessage = "The tree is empty") :message(theMessage) {

	}
	const char* what() { return this->message.c_str(); }
private:
	std::string message;
};

二叉树节点(binaryTreeNode)

template<typename T>
struct binaryTreeNode
{
	T element; //节点元素
	struct binaryTreeNode<T>* leftChild, *rightChild; //节点的左孩子和右孩子指针

	//以下为3种构造函数
	binaryTreeNode() {
		this->leftChild = this->rightChild = nullptr;
	}

	binaryTreeNode(const T& theElement) :element(theElement) {
		this->leftChild = this->rightChild = nullptr;
	}

	binaryTreeNode(const T& theElement,struct binaryTreeNode<T>* theLeftChild,struct binaryTreeNode<T>* theRightChild) :element(theElement) {
		this->leftChild = theLeftChild;
		this->rightChild = theRightChild;
	}
};

二叉树抽象类(binaryTree)

template<typename T>
class binaryTree
{
public:
	virtual ~binaryTree() {}

	virtual bool empty()const = 0; //二叉树是否为空
	virtual int size()const = 0;   //二叉树大小

	virtual void preOrder(void(*)(T*)) = 0;   //前序遍历二叉树
	virtual void inOrder(void(*)(T*)) = 0;    //中序遍历二叉树
	virtual void postOrder(void(*)(T*)) = 0; //后续遍历二叉树
	virtual void levelOrder(void(*)(T*)) = 0; //层数遍历二叉树
};

二叉树的链表实现(linkedBinaryTree)

构造函数、析构函数、清除函数(erase())、删除节点函数(++dispose())

  • 构造函数将根节点置空,树的大小置位0
  • 析构函数直接调用erase清除函数
  • erase()函数:清除函数利用后续遍历(后续遍历见下)整个树的每个节点,然后在每个节点上调用__dispose()函数
  • __dispose()函数:传入一个节点,删除该节点
template<typename T>
class linkedBinaryTree :public binaryTree<binaryTreeNode<T>>
{
public:
	linkedBinaryTree() {
		this->root = nullptr;
		this->treeSize = 0;
	}
	~linkedBinaryTree() { erase(); }  //析构函数,直接调用erase成员函数

	//清空整个数(后序遍历整个树,并且每个节点执行__dispose函数)
	void erase() { 
		this->postOrder(this->__dispose);
		this->root = NULL;
		this->treeSize = 0;
	}

protected:
	binaryTreeNode<T>* root;  //根节点
	int treeSize;             //树的节点个数
	static void(*__visit)(binaryTreeNode<T>* theNode);//一个函数指针,参数是一个binaryTreeNode类型

protected:
	static void __dispose(binaryTreeNode<T>* theNode) { delete theNode; theNode = NULL; }  //释放参数所指的节点
};

__visit函数指针

  • 一个函数指针,参数是一个节点,将一个特定类型的函数赋值给该指针时,用来对参数所指的节点进行删除/遍历

判断是否为空(empty())、返回树大小(size())、返回根节点(rootNode())

  • empty():判断树是否为空
  • size():返回树的大小
  • rootNode():返回根节点
template<typename T>
class linkedBinaryTree :public binaryTree<binaryTreeNode<T>>
{
public:
	bool empty()const { return (this->treeSize == 0); } //判断树是否为空
	int size()const { return this->treeSize; }   //返回树的大小
	binaryTreeNode<T>* rootNode()const { return ((this->treeSize == 0) ? NULL : this->root;) }//返回根节点
};

返回树的高度(height()、__height())

  • height():返回树的高度,直接调用__height()函数
template<typename T>
class linkedBinaryTree :public binaryTree<binaryTreeNode<T>>
{
public:
	int height()const { return __height(this->root); }   //返回树的高度
	
protected:
	
	static int __height(binaryTreeNode<T>* theNode); //返回树的高度
};

//返回树的高度(递归)
template<typename T>
int linkedBinaryTree<T>::__height(binaryTreeNode<T>* theNode)
{
	if (theNode == nullptr)
		return 0;
	int leftSize = __height(theNode->leftChild);  //递归左子树的高度
	int rightSize = __height(theNode->rightChild);//递归右子树的高度

	//返回最大的高度(++是因为需要加上根节点)
	return (std::max(leftSize, rightSize) + 1);
}

构造树函数(makeTree)

  • 此函数用来初始化一棵树,在下面main函数使用时介绍
template<typename T>
void linkedBinaryTree<T>::makeTree(const T& element,linkedBinaryTree<T>& left, linkedBinaryTree<T>& right)
{
	this->root = new binaryTreeNode<T>(element, left.root, right.root);
	this->treeSize = left.treeSize + right.treeSize + 1;

	left.root = right.root = nullptr;
	left.treeSize = right.treeSize = 0; 
}

前序、中序、后续、层次遍历树

  • 将__output函数赋值给__visit函数用来打印节点信息
template<typename T>
class linkedBinaryTree :public binaryTree<binaryTreeNode<T>>
{
public:
	//以下四个函数分别为:前序、中序、后序、层次遍历二叉树,遍历每个节点时再执行参数所指的函数
	virtual void preOrder(void(*theVisit)(binaryTreeNode<T>*)) override {
		__visit = theVisit;    //为函数指针赋值,将来每个节点就执行这个函数__visit函数
		__preOrder(this->root);//层次遍历每个节点,并在遍历每个节点时执行
	}
	virtual void inOrder(void(*theVisit)(binaryTreeNode<T>*)) override {
		__visit = theVisit;
		__inOrder(this->root);
	}
	virtual void postOrder(void(*theVisit)(binaryTreeNode<T>*)) override {
		__visit = theVisit;
		__postOrder(this->root);
	}
	virtual void levelOrder(void(*theVisit)(binaryTreeNode<T>*)) override;//层次遍历比较复杂,下面介绍

	//分别打印出前序、中序、后序、层次遍历二叉树的结果
	void preOrderOutput() { this->preOrder(__output); std::cout << std::endl; }
	void inOrderOutput() { this->inOrder(__output); std::cout << std::endl; }
	void postOrderOutput() { this->postOrder(__output); std::cout << std::endl; }
	void levelOrderOutput() { this->levelOrder(__output); std::cout << std::endl; }

protected:
	binaryTreeNode<T>* root;  //根节点
	static void(*__visit)(binaryTreeNode<T>* theNode);//一个函数指针,参数是一个binaryTreeNode类型
protected:
	static void __preOrder(binaryTreeNode<T>* theNode);
	static void __inOrder(binaryTreeNode<T>* theNode);
	static void __postOrder(binaryTreeNode<T>* theNode);
	static void __output(binaryTreeNode<T>* theNode) { std::cout << theNode->element << " "; } //打印参数所指的节点的值
};


//前序遍历二叉树的每个节点,遍历每个节点时执行参数所指的函数(下同)
template<typename T>
void linkedBinaryTree<T>::__preOrder(binaryTreeNode<T>* theNode)
{
	if (theNode) {
		linkedBinaryTree<T>::__visit(theNode);
		__preOrder(theNode->leftChild);
		__preOrder(theNode->rightChild);
	}
}

//中序遍历二叉树的每个节点,遍历每个节点时执行参数所指的函数
template<typename T>
void linkedBinaryTree<T>::__inOrder(binaryTreeNode<T>* theNode)
{
	if (theNode) {
		__inOrder(theNode->leftChild);
		linkedBinaryTree<T>::__visit(theNode);
		__inOrder(theNode->rightChild);
	}
}

//后序遍历二叉树的每个节点,遍历每个节点时执行参数所指的函数
template<typename T>
void linkedBinaryTree<T>::__postOrder(binaryTreeNode<T>* theNode)
{
	if (theNode) {
		__postOrder(theNode->leftChild);
		__postOrder(theNode->rightChild);
		linkedBinaryTree<T>::__visit(theNode);
	}
}

//层次遍历二叉树的每个节点,遍历每个节点时执行参数所指的函数
template<typename T>
void linkedBinaryTree<T>::levelOrder(void(*theVisit)(binaryTreeNode<T>*))
{
	std::queue<binaryTreeNode<T>*> q;
	binaryTreeNode<T> *theNode = root;
	while (theNode != NULL)
	{
		theVisit(theNode);

		if (theNode->leftChild != NULL)
			q.push(theNode->leftChild);
		if (theNode->rightChild != NULL)
			q.push(theNode->rightChild);
		
		if (q.empty())
			return;

		theNode = q.front();
		q.pop();
	}
}

 主函数(main.cpp)

int main()
{
	linkedBinaryTree<int> a, x, y, z;
	y.makeTree(1, a, a);
	z.makeTree(2, a, a);
	x.makeTree(3, y, z);
	y.makeTree(4, x, a);

	cout << "Number of nodes = ";
	cout << y.size() << endl;
	cout << "height = ";
	cout << y.height() << endl;

	cout << "Preorder sequence is ";
	y.preOrderOutput();

	cout << "Inorder sequence is ";
	y.inOrderOutput();

	cout << "Postorder sequence is ";
	y.postOrderOutput();

	cout << "Level order sequence is ";
	y.levelOrderOutput();

	return 0;
}
  • makeTree函数的执行流程如下

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

董哥的黑板报

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值