@rg070836rg
2015-08-16T07:08:09.000000Z
字数 4516
阅读 2294
data_structure线索二叉树是在二叉树的基础上,把空指针加以利用,通过左右type域来标记类型。生成方法是先构造二叉树,再把二叉树线索化,线索化的过程稍候会介绍。
先贴代码:
enum BiThrNodeType{LINK,THREAD};template<class T>struct BiThrNode{BiThrNodeType ltype, rtype;T data;BiThrNode<T> *lchild, *rchild;};
明显,与二叉树相比,只是多了两个枚举类型的数据成员,通俗的解释,
- LINK标志表示接下来的是他的孩子,
- THREAD表示接下来的前驱或者后继。
同时贴上InBiThrTree的头文件,里面的函数,会在下面介绍。
template<class T>class InBiThrTree{private:BiThrNode<T> *root;//根节点BiThrNode<T> *prenode;//前置点void InThreaded(BiThrNode<T> *&p);BiThrNode<T> *CreateByPre(vector<T> &pre, int &i);public:InBiThrTree(){ root = NULL; }InBiThrTree(vector<T> &pre); //根据先序序列创建二叉树void InThreaded(); //中序线索化//~InBiThrTree(); //析构函数BiThrNode<T> *GetNext(BiThrNode<T> *p); //求中序遍历中的后继结点BiThrNode<T> *GetPrev(BiThrNode<T> *p); //求中序遍历中的前驱结点void Travese(); //利用线索进行中序遍历BiThrNode<T>* GetParent(BiThrNode<T> *p); //求父结点地址BiThrNode<T>* GetRoot(){ return root; } //求根结点BiThrNode<T>* Search(T e); //根据值e查找结点1BiThrNode<T>* Search(BiThrNode<T> *p,T e); //在以p为根的树查找1void setPre(){prenode=NULL;} //置空前置点};
说明一下,这一块和前面的树基本没有差异,只是在其中多了个对枚举类型的置空,即默认所有标志位均为孩子位。
//根据先序序列创建二叉树template<class T>InBiThrTree<T>::InBiThrTree(vector<T> &pre){int i = 0; //向量pre的下标变量root = CreateByPre(pre, i);}template<class T>BiThrNode<T> *InBiThrTree<T>::CreateByPre(vector<T> &pre, int &i){T e = pre[i]; i++;//提取当前数据if (e == '*')return NULL;//若是特殊数据,返回空指针BiThrNode<T> *p = new BiThrNode<T>;//创建新结点p->data = e;p->ltype = LINK;p->rtype = LINK;p->lchild = CreateByPre(pre, i);//创建左子树p->rchild = CreateByPre(pre, i);//创建右子树return p;}
//二叉树的中序线索化算法template<class T>void InBiThrTree<T>::InThreaded(){InThreaded(root);}template<class T>void InBiThrTree<T>::InThreaded(BiThrNode<T> *&p){if (p == NULL) //如果二叉链表p为空,则空操作返回return;InThreaded(p->lchild); //对p的左子树建立线索//对p所指结点建立线索if (p->lchild == NULL) //对p的左指针处理{p->ltype = THREAD;p->lchild = prenode;}if (p->rchild == NULL) //对p的右指针处理p->rtype = THREAD;if (prenode != NULL){if (prenode->rtype == THREAD) //设置prenode的后续线索prenode->rchild = p;}prenode = p;InThreaded(p->rchild); //对p的右子树建立线索}
这边是比较关键的算法,书上是这么说的
- 如果二叉链表p为空,则空操作返回
- 对p的左子树建立线索
- 对p所指结点建立线索
若p没有左孩子,则为p加上前驱线索
若p没有右孩子,则将p右标志置为1
若结点prenode右标志为1,则为prenode加上后继线索
令prenode指向刚刚访问的结点p- 对p的右子树建立线索
下面,就是这棵树线索化前后的图片:
线索前:
线索后:

由于时间关系,下面这些函数不做详细介绍,都挺简单的。
//在中序线索二叉树中求结点的后继指针的算法template<class T>BiThrNode<T> *InBiThrTree<T>::GetNext(BiThrNode<T> *p){if (p->rtype == THREAD)return p->rchild;p = p->rchild;while (p->ltype == LINK)p = p->lchild;return p;}//在中序线索二叉树中求结点的前驱指针的算法template<class T>BiThrNode<T> *InBiThrTree<T>::GetPrev(BiThrNode<T> *p){if (p->ltype == THREAD)return p->lchild;p = p->lchild;while (p->rtype == LINK)p = p->rchild;return p;}//中序遍历中序线索二叉树string result;template<class T>void InBiThrTree<T>::Travese(){BiThrNode<T> *p = root;while (p->ltype == LINK) //找到中序遍历的起点p = p->lchild;while (p != NULL){result+=p->data;cout << p->data;p = GetNext(p);}}//在中序线索化树中,查找结点的父结点template<class T>BiThrNode<T> *InBiThrTree<T>::GetParent(BiThrNode<T> *p){if (p == NULL)return NULL;BiThrNode<T> *parent;parent = p;while (parent->rtype == LINK)parent = parent->rchild;parent = parent->rchild; //parent是*p的最右下方结点的后继指针if (parent && parent->lchild == p)return parent; //猜测*p是否是*parent的左孩子parent = p;while (parent->ltype == LINK)parent = parent->lchild;parent = parent->lchild; //parent是*p的最左下方结点的前驱指针return parent; //parent一定是*p的父指针}/*根据值e查找结点*/template <class T>BiThrNode<T>* InBiThrTree<T>::Search(T e){return Search(root,e);}template<class T>BiThrNode<T>* InBiThrTree<T>::Search(BiThrNode<T> *p,T e){if(p==NULL) //整棵树空。查找失败,返回上一层return NULL;if(p->data==e) //当前节点值正确,返回当前节点return p;BiThrNode <T> *q=NULL;if (p->ltype!=THREAD)q=Search(p->lchild,e); //若此节点不空,并且此节点数据不匹配,找左子树if(q!=NULL) //若左边找到了,返回找到的节点给上一层。return q;if (p->rtype!=THREAD)return Search(p->rchild,e); //若左边没找到,返回右子树找到的结果,可以为NULL,可以为节点、return NULL;}
需要注意一点,不能把按值查找直接搬过来,需要改下判断条件就可以了,其他的函数,书本上都有,不做过多解释。
int main(){vector<char> a;//char c[20]="ab*c**de**f**";//char c[20]="abd**e**cf***";char c[20]="abd**e**cf***";cout<<"树的前序向量:"<<c<<endl;for (int i = 0; i < strlen(c); i++){a.push_back(c[i]);}InBiThrTree <char> A(a);A.setPre();//置空A.InThreaded();cout<<"中序遍历打印:";A.Travese(); //cout<<endl;for (i=0;i<result.length();i++){cout<<endl;char c=result.at(i);cout<<"查找的值"<<c<<"所在节点并输出地址:";BiThrNode<char> *tmp = A.Search(c);cout<<tmp<<endl;cout<<tmp->data<<"节点的前驱:";if (A.GetPrev(tmp)!=NULL){cout<<A.GetPrev(tmp)<<" 值为:"<<A.GetPrev(tmp)->data<<endl;}elsecout<<NULL<<endl;cout<<tmp->data<<"节点的后继:";if (A.GetNext(tmp)!=NULL){cout<<A.GetNext(tmp)<<" 值为:"<<A.GetNext(tmp)->data<<endl;}elsecout<<NULL<<endl;cout<<tmp->data<<"节点的父节点:";if (A.GetParent(tmp)!=NULL){cout<<A.GetParent(tmp)<<" 值为:"<<A.GetParent(tmp)->data<<endl;}elsecout<<NULL<<endl;cout<<endl;}return 0;}
这边需要注意一下,在线索化之前,需要把PreNode置空,便于第一个THREAD节点的操作。
测试树是这棵:
测试结果如下:

2015年5月4日晚