数据结构--二叉树的遍历和线索二叉树

一、遍历二叉树

  • 遍历定义:顺着某一条搜索路线巡防二叉树中的结点,使得到每个节点均被访问一次,而且仅被访问一次(又称周游)

    • 访问的含义很广,可以是对结点作各种处理,

    • 如:输出结点的信息、修该结点的数据值等,但要求这种访问不破坏原来的数据结构

  • 遍历目的:得到树中所有结点的一个线性排列。

  • 遍历用途:它是树结构插入、删除、修该、查找和排序运算的前提,是二叉树一切运算的基础和核心。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

 

1.1 先序遍历

若二叉树为空,则返回空;否则

  • 访问根节点

  • 先序遍历左子树

  • 先序遍历右子树

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

 代码实现:

// 先序遍历
int PreOrderTraverse(BiTree T){
	if(T == NULL){
		return 0;  // 空二叉树 
	}
	else{
		printf("%c\t",T->data);		// 访问根结点 
		PreOrderTraverse(T->Lchild);	// 递归遍历左子树 
		PreOrderTraverse(T->Rchild);	// 递归遍历右子树 
	} 
} 

1.2 中序遍历

若二叉树为空,则返回空;否则

  • 中序遍历左子树

  • 访问根节点

  • 中序遍历右子树

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

 代码实现:

// 中序遍历
int InorderTraverse(BiTree T){
	if(T == NULL){		// 空二叉树 
		return 0; 
	}
	else{
		InorderTraverse(T->Lchild);		// 递归遍历左
		printf("%c\t",T->data);					// 访问根结点 
		InorderTraverse(T->Rchild);		// 递归遍历右
	}
} 

1.3 后续遍历

若二叉树为空,则返回空操作;否则:

  • 后续遍历左子树

  • 后序遍历右子树

     

  • 访问根节点

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

代码实现:

// 后序遍历
int PostOrderTraverse(BiTree T){
	if(T == NULL){		// 空二叉树 
		return 0; 
	}
	else{
		PostOrderTraverse(T->Lchild);		// 递归遍历左
		PostOrderTraverse(T->Rchild);		// 递归遍历右
		printf("%c\t",T->data);					// 访问根结点 
	}
}

1.4 例题 

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

1.5 根据遍历序列确定二叉树

  • 若二叉树中各节点的值均不相同,则二叉树结点的先序序列、中序序列、后序序列都是唯一的

  • 由二叉树的先序序列和中序序列,或由二叉树的后续序列和中序序列可以确定唯一 一颗二叉树

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16 watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

 1.6 中序遍历的非递归实现

基本思想:

  • 先建立一个栈

  • 根结点进栈,遍历左子树

  • 根结点出栈,输出根节点,遍历右子树。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

 1.6.1 先建立一个栈

typedef struct StackNode{
	SElemType data;
	struct StackNode *next;
}StackNode,*LinkStack; 


// 1、栈的初始化
Status InitLinkStack(LinkStack &S){
	S = NULL;
	return OK;
} 

// 2、链栈是否为空
Status LinkStackEmpty(LinkStack &S){
	if(S == NULL){
		return TRUE;
	}else{
		return FALSE;
	}
} 

// 3、 链栈的入栈
Status Push(LinkStack &S,SElemType e){
	StackNode *p;
	p = new StackNode;
	p->data = e;
	p->next = S;
	S = p;
	return OK;
} 

// 4、链栈的出栈
Status Pop(LinkStack &S,SElemType e){
	StackNode *p;
	if(S == NULL){
		return ERROR;
	}
	e = S->data;
	p = S;
	S = S->next;
	delete p;
	return OK;
} 

 1.6.2 建立二叉树

// 构造一个二叉树
typedef struct BiNode{
	SElemType data;
	struct BiNode *Lchild;
	struct BiNode *Rchild;
}BiNode,*BiTree; 

1.6.3 遍历二叉树

// 中序遍历非递归
Status InOrderStraverse(BiTree T){
	BiTree p,q;
	LinkStack S;
	InitLinkStack(S);
	p = T;
	while(p||!LinkStackEmpty(S)){
		if(p){
			Push(S,p->data);
			p = p->Lchild;
		}
		else{
			Pop(S,q->data);
			printf("%c\t",p->data);
			p = q->Rchild;
		}
	}
	return OK;
} 

 

1.7 二叉树的层次遍历

基本思想:

  • 使用一个队列

  • 将根结点进队;

  • 队不空时循环:从队列中出列一个结点*p,访问它;

    • 若它有左孩子结点,将左孩子结点进队;

    • 若它有右孩子结点,将右孩子结点进队;

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

# define OK 1
# define ERROR 0
# define MAXQSIZE 100 

