前面实现了二叉树的二叉链表表示实现,当用二叉链表作为二叉树的存储结构时,因为每个结点中只有指向其左、右儿子结点的指针,所以从任一结点出发只能直接找到该结点的左、右儿子。在一般情况下靠它无法直接找到该结点在某种遍历序下的前驱和后继结点。如果在每个结点中增加指向其前驱和后继结点的指针,将降低存储空间的效率。
在n个结点的二叉链表中含有n+1个空指针。因为含n个结点的二叉链表中含有个指针,除了根结点,每个结点都有一个从父结点指向该结点的指针,因此一共使用了n-1个指针,所以在n个结点的二叉链表中含有n+1个空指针。
因此可以利用这些空指针,存放指向结点在某种遍历次序下的前驱和后继结点的指针。这种附加的指针称为线索,加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(ThreadedBinaryTree)。根据线索性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种。
下面实现中序线索二叉树。
头结点信息ThreadNode.h
#include "stdafx.h" #include <iostream> using namespace std; template <typename Type> class ThreadTree; template <typename Type> class ThreadNode{ public: friend class ThreadTree<Type>; ThreadNode():lchild(NULL),rchild(NULL),ltag(0),rtag(0){} ThreadNode(Type item,ThreadNode<Type>* l=NULL,ThreadNode<Type>* r=NULL) :data(item),rchild(r),lchild(l),ltag(0),rtag(0){} void inOrder(); private: Type data; // 数据 ThreadNode<Type>*lchild; // 左孩子 ThreadNode<Type>*rchild; //右孩子 int ltag; //左标记(0 指向左孩子,1指向前驱) int rtag; // 右标记(0指向右孩子,1指向后继) }; template<typename Type> void ThreadNode<Type>::inOrder(){ if(NULL!=this){ this->lchild->inOrder(); cout << "->" << this->data; this->rchild->inOrder(); } }
中序线索二叉树的实现:ThreadTree.h
#include "ThreadNode.h" template <typename Type> class ThreadTree{ public: ThreadTree():root(NULL),pre(NULL),head(NULL){} bool insert(const Type item); void inOrder(); // 中续遍历 void inThreading(); // 建立中续索引 void inThreadVisit(); private: ThreadNode<Type>*root; // 根节点 ThreadNode<Type>*pre; // 始终记录刚访问过的节点 ThreadNode<Type>*head; void inThreadBuilt(ThreadNode<Type>* t); }; template<typename Type> bool ThreadTree<Type>::insert(const Type item){ ThreadNode<Type>*newNode = new ThreadNode<Type>(item); if(root==NULL){ root = newNode; return 1; } ThreadNode<Type>*pmove = root; while(1){ if(item>pmove->data){ if(NULL==pmove->rchild){ pmove->rchild = newNode; return 1; } pmove = pmove->rchild; } else{ if(NULL==pmove->lchild){ pmove->lchild = newNode; return 1; } pmove=pmove->lchild; } } } // 建立线索 template<typename Type> void ThreadTree<Type>::inOrder(){ this->root->inOrder(); cout << endl; } template<typename Type> void ThreadTree<Type>::inThreading(){ head=new ThreadNode<Type>; head->lchild = head; head->rtag = 1; if(NULL!=root){ head->lchild = root; pre = head; inThreadBuilt(root); pre->rchild = head; head->rchild = pre; } } template<typename Type> void ThreadTree<Type>::inThreadBuilt(ThreadNode<Type>* t){ if(NULL!=t){ inThreadBuilt(t->lchild); if(t->lchild==NULL){ t->lchild = pre; t->ltag = 1; } if(pre->rchild==NULL){ pre->rchild = t; pre->rtag = 1; } pre = t; inThreadBuilt(t->rchild); } } template<typename Type> void ThreadTree<Type>::inThreadVisit(){ if(NULL==head)return; ThreadNode<Type>* pmove = head->lchild; while(pmove!=head){ while (pmove->ltag==0){ pmove=pmove->lchild; } cout << "->" << pmove->data; while((pmove->rchild!=head)&&pmove->rtag==1){ pmove = pmove->rchild; cout << "->" << pmove->data; } pmove = pmove->rchild; // 进入右子树 } cout << endl; }
测试:
// ThreadTree.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include "ThreadTree.h" int _tmain(int argc, _TCHAR* argv[]) { ThreadTree<int> tree; int array[]={20,12,65,54,63,14,16,18}; for(int i = 0 ; i<8 ; i++){ tree.insert(array[i]); } tree.inOrder(); tree.inThreading(); tree.inThreadVisit(); return 0; }
结果:
->12->14->16->18->20->54->63->65
->12->14->16->18->20->54->63->65
请按任意键继续. . .