[关闭]
@rg070836rg 2015-08-16T15:08:09.000000Z 字数 4516 阅读 2078

线索二叉树

data_structure

一、简介

线索二叉树是在二叉树的基础上,把空指针加以利用,通过左右type域来标记类型。生成方法是先构造二叉树,再把二叉树线索化,线索化的过程稍候会介绍。

二、线索二叉树的节点构造

先贴代码:

  1. enum BiThrNodeType{LINK,THREAD};
  2. template<class T>
  3. struct BiThrNode
  4. {
  5. BiThrNodeType ltype, rtype;
  6. T data;
  7. BiThrNode<T> *lchild, *rchild;
  8. };

明显,与二叉树相比,只是多了两个枚举类型的数据成员,通俗的解释,

  • LINK标志表示接下来的是他的孩子,
  • THREAD表示接下来的前驱或者后继。

同时贴上InBiThrTree的头文件,里面的函数,会在下面介绍。

  1. template<class T>
  2. class InBiThrTree
  3. {
  4. private:
  5. BiThrNode<T> *root;//根节点
  6. BiThrNode<T> *prenode;//前置点
  7. void InThreaded(BiThrNode<T> *&p);
  8. BiThrNode<T> *CreateByPre(vector<T> &pre, int &i);
  9. public:
  10. InBiThrTree(){ root = NULL; }
  11. InBiThrTree(vector<T> &pre); //根据先序序列创建二叉树
  12. void InThreaded(); //中序线索化
  13. //~InBiThrTree(); //析构函数
  14. BiThrNode<T> *GetNext(BiThrNode<T> *p); //求中序遍历中的后继结点
  15. BiThrNode<T> *GetPrev(BiThrNode<T> *p); //求中序遍历中的前驱结点
  16. void Travese(); //利用线索进行中序遍历
  17. BiThrNode<T>* GetParent(BiThrNode<T> *p); //求父结点地址
  18. BiThrNode<T>* GetRoot(){ return root; } //求根结点
  19. BiThrNode<T>* Search(T e); //根据值e查找结点1
  20. BiThrNode<T>* Search(BiThrNode<T> *p,T e); //在以p为根的树查找1
  21. void setPre(){prenode=NULL;} //置空前置点
  22. };

三、函数介绍

3.1、根据先序序列创建二叉树

说明一下,这一块和前面的树基本没有差异,只是在其中多了个对枚举类型的置空,即默认所有标志位均为孩子位。

  1. //根据先序序列创建二叉树
  2. template<class T>
  3. InBiThrTree<T>::InBiThrTree(vector<T> &pre)
  4. {
  5. int i = 0; //向量pre的下标变量
  6. root = CreateByPre(pre, i);
  7. }
  8. template<class T>
  9. BiThrNode<T> *InBiThrTree<T>::CreateByPre(vector<T> &pre, int &i)
  10. {
  11. T e = pre[i]; i++;//提取当前数据
  12. if (e == '*')
  13. return NULL;//若是特殊数据,返回空指针
  14. BiThrNode<T> *p = new BiThrNode<T>;//创建新结点
  15. p->data = e;
  16. p->ltype = LINK;
  17. p->rtype = LINK;
  18. p->lchild = CreateByPre(pre, i);//创建左子树
  19. p->rchild = CreateByPre(pre, i);//创建右子树
  20. return p;
  21. }

3.2, 二叉树的线索化

  1. //二叉树的中序线索化算法
  2. template<class T>
  3. void InBiThrTree<T>::InThreaded()
  4. {
  5. InThreaded(root);
  6. }
  7. template<class T>
  8. void InBiThrTree<T>::InThreaded(BiThrNode<T> *&p)
  9. {
  10. if (p == NULL) //如果二叉链表p为空,则空操作返回
  11. return;
  12. InThreaded(p->lchild); //对p的左子树建立线索
  13. //对p所指结点建立线索
  14. if (p->lchild == NULL) //对p的左指针处理
  15. {
  16. p->ltype = THREAD;
  17. p->lchild = prenode;
  18. }
  19. if (p->rchild == NULL) //对p的右指针处理
  20. p->rtype = THREAD;
  21. if (prenode != NULL)
  22. {
  23. if (prenode->rtype == THREAD) //设置prenode的后续线索
  24. prenode->rchild = p;
  25. }
  26. prenode = p;
  27. InThreaded(p->rchild); //对p的右子树建立线索
  28. }

这边是比较关键的算法,书上是这么说的


  • 如果二叉链表p为空,则空操作返回
  • 对p的左子树建立线索
  • 对p所指结点建立线索

    若p没有左孩子,则为p加上前驱线索
    若p没有右孩子,则将p右标志置为1
    若结点prenode右标志为1,则为prenode加上后继线索
    令prenode指向刚刚访问的结点p

  • 对p的右子树建立线索

下面,就是这棵树线索化前后的图片:
线索前:
此处输入图片的描述
线索后:
此处输入图片的描述

3.3、一些查找函数