typedef char QElemType;
typedef int Status;

typedef struct {
	QElemType data[MAXQSIZE];
	int front;
	int rear;
}SqQueue;

// 1、初始化
Status InitQueue(SqQueue &Q){
	Q.front = 0;
	Q.rear = 0;
	return OK;
} 
Status QueueEnpty(SqQueue &Q){
	if(Q.front == Q.rear){
		return 1;
	}
	else{
		return 0;
	}
}

// 2、循环队列入队
Status EnQueue(SqQueue &Q,QElemType e){
	if((Q.rear+1)%MAXQSIZE == Q.front){ 	// 队满 
		return ERROR;
	}
	Q.data[Q.rear] = e;						// 新元素加入队尾 
	Q.rear = (Q.rear+1)%MAXQSIZE;			// 队尾指针+1 
	return OK; 
}

// 3、出队
Status  DeQueue(SqQueue &Q,QElemType e){
	if(Q.front == Q.rear){
		return ERROR; 				// 队空 
	} 
	e = Q.data[Q.front];
	Q.front = (Q.front+1)%MAXQSIZE;
	return OK;
}

// 构造一个二叉树
typedef struct BiNode{
	QElemType data;
	struct BiNode *Lchild;
	struct BiNode *Rchild;
}BiNode,*BiTree; 

// 二叉树的层次遍历算法
void LevelOrder(BiNode *b){
	BiNode *p;
	SqQueue qu;
	InitQueue(qu);			// 初始化队列 
	EnQueue(qu,b->data);	// 根节点指针进入队列
	while(!QueueEnpty(qu)){	// 队列不为空 
		DeQueue(qu,p->data);	// 出队结点 
		printf("%c\t",p->data);
		if(p->Lchild != NULL){
			EnQueue(qu,p->Lchild->data);	// 左孩子进队 
		}
		if(p->Rchild != NULL){
			EnQueue(qu,p->Rchild->data);	// 右孩子进队 
		}
	} 
}

二、二叉树遍历算法的应用

2.1 二叉树的建立

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

 

// 二叉树的创建
void CreateBiTree(BiTree &T){
	char ch;
	scanf("%c",&ch);
	if(ch == '#'){
		T = NULL;
	}
	else{
		T = (BiTree )malloc(sizeof(BiNode));
		if(!T){
			exit(-1);
		}
		T->data = ch;
		CreateBiTree(T->Lchild);
		CreateBiTree(T->Rchild);
	}
} 

2.2 二叉树的复制

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

 

// 复制二叉树
int Copy(BiTree T,BiTree &newT){
	if(T==NULL){		// 如果是空树,返回0 
		newT = NULL;
		return 0;
	}
	else{
		newT = new BiNode;
		newT->data = T->data;
		Copy(T->Lchild,newT->Lchild);
		Copy(T->Rchild,newT->Rchild);
	}
} 

2.3 计算二叉树的深度

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

 

// 计算二叉树的深度
int Depth(BiTree T){
	int m,n;
	if(T==NULL){
		return 0;
	}
	else{
		m = Depth(T->Lchild);
		n = Depth(T->Rchild);
		if(m>n){
			return (m+1);
		}
		else{
			return (n+1);
		}
	}
}

2.4 计算二叉树的结点总数

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

 

// 计算结点总数
int NodeCount(BiTree T){
	if(T == NULL){
		return 0;
	}
	else{
		return NodeCount(T->Lchild)+NodeCount(T->Rchild
		)+1;
	}
} 

2.5 计算叶子节点数

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

// 计算叶子节点数
int LeadCount(BiTree T){
	if(T ==NULL){
		return 0;
	}
	if(T->Lchild == NULL && T->Rchild == NULL){
		return 1;
	}
	else{
		return LeadCount(T->Lchild)+LeadCount(T->Rchild);
	}
} 

 

三、线索二叉树

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

 

利用二叉链表中的空指针域:

  • 如果某个结点的左孩子为空,则将空的左孩子指针域改为指向其前驱;

  • 如果某个结点的右孩子为空,则将空的右孩子指针域改为指向其后继

  • 这种改变指向的指针称为线索

  • 加上了线索的二叉树称为线索二叉树

  • 对二叉树按某种遍历次序使其变为线索二叉树的过程叫做线索化

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

 对二叉链表中每个结点增设两个标志域Ltag 和 Rtag,并约定

Ltag = 0  	Lchild 指向该节点的左孩子
Ltag = 1	Lchild 指向该节点的前驱
Rtag = 0	Rchild 指向该节点的右孩子
Rtag = 1	Rchild 指向该节点的后继

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

 watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

 

 

  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XUN~MLF

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值