zoukankan      html  css  js  c++  java
  • 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.在下菜鸟,代码中难免有不妥之处,恳求大神批评指正。您的批评就是在下提高的起点,对于您的
          批评,在下将不胜感激! 
    复制代码
  • 相关阅读:
    详细的解说public,protected,Default和private的权限问题
    谈谈java中静态变量与静态方法在有继承关系的两个类中调用
    谈谈java中成员变量与成员方法继承的问题
    谈谈嵌套for循环的理解
    JAVA基础细谈
    Css的使用细谈
    Hibernate映射
    hibernate基本
    struts2
    s:form标签
  • 原文地址:https://www.cnblogs.com/zhangyuhang3/p/6872680.html
Copyright © 2011-2022 走看看