《C++实现数据结构》:二叉树
来源:互联网 发布:江苏省人口普查数据 编辑:程序博客网 时间:2024/06/10 00:25
二叉树的定义以及性质在之前的博客里已经说过了,今天来用C++实现二叉树。提供先序遍历、中序遍历、后序遍历的递归和非递归的两种实现方式,也提供了层次遍历的用队列实现方式。详细的看代码学习吧,关键注释都有加上了。
————————————————————2017.4.4补充————————————————————
今天补充了反转二叉树的实现,提供递归和非递归两个版本。
————————————————————————————————————————————————
//// Created by huxijie on 17-3-20.// 二叉树#include <iostream>#include <stack>#include <queue>using namespace std;//二叉树结点类template <typename T>struct BTNode{ T elemet; BTNode<T>* lChild,*rChild; BTNode() { lChild = rChild = NULL; } BTNode(const T& x,BTNode<T>* l, BTNode<T> *r) { elemet = x; lChild = l; rChild = r; }};//二叉树类template <typename T>class BinaryTree{private: BTNode<T>* root; void Clear(BTNode<T>* t); void PreOrder(void (*Visit)(T &x),BTNode<T> *r); void InOrder(void (*Visit)(T &x),BTNode<T> *r); void PostOrder(void (*Visit)(T &x),BTNode<T> *r); void LayerOrder(void (*Visit)(T &x), BTNode<T> *r); int Size(BTNode<T>* r); BTNode<T>* Copy(BTNode<T> *r); BTNode<T>* InvertTree(BTNode<T> *root);public: BinaryTree(); ~BinaryTree(); bool IsEmpty() const; void Clear(); //移去所有结点,成为空二叉树 bool Root(T& x) const; //若二叉树非空,则x为根的值,并返回true //构造一棵二叉树,根的值为x,以left和right为左右子树 void MakeTree(const T& x,BinaryTree<T>& left,BinaryTree<T>& right); void PreOrder(void (*Visit)(T &x)); //先序遍历 void InOrder(void (*Visit)(T &x)); //中序遍历 void PostOrder(void (*Visit)(T &x)); //后序遍历 void LayerOrder(void (*Visit)(T &x)); //层次遍历 int Size(); //结点个数 BTNode<T>* Copy(); //二叉树的复制 void InvertTree(); //反转二叉树};template <typename T>BinaryTree<T>::BinaryTree() { root = NULL;}template <typename T>BinaryTree<T>::~BinaryTree() { Clear();}template <typename T>bool BinaryTree<T>::IsEmpty() const { if (root == NULL) { return true; } else { return false; }}//递归实现清空二叉树template <typename T>void BinaryTree<T>::Clear(BTNode<T> *t) { if (!t) { return; } else { Clear(t->lChild); Clear(t->rChild); delete (t); t = NULL; }}template <typename T>void BinaryTree<T>::Clear() { Clear(root);}template <typename T>bool BinaryTree<T>::Root(T &x) const { if (IsEmpty()) { return false; }else { x = root->elemet; return true; }}template <typename T>void BinaryTree<T>::MakeTree(const T &x, BinaryTree<T> &left, BinaryTree<T> &right) { if (root || &left == &right) { //若root不空则返回,若左右子树相同则返回,不构造树 return; } root = new BTNode<T>(x, left.root, right.root); left.root = NULL; right.root = NULL;}//访问元素的函数,作为参数传入遍历函数中template <typename T>void Visit(T &x) { cout << x << " ";}////递归实现先序遍历//template <typename T>//void BinaryTree<T>::PreOrder(void (*Visit)(T &x),BTNode<T> *r) {// if (r) {// Visit(r->elemet);// PreOrder(Visit, r->lChild);// PreOrder(Visit, r->rChild);// }//}//非递归实现先序遍历template <typename T>void BinaryTree<T>::PreOrder(void (*Visit)(T &x),BTNode<T> *r) { if (r == NULL) { return; } BTNode<T>* p = r; stack<BTNode<T> *> mystack; while (p != NULL || !mystack.empty()) { //边遍历边打印,并存入栈中,以后需要通过这些结点进入右子树 while (p != NULL) { Visit(p->elemet); mystack.push(p); p = p->lChild; } //当p为空时,说明根和左子树已经遍历完了,需要进入右子树了 if (!mystack.empty()) { p = mystack.top(); mystack.pop(); p = p->rChild; } }}template <typename T>void BinaryTree<T>::PreOrder(void (*Visit)(T &)) { PreOrder(Visit, root);}////递归实现中序遍历//template <typename T>//void BinaryTree<T>::InOrder(void (*Visit)(T &), BTNode<T> *r) {// if (r) {// InOrder(Visit, r->lChild);// Visit(r->elemet);// InOrder(Visit, r->rChild);// }//}//非递归实现中序遍历template <typename T>void BinaryTree<T>::InOrder(void (*Visit)(T &), BTNode<T> *r) { if (r == NULL) { return; } BTNode<T> *p = r; stack<BTNode<T>*> mystack; while (p != NULL || !mystack.empty()) { //一直遍历到最后一棵左子树,边遍历边保存根结点到栈中 while (p != NULL) { mystack.push(p); p = p->lChild; } //当p为空时,说明已经到达最后一棵左子树了,这时需要出栈了 if (!mystack.empty()) { p = mystack.top(); mystack.pop(); Visit(p->elemet); //进入右子树,开始新的一轮左子树遍历 p = p->rChild; } }}template <typename T>void BinaryTree<T>::InOrder(void (*Visit)(T &)) { InOrder(Visit, root);}////递归实现后序遍历//template <typename T>//void BinaryTree<T>::PostOrder(void (*Visit)(T &), BTNode<T> *r) {// if (r) {// PostOrder(Visit, r->lChild);// PostOrder(Visit, r->rChild);// Visit(r->elemet);// }//}//非递归实现后序遍历template <typename T>void BinaryTree<T>::PostOrder(void (*Visit)(T &), BTNode<T> *r) { if (r == NULL) { return; } stack<BTNode<T>*> mystack; BTNode<T>* pCur = r; //当前访问结点 BTNode<T>* pLast = NULL; //上次访问结点 //一直遍历到最后一棵左子树,边遍历边保存根结点到栈中 while (pCur != NULL) { mystack.push(pCur); pCur = pCur->lChild; } //已经遍历到最后一棵左子树了,接下来从栈中取结点 while (!mystack.empty()) { pCur = mystack.top(); mystack.pop(); //一个根结点被访问的前提是:无右子树或者右子树已被访问过 if (pCur->rChild == NULL || pCur->rChild == pLast) { Visit(pCur->elemet); //修改最近被访问的结点 pLast = pCur; } else { //先进入右子树 mystack.push(pCur); //根结点重新入栈 pCur = pCur->rChild; //进入右子树 while (pCur != NULL) { //开始在右子树中一直遍历到最后一棵左子树 mystack.push(pCur); pCur = pCur->lChild; } } }}template <typename T>void BinaryTree<T>::PostOrder(void (*Visit)(T &)) { PostOrder(Visit, root);}//用队列实现层次遍历template <typename T>void BinaryTree<T>::LayerOrder(void (*Visit)(T &x),BTNode<T> *r) { if (!r) { return; } queue<BTNode<T>*> myqueue; BTNode<T> *p = r; while (p != NULL || !myqueue.empty()) { if (p != NULL) { Visit(p->elemet); myqueue.push(p->lChild); myqueue.push(p->rChild); } p = myqueue.front(); myqueue.pop(); }}template <typename T>void BinaryTree<T>::LayerOrder(void (*Visit)(T &)) { LayerOrder(Visit, root);}//递归实现求结点总数template <typename T>int BinaryTree<T>::Size(BTNode<T> *r) { if (!r) { return 0; } else { return Size(r->lChild) + Size(r->rChild) + 1; }}template <typename T>int BinaryTree<T>::Size() { return Size(root);}//递归实现复制二叉树template <typename T>BTNode<T>* BinaryTree<T>::Copy(BTNode<T> *r) { if (!this) { return NULL; } else { BTNode<T> *p = new BTNode<T>(r->elemet); p->lChild = Copy(r->lChild); p->rChild = Copy(r->rChild); return p; }}template <typename T>BTNode<T>* BinaryTree<T>::Copy() { return Copy(root);}////递归实现反转二叉树//template <typename T>//BTNode<T>* BinaryTree<T>::InvertTree(BTNode<T> *root) {// if (NULL == root) {// return NULL;// }//// root->lChild = InvertTree(root->lChild); //对左子树进行反转// root->rChild = InvertTree(root->rChild); //对右子树进行反转//// //将左右子树的根结点进行交换// BTNode<T> *tmp = root->lChild;// root->lChild = root->rChild;// root->rChild = tmp;//}//非递归实现反转二叉树template <typename T>BTNode<T>* BinaryTree<T>::InvertTree(BTNode<T> *root) { if (NULL == root) { return NULL; } queue<BTNode<T>*> myqueue; myqueue.push(root); //先将根结点入队 BTNode<T> *tmp = NULL; BTNode<T> *tmpLeft = NULL; while (!myqueue.empty()) { tmp = myqueue.front(); myqueue.pop(); tmpLeft = tmp->lChild; //交换左右孩子 tmp->lChild = tmp->rChild; tmp->rChild = tmpLeft; if (tmp->lChild != NULL) { //交换后左孩子入队 myqueue.push(tmp->lChild); } if (tmp->rChild != NULL) { //交换后右孩子入队 myqueue.push(tmp->rChild); } }}//反转二叉树template <typename T>void BinaryTree<T>::InvertTree() { InvertTree(root);}
最后的测试用例如下,构造的二叉树结构(左图)以及反转后的二叉树(右图)是:
int main() { BinaryTree<char> a, b, x, y, z; //都是空二叉树 char e; x.MakeTree('A', a, b); y.MakeTree('B', a, b); z.MakeTree('C', x, y); x.MakeTree('D', a, b); y.MakeTree('E', x, b); x.MakeTree('F', y, z); cout<<"先序遍历:"; x.PreOrder(Visit); cout<<endl; cout<<"中序遍历:"; x.InOrder(Visit); cout<<endl; cout<<"后序遍历:"; x.PostOrder(Visit); cout<<endl; cout<<"层次遍历:"; x.LayerOrder(Visit); cout<<endl; cout<<"结点个数:"; cout << x.Size()<<endl; cout<<"反转二叉树......"<<endl; x.InvertTree(); cout<<"先序遍历:"; x.PreOrder(Visit); cout<<endl; cout<<"中序遍历:"; x.InOrder(Visit); cout<<endl; cout<<"后序遍历:"; x.PostOrder(Visit); cout<<endl; cout<<"层次遍历:"; x.LayerOrder(Visit); cout<<endl; return 0;}
运行结果是:
先序遍历:F E D C A B 中序遍历:D E F A C B 后序遍历:D E A B C F 层次遍历:F E C D A B 结点个数:6反转二叉树......先序遍历:F C B A E D 中序遍历:B C A F E D 后序遍历:B A C D E F 层次遍历:F C E B A D Process finished with exit code 0
0 0
- 数据结构的C实现_二叉树
- (C语言)二叉树实现(数据结构十三)
- C 实现数据结构二叉查找树
- [数据结构]C语言二叉树的实现
- 数据结构 二叉树的实现 c语言版
- c语言实现二叉树数据结构
- 数据结构(C实现)------- 遍历二叉树
- C语言二叉树的数据结构实现
- 数据结构:二叉树的实现(C++)
- 数据结构之---二叉树C实现
- 数据结构:二叉查找树(C语言实现)
- 【数据结构】数据结构C语言的实现(简单二叉树)
- 数据结构(C++)--二叉树
- 二叉树(数据结构 c++)
- 【数据结构】二叉树(c++)
- 数据结构-二叉树实现
- 数据结构 二叉树实现
- 二叉树数据结构实现
- banner框架的简单使用
- linux正则表达式详解
- Android 照相 获取图片 剪切图片获取图片
- spring事务管理(一)
- 常用日期函数
- 《C++实现数据结构》:二叉树
- 为什么以太网无法接收大于1500字节的数据包
- javascript 实现快排的两种方法 和sort()的比较,以及效率
- 求最大公约数与最小公倍数
- 步进电机原理
- AES,MD5,RSA,SHA系列等各类加密解读
- Git个别理解
- Q94:怎么用ray tracing画部分圆环(Part Tori)
- [Bootkit]开源Bootkit技术(三)vBootkit