数据结构线索二叉树(C++)

数据结构线索二叉树(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);//右子树线索化
}

注意

  1. 参数pre使用的是*&
  2. 在遍历过程中pre始终指向结点的前驱结点。即中序遍历过程中刚刚访问过的结点。
  3. 在做中序遍历的时候一遇到空指针域就进行填入。

线索二叉树的前序遍历

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;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值