C++实现树的基本操作,界面友好,操作方便,运行流畅,运用模板
Ⅰ.说明: 1.采用左孩子右兄弟的方式,转化为二叉树来实现。 2.树的后根遍历与二叉树的中根遍历即有联系又有区别,请读者注意分析体会。 Ⅱ.功能: 1.创建树并写入数据 2.先根遍历树 3.计算树高 4.后根遍历树 5.层次遍历树 6.搜索数据域为某值的结点 7.删除数据域为某值的结点及其子树 8.销毁树 Ⅲ.代码: //.h文件 #ifndef TREE_H #define TREE_H #include<iostream> #include<iomanip> using namespace std; template<typename T> //树结点 struct Node { T data; Node<T> *left, *right; Node(const T& item); }; template<typename T> //树结点初始化 Node<T>::Node(const T& item) { data = item; left = NULL; right = NULL; } template<typename T> //辅助队列,计算树高 Quefh:queue for high struct Quefh { Node<T>* nodrs; //node's adress int leve; //level Quefh<T>* hnext; Quefh(Node<T>* nds, int lel, Quefh<T>* hnxt); }; template<typename T> //Quefh构造函数 Quefh<T>::Quefh(Node<T>* nds, int lel, Quefh<T>* hnxt) { nodrs = nds; leve = lel; hnext = hnxt; } template<typename T> //辅助队列,查找结点 Quefs:queue for search struct Quefs //此队列同时用于层次遍历 { Node<T>* snodrs; //Quefs::node's adress Quefs<T>* snext; Quefs(Node<T>* snds, Quefs<T>* snxt); }; template<typename T> //Quefs构造函数 Quefs<T>::Quefs(Node<T>* snds, Quefs<T>* snxt) { snodrs = snds; snext = snxt; } template<typename T> //辅助队列,删除结点 Quefd:queue for delete struct Quefd //此队列同时在后根遍历中做临时堆栈 { T ddata; Quefd<T>* dnext; Quefd(const T& ddt, Quefd<T>* dnxt); }; template<typename T> //Quefd构造函数 Quefd<T>::Quefd(const T& ddt, Quefd<T>* dnxt) { ddata = ddt; dnext = dnxt; } template<typename T> //树类 class Tree { private: Node<T>* root; Quefh<T> *hhead, *htail; Quefs<T> *shead, *stail; Quefd<T> *dhead, *dtail,*top; int size; int hsize; int ssize; int dsize; public: Tree(); ~Tree(); void Operate(); private: Node<T>* Creat(Node<T>* &rt); void Destory(Node <T>* t); void Addqh(Node<T>* pn, int levl); void Addqs(Node<T>* spn); void Addqd(const T& dedata); void Outqh(Node<T>* &pn, int &levl); Node<T>* Outqs(); void Delqh(); void Delqs(); void Delqd(); int Couhg(Node<T>* t); Node<T>* GetFather(Node<T>* t, Node<T>* p); void Search(Node<T>* t, const T& item, bool& sign); void Del(Node<T>* t); void D_ShowAll(Quefd<T>* dheader); void FiRoTra(Node<T>* rt, int& ct); void MiRoTra(Node<T>* rt, int& ct); void LeveTra(Node<T>* t); void ShowAll(Quefs<T>* header); Node<T>* Push(Node<T>* t); void PopAll(int& ct); }; template<typename T> //类构造函数 Tree<T>::Tree() { root = NULL; hhead = NULL; htail = NULL; shead = NULL; stail = NULL; dhead = NULL; dtail = NULL; top = NULL; size = 0; hsize = 0; ssize = 0; dsize = 0; } template<typename T> //类析构函数 Tree<T>::~Tree() { Destory(root); } template<typename T> //Quefh入队一个结点 void Tree<T>::Addqh(Node<T>* pn, int levl) { if (!hhead){ hhead = htail = new Quefh<T>(pn, levl, NULL); hsize = 1; } else { htail->hnext = new Quefh<T>(pn, levl, NULL); htail = htail->hnext; hsize++; } } template<typename T> //Quefh出队一个结点 void Tree<T>::Outqh(Node<T>* &pn, int &levl) { pn = hhead->nodrs; levl = hhead->leve; Quefh<T>* itemph; itemph = hhead; hhead = hhead->hnext; delete itemph; hsize--; } template<typename T> //清空队列Quefh void Tree<T>::Delqh() { while (hhead) { Quefh<T>* itemphd; itemphd = hhead; hhead = hhead->hnext; delete itemphd; } } template<typename T> //Quefs入队一个结点 void Tree<T>::Addqs(Node<T>* spn) { if (!shead){ shead = stail = new Quefs<T>(spn, NULL); ssize = 1; } else { stail->snext = new Quefs<T>(spn, NULL); stail = stail->snext; ssize++; } } template<typename T> //Quefs出队一个结点 Node<T>* Tree<T>::Outqs() { Node<T>* pn; pn = shead->snodrs; Quefs<T>* itemps; itemps = shead; shead = shead->snext; delete itemps; ssize--; return pn; } template<typename T> //输出队列Quefs内全部元素 void Tree<T>::ShowAll(Quefs<T>* header) { Quefs<T>* p = header; for (int i = 1; i <= ssize; i++) { cout << p->snodrs << " "; if (i % 5 == 0)cout << endl; p = p->snext; } cout << endl; } template<typename T> //清空队列Quefs void Tree<T>::Delqs() { Quefs<T>* itempsd; while(shead){ itempsd = shead; shead = shead->snext; delete itempsd; } } template<typename T> //Quefd入队一个结点 void Tree<T>::Addqd(const T& dedata) { if (!dhead){ dhead = dtail = new Quefd<T>(dedata, NULL); dsize = 1; } else { dtail->dnext = new Quefd<T>(dedata, NULL); dtail = dtail->dnext; dsize++; } } template<typename T> //输出队列Quefd内全部元素 void Tree<T>::D_ShowAll(Quefd<T>* dheader) { Quefd<T>* dp = dheader; for (int i = 1; i <= dsize; i++) { cout << setiosflags(ios::left); cout << setw(10) << dp->ddata; if (i % 5 == 0)cout << endl; dp = dp->dnext; } cout << endl; } template<typename T> //利用结构体Quefd构造的临时堆栈的入队操作 Node<T>* Tree<T>::Push(Node<T>* t) { while (!t->right) { top = new Quefd<T>(t->data, top); t = t->left; } return t; } template<typename T> //一次性弹出队列中所有元素 void Tree<T>::PopAll(int& ct) { while (top) { cout << setiosflags(ios::left); cout << setw(10) << top->ddata; ct++; if (ct % 5 == 0)cout << endl; Quefd<T>* itemp4; itemp4 = top; top = top->dnext; delete itemp4; } } template<typename T> //清空队列Quefs void Tree<T>::Delqd() { Quefd<T>* itempdd; while (dhead){ itempdd = dhead; dhead = dhead->dnext; delete itempdd; } } template<typename T> //创建树 Node<T>* Tree<T>::Creat(Node<T>* &rt) { int choice; bool flag; if (size > 0) { cout << "是否继续创建子树?是请按1,否请按0:" << endl; cin >> choice; flag = true; } if (size == 0) { cout << "请输入根结点数据;" << endl; T data; cin >> data; rt = new Node<T>(data); if (!rt){ cout << "根结点创建失败!" << endl; return NULL; } size++; flag = false; cout << "根结点创建成功!" << endl; cout << "目前树中共有结点" << size << "个。" << endl; } if (flag) { if (choice == 0)return 0; else { cout << "请输入子结点数据;" << endl; T data; cin >> data; rt = new Node<T>(data); if (!rt){ cout << "子结点创建失败!" << endl; return NULL; } size++; cout << "子结点创建成功!" << endl; cout << "目前树中共有结点" << size << "个。" << endl; } } Creat(rt->left); Creat(rt->right); return root; } template<typename T> //先根递归遍历 FiRoTra是first root traversal的缩写 void Tree<T>::FiRoTra(Node<T>* rt, int& ct) { if (rt) { cout << setiosflags(ios::left); cout << setw(10) << rt->data; ct++; if (ct % 5 == 0) cout << endl; FiRoTra(rt->left, ct); FiRoTra(rt->right, ct); } } template<typename T> //中根递归遍历 MiRoTra是middle root traversal的缩写 这里用来进行树的后根遍历 void Tree<T>::MiRoTra(Node<T>* rt, int& ct) { if (rt) { MiRoTra(rt->left, ct); cout << setiosflags(ios::left); cout << setw(10) << rt->data; ct++; if (ct % 5 == 0) cout << endl; MiRoTra(rt->right, ct); } } template<typename T> //层次遍历 LeveTra是level traversal的缩写 void Tree<T>::LeveTra(Node<T>* t) { int count=0; Node<T>* pt; Addqs(t); while (ssize>0) { pt = Outqs(); count++; cout << setiosflags(ios::left); cout << setw(10) << pt->data; if (count % 5 == 0)cout << endl; pt = pt->left; while (pt) { Addqs(pt); pt = pt->right; } } } template<typename T> //计算树高 int Tree<T>::Couhg(Node<T>* t) { int level = 0, lev, max = 0; Node<T>* pt; Addqh(t, level); while (hsize>0) { Outqh(pt, lev); level = lev + 1; if (max < lev)max = lev; while (pt) { if (pt->left)Addqh(pt->left, level); pt = pt->right; } } hhead = htail = NULL; return max; } template<typename T> //搜索数据域为某值的结点 void Tree<T>::Search(Node<T>* t, const T& item, bool& sign) { if (t) { Search(t->left, item, sign); Search(t->right, item, sign); if (t->data == item){ sign = true; Addqs(t); } } } template<typename T> //得到某结点(以地址为关键值)的父结点的地址 Node<T>* Tree<T>::GetFather(Node<T>* t, Node<T>* p) { Node<T>* q; if (t == NULL)return NULL; if (t->left == p || t->right == p)return t; q = GetFather(t->left, p); if (q != NULL)return q; else return GetFather(t->right, p); } template<typename T> //在树中删除以某结点为根的树 void Tree<T>::Del(Node<T>* t) { if (t != NULL) { Del(t->left); Del(t->right); Addqd(t->data); delete t; size--; } } template<typename T> //销毁树 void Tree<T>::Destory(Node<T>* t) { if (t != NULL) { Destory(t->left); Destory(t->right); delete t; size--; } } template <typename T> void Tree<T>::Operate() { bool flager = true; while (flager) { cout << "请您选择操作(输入操作前的数字进行选择):" << endl; cout << "1.创建树并写入数据" << endl; cout << "2.先根遍历树" << endl; cout << "3.计算树高" << endl; cout << "4.后根遍历树" << endl; cout << "5.层次遍历树" << endl; cout << "6.搜索数据域为某值的结点" << endl; cout << "7.删除数据域为某值的结点及其子树" << endl; cout << "8.销毁树" << endl; int choice; cin >> choice; switch (choice) { //由用户创建树 case 1: { if (root){ cout << "树已经创建,无需再建!若想新建,请您先销毁旧树!" << endl; break; } Creat(root); cout << "树创建完成!" << endl; cout << "此树中共有结点" << size << "个!" << endl; break; } //先根遍历树 case 2: { if (!root){ cout << "树还未创建或已被销毁,无法执行遍历操作,请您先创建树!" << endl; break; } int counter2 = 0; FiRoTra(root, counter2); cout << endl; break; } //计算树高 case 3: { if (!root){ cout << "树还未创建或已被销毁,无法计算树高,请您先创建树!" << endl; break; } int high; high= Couhg(root); cout << "树的高度为:" <<high<< endl; break; } //后根遍历树 case 4: { if (!root){ cout << "树还未创建或已被销毁,无法执行遍历操作,请您先创建树!" << endl; break; } Node<T>* pt4 = Push(root); int counter4 = 0; MiRoTra(pt4, counter4); PopAll(counter4); cout << endl; break; } //层次遍历树 case 5: { if (!root){ cout << "树还未创建或已被销毁,无法执行遍历操作,请您先创建树!" << endl; break; } LeveTra(root); cout << endl; shead = stail = NULL; break; } //搜索数据域为某值的结点 case 6: { if (!root){ cout << "树还未创建或已被销毁,无法执行搜索操作,请您先创建树!" << endl; break; } cout << "请您输入数据域的值;" << endl; T indata; cin >> indata; bool flag = false; Search(root, indata, flag); if (!flag){ cout << "该树中没有数据域为" << indata << "的结点!" << endl; break; } else cout << "该树中数据域为" << indata << "的结点共有" << ssize << "个。" << endl; cout << "是否输出这些结点的地址?是请按1,否则按0:" << endl; int choice6; cin >> choice6; if (choice6 == 1) ShowAll(shead); Delqs(); shead = stail = NULL; ssize = 0; break; } //删除数据域为某值的结点及其子树 case 7: { if (!root){ cout << "树还未创建或已被销毁,无法执行删除操作,请您先创建树!" << endl; break; } T data7; bool flag7 = false; bool sign7 = true; int choice7; cout << "请您输入结点数据的值:" << endl; cin >> data7; Search(root, data7, flag7); if (!flag7){ cout << "目前树中无数据域为" << data7 << "的结点!" << endl; break; } while (sign7) { Node<T> *p7, *fp7; Quefs<T> *item7; p7 = shead->snodrs; item7 = shead; shead = shead->snext; delete item7; ssize--; if (p7 == root) { cout << "数据域为" << data7 << "的结点为根结点,若执行删除操作将会销毁整棵树!" << endl; cout << "是否确定执行删除操作?确定请按1,取消请按0:" << endl; cin >> choice7; if (choice7 == 0){ Delqs(); shead = stail = NULL; ssize = 0; goto mark7; } else { Destory(p7); root = NULL; size = 0; cout << "删除成功!同时整棵树也被销毁!" << endl; Delqs(); shead = stail = NULL; ssize = 0; goto mark7; } } fp7 = GetFather(root, p7); if (p7->right) //其实这两个if可以合成一个,但考虑到程序的可读性,分开来写 { if (fp7->left == p7)fp7->left = p7->right; if (fp7->right == p7) fp7->right = p7->right; p7->right = NULL; } if (!p7->right) { if (fp7->left == p7)fp7->left = NULL; if (fp7->right == p7)fp7->right = NULL; } Del(p7); cout << "删除成功!" << endl; if (ssize == 0){ cout << "此时树中已无数据域为" << data7 << "的结点及其子树!" << endl; sign7 = false; } if (ssize > 0){ cout << "但此时树中数据域为" << data7 << "的结点还有" << ssize << "个!" << endl; } cout << "此次共删除结点" << dsize << "个," << "目前树中还有结点" << size << "个。" << endl; cout << "是否显示被删除的各结点的值?是请按1,否则请按0:" << endl; cin >> choice7; if (choice7 == 1)D_ShowAll(dhead); Delqd(); dhead = dtail = NULL; dsize = 0; if (ssize > 0) { cout << "是否继续删除数据域为" << data7 << "的结点及其子树?是请按1,否则按0:" << endl; cin >> choice7; if (choice7 == 0)sign7 = false; } } Delqs(); shead = stail = NULL; ssize = 0; mark7:break; } //销毁树 case 8: { if (!root){ cout << "树还未创建或已被销毁!" << endl; break; } cout << "您确定销毁该树吗?确定请按1,取消请按0:" << endl; int choice8; cin >> choice8; if (choice8 == 0)break; else Destory(root); root = NULL; size = 0; cout << "树已销毁!" << endl; break; } //处理用户的错误输入 default: { cout << "您的输入有误,无法进行操作!" << endl; break; } }//switch结束 //控制循环 cout << "是否继续?继续请按1,退出请按0:" << endl; int ifgoon; cin >> ifgoon; if (ifgoon == 0)flager = false; }//while结束 } #endif //.cpp文件 #include"Tree.h" #include<iostream> using namespace std; int main() { //是否进入程序 int uscho; bool flag = true;//uscho:user choice的缩写 cout << "敬告;请您务必按提示要求操作,如果您进行了规定以外的操作,由此造成的一切后果,将全部由您个人承担,程序开发者概不负责!" << endl; cout << "是否进入程序?进入请按1,否则按0;" << endl; cin >> uscho; if (uscho == 0) return 0; //用户选择类型 while (flag) { cout << "请选择您所要创建树的数据类型,输入类型前的数字进行选择;" << endl; cout << "1.整型 2.浮点 3.字符" << endl; cin >> uscho; if (uscho != 1 && uscho != 2 && uscho != 3) { cout << "您的输入有误!重新输入请按1,退出请按0:" << endl; cin >> uscho; if (uscho == 0)return 0; else flag = false; } if (flag) flag = false; else flag = true; } switch (uscho) { case 1: { Tree<int> tree_int; tree_int.Operate(); break; } case 2: { Tree<float> tree_float; tree_float.Operate(); break; } case 3: { Tree<char> tree_char; tree_char.Operate(); break; } default: cout << "您的输入有误!" << endl; break; } return 0; } Ⅳ.结语: 代码已经过测试,在VS2013上成功运行! 发此文有两大目的: 1.和大家交流经验,供需要的人参考。 2.在下菜鸟,代码中难免有不妥之处,恳求大神批评指正。您的批评就是在下提高的起点,对于您的 批评,在下将不胜感激!