【数据结构】二叉树的线索化及遍历(C语言)

1. 线索二叉树的概念及结构

在有 n 个结点的二叉链表中共有 2n 个链域,但只有 n-1 个有用的非空链域,其余 n+1 个链域是空的。可以利用这空闲的 n+1 个空链域来存放遍历过程中结点的前驱和后继信息。
现规定:若结点有左子树,则其 LChild 域指向其左孩子,否则 LChild 域指向其前驱结点;若节点有右子树,则其 RChild 域指向其右孩子,否则 RChild 域指向其后继结点。
在这种存储结构中,指向前驱和后继结点的指针称为线索。以这种结构组成的二叉链表作为二叉树的存储结构,称为线索链表。对二叉树以某种次序进行遍历并且加上线索的过程称为线索化,线索化了的二叉树称为线索二叉树
线索二叉树的结点结构

2. 二叉树的线索化(以中序线索树为例)

中序线索化采用中序递归遍历算法框架,设置一个指针 pre 始终记录刚访问过的结点。
① 如果当前遍历结点 bt 的左子域为空,则让左子域指向 pre ;
② 如果前驱 pre 的右子域为空,则让右子域指向当前遍历结点 bt ;
③ 为下次做准备,当前访问结点 bt 作为下一个访问结点的前驱 pre 。
中序线索二叉树

/*建立中序线索树*/
BiTree pre;
void Inthread(BiTree bt) {
    
    
//对于bt所指的二叉树进行中序线索化,其中pre始终指向刚访问过的结点,其初值为NULL
	if (bt != NULL) {
    
    
		Inthread(bt->LChild);			//线索化左子树
		if (bt->LChild == NULL) {
    
    		//置前驱线索
			bt->Ltag = 1;
			bt->LChild = pre;
		}
		if (pre != NULL && pre->RChild == NULL) {
    
    	//置后继线索
			pre->RChild = bt;
			pre->Rtag = 1;
		}
		pre = bt;						//当前访问结点为下一个访问结点的前驱
		Inthread(bt->RChild);			//线索化右子树
	}
}

3. 线索二叉树的遍历(以中序线索树为例)

① 求出中序遍历次序下的第一个被访问结点;
② 连续求出刚遍历结点的后继结点,直至所有结点均被遍历。

/*遍历中序线索二叉树*/
void TInOrder(BiTree bt) {
    
    
	BiTree p = bt;
	while (p != NULL) {
    
    
		while (p->Ltag == 0) {
    
    			//找中序遍历的第一个结点
			p = p->LChild;
		}
		printf("%c ", p->data);
		while (p->Rtag == 1 && p->RChild != NULL) {
    
    
			p = p->RChild;
			printf("%c ", p->data);
		}
		p = p->RChild;
	}
}

4. 中序线索树完整实现代码

/*中序线索二叉树*/

# include<stdio.h>
# include<malloc.h>

/*二叉线索树的存储结构*/
typedef char DataType;
typedef struct Node {
    
    
	DataType data;
	int Ltag;
	int Rtag;
	struct Node* LChild;
	struct Node* RChild;
}BiTNode, * BiTree;

/*按扩展先序遍历序列创建二叉链表*/
void CreateBiTree(BiTree* bt) {
    
    
//'.'表示空子树
	char ch;
	ch = getchar();
	if (ch == '.')
		*bt = NULL;
	else {
    
    
		*bt = (BiTree)malloc(sizeof(BiTNode));
		(*bt)->data = ch;
		(*bt)->Ltag = 0;
		(*bt)->Rtag = 0;
		CreateBiTree(&((*bt)->LChild));
		CreateBiTree(&((*bt)->RChild));
	}
}

/*建立中序线索树*/
BiTree pre;
void Inthread(BiTree bt) {
    
    
//对于bt所指的二叉树进行中序线索化,其中pre始终指向刚访问过的结点,其初值为NULL
	if (bt != NULL) {
    
    
		Inthread(bt->LChild);			//线索化左子树
		if (bt->LChild == NULL) {
    
    		//置前驱线索
			bt->Ltag = 1;
			bt->LChild = pre;
		}
		if (pre != NULL && pre->RChild == NULL) {
    
    	//置后继线索
			pre->RChild = bt;
			pre->Rtag = 1;
		}
		pre = bt;							//当前访问结点为下一个访问结点的前驱
		Inthread(bt->RChild);			//线索化右子树
	}
}

/*遍历中序线索二叉树*/
void TInOrder(BiTree bt) {
    
    
	BiTree p = bt;
	while (p != NULL) {
    
    
		while (p->Ltag == 0) {
    
    			//找中序遍历的第一个结点
			p = p->LChild;
		}
		printf("%c ", p->data);
		while (p->Rtag == 1 && p->RChild != NULL) {
    
    
			p = p->RChild;
			printf("%c ", p->data);
		}
		p = p->RChild;
	}
}

int main() {
    
    
	BiTree bt;
	printf("树的创建:");
	CreateBiTree(&bt);
	Inthread(bt);
	printf("遍历结果:");
	TInOrder(bt);
	return 0;
}

5. 运行结果

运行结果
参考:耿国华《数据结构——用C语言描述(第二版)》

更多数据结构内容关注我的《数据结构》专栏https://blog.csdn.net/weixin_51450101/category_11514538.html?spm=1001.2014.3001.5482

猜你喜欢

转载自blog.csdn.net/weixin_51450101/article/details/122856714