【数据结构七】二叉树的先/中/后序遍历以及线索化

311 阅读4分钟

二叉树的先/中/后序遍历

遍历:按照某种次序把所有结点都访问一遍

  • 先序遍历:左右(NLR)
  • 中序遍历:左右(LNR)
  • 后序遍历:左右(LRN

eg:

图片.png

图片.png

代码实现

typedef struct BiTNode{
	ElemType data;
	struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;

//遍历条件:
//1)若二叉树为空,则什么都不做
//2)若二叉树非空,则按对应的遍历规则进行遍历

//先序遍历:空间复杂度:O(h)
void PreOrder(BiTree T){
	if(T != NULL){// 如果二叉树非空 
		visit(T);//访问根结点(可以做一些打印这个结点的值等等的操作) 
		PreOrder(T->lchild); //递归遍历左子树
		PreOrder(T->rchild); //递归遍历右子树 
	}
} 
//中序遍历
void InOrder(BiTree T){
	if(T != NULL){// 如果二叉树非空  
		InOrder(T->lchild); //递归遍历左子树
		visit(T);//访问根结点
		InOrder(T->rchild); //递归遍历右子树 
	}
}
//后序遍历
void PostOrder(BiTree T){
	if(T != NULL){// 如果二叉树非空  
		PostOrder(T->lchild); //递归遍历左子树
		PostOrder(T->rchild); //递归遍历右子树 
		visit(T);//访问根结点
	}
} 
//求树的深度(应用)
int treeDepth(BiTree T){
	if(T == NULL) return 0;
	else{
		int l = treeDepth(T->lchild);
		int r = treeDepth(T->rchild);
		//树的深度=MAX(l r)+1
		return l>r ? l+1 :r+1; 
	}
} 

图片.png

二叉树的层序遍历

也就是一层一层的遍历一个二叉树

算法思想:

  • 初始化一个辅助队列
  • 根结点入队
  • 若队列非空,则队头结点出队访问该结点,并将其左、右孩子插入队尾(如果有的话)

代码实现:

//---------结构定义
typedef struct BiTNode{
	char data;
	struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;
typedef struct LinkNode{
	BiTNode * data;
	struct LinkNode *next;
}LinkNode;
typedef struct{
	LinkNode *front, *rear; //队头队尾指针 
}LinkQueue;

//层序遍历
void LevelOrder(BiTree T){
	LinkQueue Q; //链队列 
	InitQueue(Q);  //初始化辅助队列
	BiTree p;
	EnQueue(Q,T);  //将根结点入队
	while(!IsEmpty(Q)){//队列非空则循环
		DeQueue(Q, p); //队头结点出队
		visit(p); //访问出队结点
		if(p->lchild != NULL)
			EnQueue(Q, p->lchild); //左孩子入队
		if(p->rchild != NULL)
			EnQueue(Q, p->rchild); //右孩子入队		 
	} 	
} 

由遍历序列构造二叉树

若只给出一棵二叉树的前/中/后层序遍历层序中的一种,不能唯一确定一棵二叉树。

图片.png

线索二叉树

图片.png

图片.png

图片.png

//-----线索二叉树的存储结构
typedef struct ThreadNode{ // 线索链表 
	ElemType data;
	struct ThreadNode *lchild, *rchild;
	int ltag, rtag;  //左,右线索标志 
	// tag == 0 : 表示指针指向孩子
	// tag == 1 : 表示指针是"线索" 
}ThreadNode, *ThreadTree; 

图片.png

二叉树线索化

图片.png

typedef struct ThreadNode{
	ElemType data;
	struct ThreadNode *lchild, *rchild;
	int ltag, rtag; //左右线索标记 
}ThreadNode, *ThreadTree;

//全局变量pre,指向当前访问结点的前驱
ThreadNode *pre = NULL;

//中序线索化二叉树T
void CreateInThread(ThreadTree T){
	pre = NULL;  //初始为NULL
	if(T != NULL){ //非空二叉树才能线索化 
		InThread(T); //中序线索化二叉树
		if(pre->rchild == NULL)
			pre->rtag = 1; //处理遍历的最后一个结点 
	} 
} 


//中序遍历二叉树,一边遍历一边线索化
void InThread(ThreadTree T){
	if(T != NULL){
		InThread(T->lchild);
		visit(T);
		InThread(T->rchild);
	}
} 

void visit(ThreadNode *q){
	if(q->lchild == NULL){ //左子树为空,建立前驱线索
		q->lchild = pre;
		q->ltag = 1; 
	}
	if(pre != NULL && pre->rchild == NULL){
		pre->rchild = q; //建立前驱结点的后续线索
		pre->rtag = 1; 
	}
	pre = q;
} 

图片.png

图片.png

图片.png

图片.png

线索二叉树找前驱/后继

  • 中序线索二叉树
//中序线索二叉树找中序后继
//找到以p为根的子树中,第一个被中序遍历的结点
ThreadNode *Firstnode(ThreadNode *p){
	//循环找到最左下结点(不一定是叶子结点)
	while(p->ltag == 0) p = p->lchild;
	return p; 
} 
//在中序线索二叉树中找到结点p的后继结点
ThreadNode *Nextnode(ThreadNode *p){
	//右子树中最左下结点
	if(p->rtag == 0) return  Firstnode(p->rchild);
	else return p->rchild; //rtag==1直接返回后继结点 
} 
//对中序线索二叉树进行中序遍历(利用线索实现的非递归算法)
//空间复杂度O(1) 
void Inorder(ThreadNode *T){
	for(ThreadNode *p=Firstnode(T);p!=NULL;p=Nextnode(p))
		visit(p);
} 

//中序线索二叉树找中序前驱
//找到以p为根的子树中,最后一个被中序遍历的结点
ThreadNode *Lastnode(ThreadNode *p){
	//循环找到最右下结点(不一定是叶结点)
	while(p->rtag == 0) p = p->rchild;
	return p; 
} 
//在中序线索二叉树中找到结点p的前驱结点
ThreadNode *Prenode(ThreadNode *p){
	//左子树中最右下结点
	if(p->ltag == 0) return Lastnode(p->lchild);
	else return p->lchild; 
} 
//对中序线索二叉树进行逆向中序遍历
void RevInorder(ThreadNode *T){
	for(ThreadNode *p=Lastnode(T);p!=NULL;p=Prenode(p))
		visit(p);
}