由于时间关系,下面这些函数不做详细介绍,都挺简单的。

  1. //在中序线索二叉树中求结点的后继指针的算法
  2. template<class T>
  3. BiThrNode<T> *InBiThrTree<T>::GetNext(BiThrNode<T> *p)
  4. {
  5. if (p->rtype == THREAD)
  6. return p->rchild;
  7. p = p->rchild;
  8. while (p->ltype == LINK)
  9. p = p->lchild;
  10. return p;
  11. }
  12. //在中序线索二叉树中求结点的前驱指针的算法
  13. template<class T>
  14. BiThrNode<T> *InBiThrTree<T>::GetPrev(BiThrNode<T> *p)
  15. {
  16. if (p->ltype == THREAD)
  17. return p->lchild;
  18. p = p->lchild;
  19. while (p->rtype == LINK)
  20. p = p->rchild;
  21. return p;
  22. }
  23. //中序遍历中序线索二叉树
  24. string result;
  25. template<class T>
  26. void InBiThrTree<T>::Travese()
  27. {
  28. BiThrNode<T> *p = root;
  29. while (p->ltype == LINK) //找到中序遍历的起点
  30. p = p->lchild;
  31. while (p != NULL)
  32. {
  33. result+=p->data;
  34. cout << p->data;
  35. p = GetNext(p);
  36. }
  37. }
  38. //在中序线索化树中,查找结点的父结点
  39. template<class T>
  40. BiThrNode<T> *InBiThrTree<T>::GetParent(BiThrNode<T> *p)
  41. {
  42. if (p == NULL)
  43. return NULL;
  44. BiThrNode<T> *parent;
  45. parent = p;
  46. while (parent->rtype == LINK)
  47. parent = parent->rchild;
  48. parent = parent->rchild; //parent是*p的最右下方结点的后继指针
  49. if (parent && parent->lchild == p)
  50. return parent; //猜测*p是否是*parent的左孩子
  51. parent = p;
  52. while (parent->ltype == LINK)
  53. parent = parent->lchild;
  54. parent = parent->lchild; //parent是*p的最左下方结点的前驱指针
  55. return parent; //parent一定是*p的父指针
  56. }
  57. /*根据值e查找结点*/
  58. template <class T>
  59. BiThrNode<T>* InBiThrTree<T>::Search(T e)
  60. {
  61. return Search(root,e);
  62. }
  63. template<class T>
  64. BiThrNode<T>* InBiThrTree<T>::Search(BiThrNode<T> *p,T e)
  65. {
  66. if(p==NULL) //整棵树空。查找失败,返回上一层
  67. return NULL;
  68. if(p->data==e) //当前节点值正确,返回当前节点
  69. return p;
  70. BiThrNode <T> *q=NULL;
  71. if (p->ltype!=THREAD)
  72. q=Search(p->lchild,e); //若此节点不空,并且此节点数据不匹配,找左子树
  73. if(q!=NULL) //若左边找到了,返回找到的节点给上一层。
  74. return q;
  75. if (p->rtype!=THREAD)
  76. return Search(p->rchild,e); //若左边没找到,返回右子树找到的结果,可以为NULL,可以为节点、
  77. return NULL;
  78. }

需要注意一点,不能把按值查找直接搬过来,需要改下判断条件就可以了,其他的函数,书本上都有,不做过多解释。

四、测试函数

  1. int main()
  2. {
  3. vector<char> a;
  4. //char c[20]="ab*c**de**f**";
  5. //char c[20]="abd**e**cf***";
  6. char c[20]="abd**e**cf***";
  7. cout<<"树的前序向量:"<<c<<endl;
  8. for (int i = 0; i < strlen(c); i++)
  9. {
  10. a.push_back(c[i]);
  11. }
  12. InBiThrTree <char> A(a);
  13. A.setPre();//置空
  14. A.InThreaded();
  15. cout<<"中序遍历打印:";
  16. A.Travese(); //
  17. cout<<endl;
  18. for (i=0;i<result.length();i++)
  19. {
  20. cout<<endl;
  21. char c=result.at(i);
  22. cout<<"查找的值"<<c<<"所在节点并输出地址:";
  23. BiThrNode<char> *tmp = A.Search(c);
  24. cout<<tmp<<endl;
  25. cout<<tmp->data<<"节点的前驱:";
  26. if (A.GetPrev(tmp)!=NULL)
  27. {
  28. cout<<A.GetPrev(tmp)<<" 值为:"<<A.GetPrev(tmp)->data<<endl;
  29. }
  30. else
  31. cout<<NULL<<endl;
  32. cout<<tmp->data<<"节点的后继:";
  33. if (A.GetNext(tmp)!=NULL)
  34. {
  35. cout<<A.GetNext(tmp)<<" 值为:"<<A.GetNext(tmp)->data<<endl;
  36. }
  37. else
  38. cout<<NULL<<endl;
  39. cout<<tmp->data<<"节点的父节点:";
  40. if (A.GetParent(tmp)!=NULL)
  41. {
  42. cout<<A.GetParent(tmp)<<" 值为:"<<A.GetParent(tmp)->data<<endl;
  43. }
  44. else
  45. cout<<NULL<<endl;
  46. cout<<endl;
  47. }
  48. return 0;
  49. }

这边需要注意一下,在线索化之前,需要把PreNode置空,便于第一个THREAD节点的操作。

测试树是这棵:
此处输入图片的描述
测试结果如下:
此处输入图片的描述

2015年5月4日晚

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注