- 本文代码下载:
- 方式1:公众号【多栖技术控小董】回复【3584】免费获取下载链接
- 方式2:CSDN下载链接:https://download.csdn.net/download/qq_41453285/12118027
- 方式3:Github下载链接(进入之后下载里面的linkedBinaryTree.zip文件):https://github.com/dongyusheng/Interview-algorithm/tree/master/c%2B%2BAlgorithms
一、二叉树的常用操作
- 确定高度
- 确定元素数目
- 复制
- 显示或打印二叉树
- 确定两棵二叉树是否一样
- 删除整棵树
二、二叉树抽象数据类型(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函数的执行流程如下