数据结构线索二叉树(C++)
概念
由于二叉树定义的时候,结点有的没有儿子指针,设置为NULL,为了不浪费这部分空间,于是利用原有的空指针域来存放结点的前驱和后继指针。一般约定,利用空的leftChild域存放结点的前驱结点指针,利用空的rightChild域存放结点的后继结点指针。这一类指示前驱和后继的指针叫做“线索”,加上了线索的二叉树叫做线索二叉树。
线索
在每个结点中设置两个标志ITag和RTag。如果ITag=0,表示leftChild域存放的是左儿子指针,否则为前驱结点,如果RTag=0,表示rightChild域存放的是右儿子指针,否则为后继结点。
线索二叉树函数的功能
线索二叉树结构体结点定义
template<class T>
struct ThreadNode
{
T data;
ThreadNode<T> *leftChild;
ThreadNode<T> *rightChild;
int LTag;
int RTag;
ThreadNode() :leftChild(NULL), rightChild(NULL), LTag(0), RTag(0) {}
ThreadNode(T item) :data(item), leftChild(NULL), rightChild(NULL), LTag(0), RTag(0) {}
};
线索二叉树类体的定义
template <class T>
class ThreadTree
{
public:
ThreadTree();
~ThreadTree();
void preOrderCreate(char endTag='#');
void preOrderCreate(ThreadNode<T> *&root,char endTag='#');//前序遍历创建线索二叉树
void createInThread();
void createInThread(ThreadNode<T> *current, ThreadNode<T> *&pre);//中序建立线索二叉树
void InOrder();
void InOrder(ThreadNode<T>* p);
void PreOrder();
void PreOrder(ThreadNode<T>* p);
void PostOrder();
void PostOrder(ThreadNode<T>* p);
ThreadNode<T>* Parent(ThreadNode<T>* p);
ThreadNode<T>* First(ThreadNode<T>* current);//返回以current为根中序遍历下的第一个结点
ThreadNode<T>* Last(ThreadNode<T>* current);//返回以current为根中序遍历下的最后一个结点
ThreadNode<T>* Prior(ThreadNode<T>* current);//返回cuurent中序遍历下的前驱结点
ThreadNode<T>* Next(ThreadNode<T>* current);//返回cuurent中序遍历下的后继结点
private:
ThreadNode<T> *root;
void destroy(ThreadNode<T> *p);
};
构造函数
template<class T>
ThreadTree<T>::ThreadTree()
{
root = NULL;
}
析构函数
~ThreadTree()
{
destroy(root);
}
template<class T>
void ThreadTree<T>::destroy()
{
if (root == NULL)
return;
destroy(root->leftChild);
destroy(root->rightChild);
delete root;
}
前序遍历建立二叉树
template<class T>
void ThreadTree<T>::preOrderCreate(char endTag)
{
preOrderCreate(root);
}
template<class T>
void ThreadTree<T>::preOrderCreate(ThreadNode<T> *&root,char endTag)
{
T element;
cin >> element;
if (element == endTag)
return;
root = new ThreadNode<T>(element);
assert(root != NULL);
preOrderCreate(root->leftChild, endTag);
preOrderCreate(root->rightChild, endTag);
}
中序遍历完成线索二叉树
template<class T>
void ThreadTree<T>::createInThread()
{
ThreadNode<T> *pre = NULL;
if (root != NULL)
{
createInThread(root, pre);
pre->rightChild = NULL;//最后一个结点没有后继
pre->RTag = 1;//当createInThread(含参)的函数执行完毕后,pre指向最后一个结点
}
}
template<class T>
void ThreadTree<T>::createInThread(ThreadNode<T> *current, ThreadNode<T> *&pre)
{
if (current == NULL)
return;//当前结点为空则返回
createInThread(current->leftChild, pre);//左子树线索化
if (current->leftChild == NULL)
{
current->leftChild = pre;
current->LTag = 1;
}
if (pre != NULL && pre->rightChild == NULL)//在前驱结点中添加后继线索
{
pre->rightChild=current;//pre!=NULL加入判断条件
pre->RTag = 1;
}
pre = current;//当前结点完成后,current->rightChild的前趋结点就为current,即pre
createInThread(current->rightChild, pre);//右子树线索化
}
注意
- 参数pre使用的是*&
- 在遍历过程中pre始终指向结点的前驱结点。即中序遍历过程中刚刚访问过的结点。
- 在做中序遍历的时候一遇到空指针域就进行填入。
线索二叉树的前序遍历
template<class T>
void ThreadTree<T>::PreOrder()
{
if (root != NULL)
PreOrder(root);
}
template<class T>
void ThreadTree<T>::PreOrder(ThreadNode<T>* p)
{
while (p != NULL)
{
cout << p->data << " ";
if (p->LTag == 0)
p = p->leftChild;
else if (p->RTag == 0)
p = p->rightChild;
else
{
while (p != NULL && p->RTag == 1)//沿后继线索检测
p = p->rightChild;//直到有右子女的结点
if (p != NULL)
p = p->rightChild;//右子女即为后继
}
}
//ABC##DE#G##F###
//A B C D E G F 前序遍历
//C B E G D F A 中序遍历
}
若当前结点有左儿子,则前序下的后继结点为左儿子结点,否则,如果有右儿子,则后继节点为右儿子。对于叶子结点,则沿中序后继线索走到一个有右儿子结点的结点,这个右儿子结点即当前结点的前序后继结点(由于中序遍历和前序遍历的共同点是先访问了左儿子结点,右儿子结点未访问,因此去找一个有右儿子的后继结点去继续访问)。
线索二叉树的中序遍历
template<class T>
void ThreadTree<T>::InOrder()
{
if(root!=NULL)
InOrder(root);
}
template<class T>
void ThreadTree<T>::InOrder(ThreadNode<T>* p)
{
for (p = First(p); p!=NULL; p = Next(p))
cout << p->data << " ";
}
中序遍历线索二叉树会非常方便,找到中序遍历下的第一个结点,一直寻找后继结点然后输出即可。
线索二叉树的后序遍历
template<class T>
void ThreadTree<T>::PostOrder()
{
if (root != NULL)
PostOrder(root);
}
template<class T>
void ThreadTree<T>::PostOrder(ThreadNode<T>* p)
{
while (p->LTag == 0 || p->RTag == 0)
if (p->LTag == 0)
p = p->leftChild;
else if (p->RTag == 0)
p = p->rightChild;//找到后序遍历的第一个结点
cout << p->data << " ";
ThreadNode<T> *father;
while ((father = Parent(p)) != NULL)
{
if (father->rightChild == p || father->RTag == 1)
p = father;
else
{
p = father->rightChild;
while (p->LTag == 0 || p->RTag == 0)
if (p->LTag == 0)
p = p->leftChild;
else if (p->RTag == 0)
p = p->rightChild;
}
cout << p->data << " ";
}
}
寻找某个结点的父结点
ThreadNode<T>* ThreadTree<T>::Parent(ThreadNode<T>* p)
{
if (p == root)
return NULL;
ThreadNode<T>* t;
for (t = p; p->LTag == 0; p = p->leftChild);
if (p->leftChild != NULL)
for (p = p->leftChild; p != NULL && p->leftChild != t && p->rightChild != t; p = p->rightChild);
if (p == NULL || p->leftChild == NULL)
{
for (p = t; p->RTag == 0; p = p->rightChild);
for (p = p->rightChild; p != NULL && p->leftChild != t && p->rightChild != t; p = p->rightChild);
}
return p;
}
返回某个结点为根的中序遍历下的第一个结点
template<class T>
ThreadNode<T>* ThreadTree<T>::First(ThreadNode<T>* current)
{
ThreadNode<T> *p=current;
while (p->LTag == 0)
p = p->leftChild;//最左下角结点,不一定是叶子结点
return p;
}
返回某个结点为根的中序遍历下的最后一个结点
template<class T>
ThreadNode<T>* ThreadTree<T>::Last(ThreadNode<T>* current)
{
ThreadNode<T>* p=current;
while (p->RTag == 0)
p = p->rightChild;//最右下角结点,不一定是叶子结点
return p;
}
返回结点在中序遍历下的前驱结点
template<class T>
ThreadNode<T>* ThreadTree<T>::Prior(ThreadNode<T>* current)
{
ThreadNode<T>* p = current->leftChild;
if (current->LTag == 0)
return Last(p);
else
return p;
}
返回结点在中序遍历下的后继结点
template<class T>
ThreadNode<T>* ThreadTree<T>::Next(ThreadNode<T>* current)
{
ThreadNode<T>* p = current->rightChild;
if (current->RTag == 0)
return First(p);
else
return p;
}
完整代码
#include<iostream>
#include<assert.h>
using namespace std;
template<class T>
struct ThreadNode
{
T data;
ThreadNode<T> *leftChild;
ThreadNode<T> *rightChild;
int LTag;
int RTag;
ThreadNode() :leftChild(NULL), rightChild(NULL), LTag(0), RTag(0) {}
ThreadNode(T item) :data(item), leftChild(NULL), rightChild(NULL), LTag(0), RTag(0) {}
};
template <class T>
class ThreadTree
{
public:
ThreadTree();
~ThreadTree() { destroy(root); }
void preOrderCreate(char endTag='#');
void preOrderCreate(ThreadNode<T> *&root,char endTag='#');//前序遍历创建线索二叉树
void createInThread();
void createInThread(ThreadNode<T> *current, ThreadNode<T> *&pre);//中序建立线索二叉树
void InOrder();
void InOrder(ThreadNode<T>* p);
void PreOrder();
void PreOrder(ThreadNode<T>* p);
void PostOrder();
void PostOrder(ThreadNode<T>* p);
ThreadNode<T>* Parent(ThreadNode<T>* p);
ThreadNode<T>* First(ThreadNode<T>* current);//返回以current为根中序遍历下的第一个结点
ThreadNode<T>* Last(ThreadNode<T>* current);//返回以current为根中序遍历下的最后一个结点
ThreadNode<T>* Prior(ThreadNode<T>* current);//返回cuurent中序遍历下的前驱结点
ThreadNode<T>* Next(ThreadNode<T>* current);//返回cuurent中序遍历下的后继结点
private:
ThreadNode<T> *root;
void destroy(ThreadNode<T>* p)
{
if (root == NULL)
return;
destroy(root->leftChild);
destroy(root->rightChild);
delete root;
}
};
template<class T>
ThreadTree<T>::ThreadTree()
{
root = NULL;
}
template<class T>
void ThreadTree<T>::preOrderCreate(char endTag)
{
preOrderCreate(root);
}
template<class T>
void ThreadTree<T>::preOrderCreate(ThreadNode<T> *&root,char endTag)
{
T element;
cin >> element;
if (element == endTag)
return;
root = new ThreadNode<T>(element);
assert(root != NULL);
preOrderCreate(root->leftChild, endTag);
preOrderCreate(root->rightChild, endTag);
}
template<class T>
void ThreadTree<T>::createInThread()
{
ThreadNode<T> *pre = NULL;
if (root != NULL)
{
createInThread(root, pre);
pre->rightChild = NULL;//最后一个结点没有后继
pre->RTag = 1;//当createInThread(含参)的函数执行完毕后,pre指向最后一个结点
}
}
template<class T>
void ThreadTree<T>::createInThread(ThreadNode<T> *current, ThreadNode<T> *&pre)
{
if (current == NULL)
return;//当前结点为空则返回
createInThread(current->leftChild, pre);//左子树线索化
if (current->leftChild == NULL)
{
current->leftChild = pre;
current->LTag = 1;
}
if (pre != NULL && pre->rightChild == NULL)//在前驱结点中添加后继线索
{
pre->rightChild=current;
pre->RTag = 1;
}
pre = current;//当前结点完成后,current->rightChild的前趋结点就为current,即pre
createInThread(current->rightChild, pre);//右子树线索化
}
template<class T>
void ThreadTree<T>::InOrder()
{
if(root!=NULL)
InOrder(root);
}
template<class T>
void ThreadTree<T>::InOrder(ThreadNode<T>* p)
{
for (p = First(p); p!=NULL; p = Next(p))
cout << p->data << " ";
}
template<class T>
void ThreadTree<T>::PreOrder()
{
if (root != NULL)
PreOrder(root);
}
template<class T>
void ThreadTree<T>::PreOrder(ThreadNode<T>* p)
{
while (p != NULL)
{
cout << p->data << " ";
if (p->LTag == 0)
p = p->leftChild;
else if (p->RTag == 0)
p = p->rightChild;
else
{
while (p != NULL && p->RTag == 1)//沿后继线索检测
p = p->rightChild;//直到有右子女的结点
if (p != NULL)
p = p->rightChild;//右子女即为后继
}
}
//ABC##DE#G##F###
//A B C D E G F 前序遍历
//C B E G D F A 中序遍历
}
template<class T>
void ThreadTree<T>::PostOrder()
{
if (root != NULL)
PostOrder(root);
}
template<class T>
void ThreadTree<T>::PostOrder(ThreadNode<T>* p)
{
while (p->LTag == 0 || p->RTag == 0)
if (p->LTag == 0)
p = p->leftChild;
else if (p->RTag == 0)
p = p->rightChild;//找到后序遍历的第一个结点
cout << p->data << " ";
ThreadNode<T> *father;
while ((father = Parent(p)) != NULL)
{
if (father->rightChild == p || father->RTag == 1)
p = father;
else
{
p = father->rightChild;
while (p->LTag == 0 || p->RTag == 0)
if (p->LTag == 0)
p = p->leftChild;
else if (p->RTag == 0)
p = p->rightChild;
}
cout << p->data << " ";
}
}
template<class T>
ThreadNode<T>* ThreadTree<T>::Parent(ThreadNode<T>* p)
{
if (p == root)
return NULL;
ThreadNode<T>* t;
for (t = p; p->LTag == 0; p = p->leftChild);
if (p->leftChild != NULL)
for (p = p->leftChild; p != NULL && p->leftChild != t && p->rightChild != t; p = p->rightChild);
if (p == NULL || p->leftChild == NULL)
{
for (p = t; p->RTag == 0; p = p->rightChild);
for (p = p->rightChild; p != NULL && p->leftChild != t && p->rightChild != t; p = p->rightChild);
}
return p;
}
template<class T>
ThreadNode<T>* ThreadTree<T>::First(ThreadNode<T>* current)
{
ThreadNode<T> *p=current;
while (p->LTag == 0)
p = p->leftChild;//最左下角结点,不一定是叶子结点
return p;
}
template<class T>
ThreadNode<T>* ThreadTree<T>::Last(ThreadNode<T>* current)
{
ThreadNode<T>* p=current;
while (p->RTag == 0)
p = p->rightChild;//最右下角结点,不一定是叶子结点
return p;
}
template<class T>
ThreadNode<T>* ThreadTree<T>::Prior(ThreadNode<T>* current)
{
ThreadNode<T>* p = current->leftChild;
if (current->LTag == 0)
return Last(p);
else
return p;
}
template<class T>
ThreadNode<T>* ThreadTree<T>::Next(ThreadNode<T>* current)
{
ThreadNode<T>* p = current->rightChild;
if (current->RTag == 0)
return First(p);
else
return p;
}
int main()
{
ThreadTree<char> Tree;
Tree.preOrderCreate();
Tree.createInThread();
Tree.InOrder();
cout << endl;
Tree.PreOrder();
cout << endl;
Tree.PostOrder();
cout << endl;
}