• 线索二叉树,二叉搜索树的简单实现


    利用前面的二叉树设计,可以很方便的实现线索二叉树,二叉搜索树,下面给出代码,很多功能还有待添加。
    //thread_binary_tree.h
      1 #ifndef _THREAD_BIANTY_TREE_H_
      2 #define _THREAD_BIANTY_TREE_H_
      3 
      4 #include "binary_tree.h"
      5 
      6 namespace binary_tree{
      7 
      8 //ThreadBinaryTreeNode with elem type T
      9 template<typename T>
     10 class ThreadBinaryTreeNode : public BinaryTreeNodeBase< T, ThreadBinaryTreeNode<T> > {
     11     public:
     12         typedef with_thread_node_tag node_category;
     13         ThreadBinaryTreeNode() :m_ltag(0),m_rtag(0) {}
     14         ThreadBinaryTreeNode(const T& elem, ThreadBinaryTreeNode<T> * left = NULL, 
     15                              ThreadBinaryTreeNode<T> * right = NULL,
     16                              bool ltag = 0bool rtag = 0)
     17                 : BinaryTreeNodeBase< T, ThreadBinaryTreeNode<T> > (elem, left, right), 
     18                   m_ltag(ltag), m_rtag(rtag){}
     19         const bool ltag() const{
     20             return m_ltag;
     21         }
     22         const bool rtag() const{
     23             return m_rtag;
     24         }
     25         void set_ltag(bool ltag){
     26             m_ltag = ltag;
     27         }
     28         void set_rtag(bool rtag){
     29             m_rtag = rtag;
     30         }
     31     private:
     32         bool m_ltag;
     33         bool m_rtag;
     34 };
     35 
     36 template <typename U, typename T = ThreadBinaryTreeNode<U> >
     37 class ThreadBinaryTree;
     38 
     39 //到底要不要让穿线二叉树继承BinaryTree呢还是独立一个类
     40 //如果继承,那么要继承所有接口,但是基本上都要重写内容
     41 //我现在只关心一部分内容,提供一部分接口,所以可以独立
     42 //写,这里还是用了继承先,注意使用的时候仅使用那些穿线二叉
     43 //树改写的内容的接口,理论上一个完整的穿线二叉树应该能
     44 //提供BinaryTree的所有接口的,而且这样好复用简单
     45 //也可以单独一个类,以后如果需要添加其它接口,需要BinaryTree
     46 //的实现的化用复合,调用处理。
     47 //其实如ThreadBinaryTree只想继承BinaryTree的一部分,暗示
     48 //BinaryTree的接口太多了,想要继承的是核心接口,应该提出来。
     49 //剩下的可以AdvacedBinaryTree public BinaryTree
     50 //或者剩下的用non memer func
     51 //这里先用private 继承 屏蔽掉基类的接口,恩还是可以用复用
     52 //但是复用代码写起来麻烦些,哦但是那样基类的root()
     53 //用户也没办法用了,还要在thread_tree中明写,权衡,呵呵
     54 //暂时还是public吧, TODO
     55 
     56 //注意对于PrintTree采用了InorderTravel(虚函数重定义)不同的基类triats手法
     57 template <typename U>
     58 class ThreadBinaryTree< U,ThreadBinaryTreeNode<U> > : public BinaryTree<U, ThreadBinaryTreeNode<U> > {
     59     public:
     60         typedef ThreadBinaryTreeNode<U> T;
     61         ~ThreadBinaryTree() { DeleteBinaryTree(this->root()); this->set_root(NULL); } //well 无法访问需要 this->
     62         virtual void DeleteBinaryTree(T *root);
     63         virtual void InOrderTravel(T *root);
     64         virtual void CreateTree(U end_mark) {
     65             BinaryTree<U, ThreadBinaryTreeNode<U> >::CreateTree(end_mark);
     66             //T* p = NULL;
     67             //InThreadRec(this->root(), p);   //no access to m_root directly, 注意InThreadRec(this->root(), NULL)不对
     68             InThreadNoRec(this->root());
     69             cout << "Finished inorder threading" << endl;
     70         }
     71         // TODO
     72 //        virtual void FindElem(T* root, U elem);
     73 //        virtual void PrintTree(); //涉及很多地方要改动
     74 //        virtual void PreOrderTravel();
     75 //        virtual void PostOrderTravel();
     76 //        T* InOrderNext(T *current);
     77 //        T* InOrderPre(T *current);
     78 //        T* PreOrderNext(T *current);
     79 //        void InsertNode(T *pointer, T *newpointer)
     80     private:
     81         //递归中序线索化二叉树
     82         void InThreadRec(T *root, T *&pre);     //这里需要引用.wow!,这里的pre相当一个全局量,而不是随着递归变化的,相当sum
     83         //非递归中序线索化二叉树                //相当容易出错!!!因为要求pre的值及时变化,但如果不是引用,下层变化了,退
     84         void InThreadNoRec(T *root);            //到上层,pre的值又变回到当时的值了(当前栈内)
     85         //中序周游
     86 };
     87 
     88 template <typename U>
     89 void ThreadBinaryTree< U,ThreadBinaryTreeNode<U> > ::
     90 DeleteBinaryTree(ThreadBinaryTreeNode<U> *root) {
     91     cout << "Dlete thread tree" << endl;
     92     if (root) {
     93         if (!root->ltag())
     94             DeleteBinaryTree(root->left());
     95         if (!root->rtag())
     96             DeleteBinaryTree(root->right());
     97         delete root;
     98     }
     99 }
    100 //关于二叉中序穿线树就是对于左子树为空的存它在中序遍历的前驱,显然对于中序第一访问的节点没有前驱,这里采用不处理方式
    101 //是不行的,因为遍历的时候不方便,也需要把它设置为ltag = 1;
    102 //右子树为空则存它在中序遍历的后继,对于中序最后访问的节点,无后继,不特殊处理,所以最后存在两个NULL指针
    103 //对于NULL指针也就无所谓去判断是线索还是左右子树了。
    104 template <typename U>
    105 void ThreadBinaryTree< U,ThreadBinaryTreeNode<U> > ::
    106 InThreadRec(ThreadBinaryTreeNode<U> *root, ThreadBinaryTreeNode<U> *&pre) {
    107     cout << "Inorder rec threading" << endl;
    108     if (root) {
    109         InThreadRec(root->left(), pre);
    110         if (!root->left()) {
    111             root->set_ltag(1);
    112             root->set_left(pre);        
    113         }
    114         if (pre && !pre->right()) {
    115             pre->set_rtag(1);
    116             pre->set_right(root);
    117         }
    118         pre = root;
    119         InThreadRec(root->right(), pre);
    120     }
    121 }
    122 
    123 template <typename U>
    124 void ThreadBinaryTree< U,ThreadBinaryTreeNode<U> > ::
    125 InThreadNoRec(ThreadBinaryTreeNode<U> *root) {
    126     cout << "Inorder threading no rec" << endl;
    127     typedef ThreadBinaryTreeNode<U> T;
    128     T* p = root;
    129     T* pre = NULL;
    130     stack<*> s;
    131     while(!s.empty() || p) {
    132         if (p){
    133             s.push(p);
    134             p = p->left();
    135         } else {
    136             p = s.top();
    137             if (!p->left()) {
    138                 p->set_ltag(1);                   
    139                 p->set_left(pre);
    140             }
    141             if (pre && !pre->right()) {
    142                 pre->set_rtag(1);
    143                 pre->set_right(p);
    144             }
    145             pre = p;
    146             s.pop();
    147             p = p->right();
    148         }
    149     }
    150 }
    151 
    152 template <typename U>
    153 void ThreadBinaryTree< U,ThreadBinaryTreeNode<U> > ::
    154 InOrderTravel(ThreadBinaryTreeNode<U> *root) {
    155     cout << "Inorder travel thread tree" << endl;
    156     typedef ThreadBinaryTreeNode<U> T;
    157     T* p = root;
    158 //    while (p) {
    159 //        if (!p->ltag()) { 
    160 //            p = p->left();
    161 //        } else {
    162 //            Visit(p);
    163 //            while (p->rtag()) {
    164 //                p = p->right();
    165 //                Visit(p);
    166 //            }
    167 //            p = p->right();     //上面的while 是必要的 不能直接p->right 只有对于原右子为空情况p->right 才进入下一向左状态
    168 //        }                       //否则p->right 之后右p->left重复访问左子树了
    169 //    }
    170     while (p) {
    171         while(!p->ltag()) { 
    172             p = p->left();          //左子树走
    173         } 
    174         Visit(p);                  //访问
    175         while (p->rtag()) {        //右子树为空,相当不停的pop 访问根节点(左子树已经访问完)
    176             p = p->right();        //注意p->right 访问后继的话,证明左子树访问完,要访问右子的,没有继续后继,而不能重复再访问左子
    177             Visit(p);
    178         }
    179         p = p->right();       //OK,进入右子树,重复开始的向左走
    180     }                         //上面的while 是必要的 不能直接p->right 只有对于原右子为空情况p->right 才进入下一向左状态
    181 }                             //否则p->right 之后右p->left重复访问左子树了
    182 
    183 
    184 
    185 //template <typename U, typename T = ThreadBinaryTreeNode<U> >
    186 //class ThreadBinaryTree {
    187 //    public:
    188 //        ThreadBinaryTree() { m_root = NULL;}
    189 //        virtual ~ ThreadBinaryTree() {DeleteBinaryTree(m_root);}
    190 //    private:
    191 //        T* m_root;
    192 //}
    193 
    194 
    195 }   // end of namespace binary_tree
    196 #endif // end of _THREAD_BIANTY_TREE_H_
    197 
    //binary_search_tree.h
      1 #ifndef _BINARY_SEARCH_TREE_H_
      2 #define _BINARY_SEARCH_TREE_H_ 
      3 #include "binary_tree.h"
      4 namespace binary_tree{
      5 
      6 //当期二叉搜索树无重复值节点
      7 template<typename U, typename T = BinaryTreeNode<U> >
      8 class BinarySearchTree;
      9 
     10 // TODO 这个命名不太好
     11 // 允许有重复元素的二叉搜索树
     12 template<typename U, typename T = BinaryTreeNode<U> >
     13 class BinarySearchTree2;
     14 
     15 template<typename U>
     16 class BinarySearchTree< U, BinaryTreeNode<U> > : public BinaryTree< U, BinaryTreeNode<U> > {
     17     public:
     18         typedef BinaryTreeNode<U> T;
     19         // TODO why here do not need 构造函数,while BinaryTree need
     20         void InsertNode(const U elem) {
     21             //InsertNodeRec(this->m_root, elem);
     22             InsertNode(this->m_root, elem);
     23         }
     24         void DeleteNode(const U elem) {
     25             DeleteNode(this->m_root, elem);
     26         }
     27     private:
     28         void InsertNodeRec(T *&root,const U elem);
     29         virtual void InsertNode(T *root, const U elem);
     30         virtual void DeleteNode(T *root, const U elem);
     31         //void InsertNode(T *root, T *pn);
     32 };
     33 
     34 //允许相同的元素,后进入的相同元素插入到原元素右子树的最左下
     35 //well 这里有个问题,对于继承类,
     36 //例如 BinarySearchTre2<float> tree; tree.InserNode(3.0);  
     37 //编译器似乎只会找到 InsertNode(T *root, const U elem),认为它最匹配但不成功
     38 //而不会去基类中查找,解决办法避免重名重载?
     39 // TODO 这里先把虚函数名从 InsertNode改成InsertNode成功 不过感觉不爽
     40 // well 条款33,基类的名称被遮掩了!!所以编译器看不到基类的void InsertNode(const U elem)
     41 // 这个陷阱好深,其实编译器应该对子类的虚函数不要掩盖基类名称.
     42 // 另外编译器竟然还是要求virtual void DeleteNode(T *root, const U elem)
     43 // 提供定义,不能用基类默认的吗,哦,用默认的你就不要再写
     44 template<typename U>
     45 class BinarySearchTree2<U, BinaryTreeNode<U> > : public BinarySearchTree<U, BinaryTreeNode<U> > {
     46     public:
     47         typedef BinaryTreeNode<U> T;
     48         //这样也不行,因为基类有个virtual void InsertNode(T *root, const U elem);是私有
     49         //using  BinarySearchTree<U, BinaryTreeNode<U> >::InsertNode;
     50         //这能用转交函数了,或者你就改名 呵呵
     51         void InsertNode(const U elem) {
     52             BinarySearchTree<U, BinaryTreeNode<U> >::InsertNode(elem);
     53         }
     54         //递归函数打印min到mx之间的元素
     55         void PrintRange(T *root, U min, U max);
     56         int PrintRangeRec(T *root, U min, U max);
     57     private:
     58         virtual void InsertNode(T *root, const U elem);
     59         //virtual void DeleteNode(T *root, const U elem);
     60 };
     61 
     62 /*binary tree 实现*/
     63 
     64 //递归写法,简单,但是注意到每次只可能走一个分支,其实递归是没有意义的
     65 //可以很简单的写成非递归
     66 template <typename U>
     67 void BinarySearchTree< U,BinaryTreeNode<U> >::
     68 InsertNodeRec(BinaryTreeNode<U> *&root,const U elem) {
     69     typedef BinaryTreeNode<U> T;
     70     if (!root)
     71         root = new T(elem);
     72     else if (elem < root->elem())
     73         InsertNode(root->m_left, elem);
     74     else if (elem > root->elem())
     75         InsertNode(root->m_right, elem);
     76     else   //遇到相同节点,不需要插入
     77         return;
     78 }
     79 
     80 //So 不要递归思维定势
     81 template <typename U>
     82 void BinarySearchTree< U,BinaryTreeNode<U> >::
     83 InsertNode(BinaryTreeNode<U> *root,const U elem) {
     84     typedef BinaryTreeNode<U> T;
     85     //空树
     86     if (!root) {
     87         this->set_root(new T(elem));
     88         return;
     89     }
     90 
     91     T* p = root;
     92     
     93     while (1) {
     94         if (elem == p->elem())      //遇到相同的节点,无需插入了
     95            break
     96         if (elem < p->elem()) { 
     97             if (p ->left()) {
     98                 p = p->left();
     99             } else {
    100                 p->set_left(new T(elem));
    101                 break;
    102             }
    103 
    104         } else {
    105             if (p->right()) {
    106                 p = p->right();
    107             } else { 
    108                 p->set_right(new T(elem));
    109                 break;
    110             }
    111         }
    112     }
    113 }
    114 template <typename U>
    115 void BinarySearchTree< U,BinaryTreeNode<U> >::
    116 DeleteNode(BinaryTreeNode<U> *root,const U elem) {
    117     typedef BinaryTreeNode<U> T;
    118     
    119     if(this->IsEmpty())
    120         return;
    121      
    122 }
    123 
    124 
    125 /*带重复元素的binary tree实现*/
    126 
    127 template <typename U>
    128 void BinarySearchTree2< U,BinaryTreeNode<U> >::
    129 InsertNode(BinaryTreeNode<U> *root,const U elem) {
    130     typedef BinaryTreeNode<U> T;
    131     //空树
    132     if (!root) {
    133         this->set_root(new T(elem));
    134         return;
    135     }
    136     T* p = root;
    137     while (1) {
    138         if (elem < p->elem()) { 
    139             if (p ->left()) {
    140                 p = p->left();
    141             } else {
    142                 p->set_left(new T(elem));
    143                 break;
    144             }
    145 
    146         } else {    // elem >= p->elem()
    147             if (p->right()) {
    148                 p = p->right();
    149             } else { 
    150                 p->set_right(new T(elem));
    151                 break;
    152             }
    153         }
    154     }
    155 }
    156 
    157 template <typename U>
    158 void BinarySearchTree2< U,BinaryTreeNode<U> >::
    159 PrintRange(BinaryTreeNode<U> *root, U min, U max) {
    160     assert(min <= max);
    161     typedef BinaryTreeNode<U> T;
    162     if (!root)
    163         return;
    164     if (root->elem() == min) {   //遇到了比min小或者相同的,其左子树无须访问了,相同需先访问根,小于则无需了直接右子树
    165         Visit(root);
    166         PrintRange(root->right(),min,max);
    167     } else if (root->elem() > min) {    
    168         PrintRange(root->left(),min,max);
    169         if (root->elem() > max)  // 遇到更大的遍历结束
    170             return;
    171         Visit(root);
    172         PrintRange(root->right(), root->elem(), max); //改成root->elem()没有太大优化
    173     } else {
    174         PrintRange(root->right(),min,max);
    175     }
    176 }
    177 
    178 template <typename U>
    179 int BinarySearchTree2< U,BinaryTreeNode<U> >::
    180 PrintRangeRec(BinaryTreeNode<U> *root, U min, U max) {
    181     
    182 }
    183 
    184 }        //end of namespace binary_tree
    185 #endif   //end of _BINARY_SEARCH_TREE_H_ 
    186 
  • 相关阅读:
    使用Python的Mock库进行PySpark单元测试
    库龄报表的相关知识
    使用PlanViz进行ABAP CDS性能分析
    Spark SQL中列转行(UNPIVOT)的两种方法
    Spark中的一些概念
    使用Visual Studio Code进行ABAP开发
    2019年的几个目标
    Dom--样式操作
    Dom选择器--内容文本操作
    Javascript面向
  • 原文地址:https://www.cnblogs.com/rocketfan/p/1556784.html
Copyright © 2020-2023  润新知