线索二叉树

一 引入


遍历二叉树有先序,中序,后序,这三种可以用递归或者栈来实现;

层序遍历可以用队列实现。


如果为了更加方便高效的遍历二叉树,容易想到的是在二叉树结点增加两个指针,分别指向前驱和后继结点。

但无疑会大大降低结点存储密度。

不过考虑到二叉树中,分支数+1=结点数可推出:

n0=n2+1,也就是说,叶子结点数=度为2的结点数+1;

空链域数目:每个叶子结点有2个+每个度为1的结点有1个=2*n0+n1=n2+1+n0+n1=n+1(n是总结点数)


所以可利用这n+1个空指针指向前驱和后继。

所以如果一个结点有左右孩子,那它就不能指向它的前驱后继了。

为了区分节点的两个指针指向的是孩子还是前驱后继,

可以用两个只占两比特的LTag和RTag指示,0(link)表示此指针指向孩子,1(Thread)表指向前驱后继。


另外增加了一个头节点HeadNode。

注意:没有实现后序遍历,是因为后序线索化后,根节点在最后遍历,左子树无后继与右子树关联

若要遍历,仍然需要栈或者递归!


从test.txt读入树,先序方式建立树。如ABD#E###C#JK##M##建立树

例如可以通过

先序建立线索关系如下:






二 程序实现


#ifndef TBTREE_H
#define TBTREE_H
enum PTag{
	Link,Thread
};
template <typename T>
struct TBNode{
	T data;
	TBNode<T> *lchild,*rchild;
	PTag LTag:2,RTag :2;
};
template<typename T>
class TBTree{
private:
	TBNode<T> *HeadNode,*pre;
	void CreateTBTree(ifstream &f,TBNode<T>* &t){
		T e;
		InputFromFile(f,e);
		if(e==Emp) t=NULL;
		else {
			t=new TBNode<T>;
			assert(t!=NULL);
			t->data=e;
			CreateTBTree(f,t->lchild);
			if(t->lchild!=NULL)
				t->LTag=Link;
			else 
				t->LTag=Thread;
			CreateTBTree(f,t->rchild);
			if(t->rchild!=NULL)
				t->RTag=Link;
			else 
				t->RTag=Thread;
		}
	}
	void DestroyTBTree(TBNode<T>* &t){
		if(t!=NULL){
			if(t->LTag==Link)
				DestroyTBTree(t->lchild);
			if(t->RTag==Link)
				DestroyTBTree(t->rchild);
			delete t;
			t=NULL;
		}
	}
	void InThread(TBNode<T>* p){
		if(p!=NULL){
			if(p->LTag==Link)
				InThread(p->lchild);
			else p->lchild=pre;
			if(pre->RTag==Thread)
				pre->rchild=p;
			pre=p;
			if(p->RTag==Link)
				InThread(p->rchild);
		}
	}
	void PreThread(TBNode<T>* p){
		if(p!=NULL){
			if(pre->RTag==Thread)
				pre->rchild=p;
		    if(p->LTag==Thread)
				p->lchild=pre;
			pre=p;
			if(p->LTag==Link)
				PreThread(p->lchild);
			if(p->RTag==Link)
				PreThread(p->rchild);
		}
	}
	void PostThread(TBNode<T>* p){
		if(p!=NULL){
			if(p->LTag==Link)
				PostThread(p->lchild);
			if(p->RTag==Link)
				PostThread(p->rchild);
			if(p->LTag==Thread)
				p->lchild=pre;
			if(pre->RTag==Thread)
				pre->rchild=p;
			pre=p;
		}
	}
public :
	TBTree(){
		HeadNode=new TBNode<T>;
		assert(HeadNode!=NULL);
		HeadNode->LTag=Link;
		HeadNode->RTag=Thread;
		HeadNode->rchild=HeadNode->lchild=HeadNode;		
	}	
	~TBTree(){
		if(HeadNode!=NULL){
			if(HeadNode->lchild)
				DestroyTBTree(HeadNode->lchild);
			delete HeadNode;
		}
	}
	void CreateTBTree(char* FileName){
		ifstream fin(FileName);
		CreateTBTree(fin,HeadNode->lchild);
		fin.close();
	}
	void InThread(){
		if(HeadNode->lchild!=NULL){
			pre=HeadNode;
			InThread(HeadNode->lchild);
			pre->rchild=HeadNode;
			HeadNode->rchild=pre;
		}
	}
	void InPrint(void (*visit)(TBNode<T>*))const{
		TBNode<T>* p=HeadNode->lchild;
		while(p!=HeadNode){
			while(p->LTag==Link)
				p=p->lchild;
			visit(p);
			while(p->RTag==Thread&&p->rchild!=HeadNode){
				p=p->rchild;
				visit(p);
			}
			p=p->rchild;
		}
	}
	void PreThread(){
		if(HeadNode->lchild!=HeadNode){
			pre=HeadNode;
			PreThread(HeadNode->lchild);
			pre->rchild=HeadNode;
			HeadNode->rchild=pre;
		}
	}
	void PrePrint(void (*visit)(TBNode<T>*))const{
		TBNode<T> *p=HeadNode->lchild;
		while(p!=HeadNode){
			visit(p);
			if(p->LTag==Link)
				p=p->lchild;
			else 
				p=p->rchild;
		}
	}
	void PostThread(){
		if(HeadNode->lchild!=HeadNode){
			HeadNode->rchild=HeadNode->lchild;
			pre=HeadNode;
			PostThread(HeadNode->lchild);
			if(pre->RTag!=Link)
				pre->rchild=HeadNode;
		}
	}
	
	
	
	
	
	
	
};

#endif


#include <iostream>
#include <fstream>
#include <assert.h>
using namespace std;
typedef char T;
T Emp='#';
void InputFromFile(ifstream &f, T &c)
{
	f>>c;
}
void Input(T &c)
{
	cin>>c;
}
#include "TBTree.h"
void Visit(TBNode<T> *c)
{
	cout<<c->data<<' ';
}
int main()
{
	TBTree<T> t;
	t.CreateTBTree("test.txt");
	t.PreThread();
	cout<<"先序遍历:";
	t.PrePrint(Visit);
	t.InThread();
	cout<<endl<<"中序遍历:";
	t.InPrint(Visit);
	t.PostThread();
	cout<<endl;
	
	return 0;
}


运行输出





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
创建线索二叉树是一种对二叉树进行优化的数据结构。它的目的是为了加快二叉树遍历速度。在传统的二叉树中,为了实现对二叉树遍历,需要使用递归或者栈来实现。而线索二叉树通过添加线索,将二叉树的节点之间的遍历顺序进行编码,从而实现快速遍历。 在线索二叉树中,每个节点都有两个指针:左指针和右指针。在一棵二叉树中,如果一个节点没有左孩子,则将其左指针指向该节点的前驱节点。如果一个节点没有右孩子,则将其右指针指向该节点的后继节点。通过这样的线索指针,可以快速地找到一个节点的前驱和后继节点,进而实现对二叉树的快速遍历。 具体来说,在线索二叉树中,如果一个节点没有左孩子,则将其左指针指向其前驱节点;如果一个节点没有右孩子,则将其右指针指向其后继节点。通过这样的线索化过程,原本需要递归或者栈来实现的遍历过程,可以直接通过线索指针快速找到下一个需要遍历的节点,从而提高了遍历的效率。 总的来说,线索二叉树是一种优化的二叉树结构,通过添加线索指针,将二叉树的节点之间的遍历顺序进行编码,从而实现了对二叉树的快速遍历。它的设计思想主要是通过设置节点的线索指针指向前驱和后继节点,提高了遍历效率,减了递归或栈的使用。这是一个在实际应用中常用的数据结构,可以广泛应用于二叉树遍历的场景中。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值