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

一、遍历二叉树

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

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

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

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

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

数据结构--二叉树的遍历和线索二叉树_第1张图片

 

1.1 先序遍历

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

  • 访问根节点

  • 先序遍历左子树

  • 先序遍历右子树

数据结构--二叉树的遍历和线索二叉树_第2张图片

 代码实现:

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

1.2 中序遍历

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

  • 中序遍历左子树

  • 访问根节点

  • 中序遍历右子树

数据结构--二叉树的遍历和线索二叉树_第3张图片

 代码实现:

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

1.3 后续遍历

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

  • 后续遍历左子树

  • 后序遍历右子树

     

  • 访问根节点

数据结构--二叉树的遍历和线索二叉树_第4张图片

代码实现:

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

1.4 例题 

数据结构--二叉树的遍历和线索二叉树_第5张图片

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

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

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

数据结构--二叉树的遍历和线索二叉树_第6张图片 数据结构--二叉树的遍历和线索二叉树_第7张图片

 1.6 中序遍历的非递归实现

基本思想:

  • 先建立一个栈

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

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

数据结构--二叉树的遍历和线索二叉树_第8张图片

 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,访问它;

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

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

数据结构--二叉树的遍历和线索二叉树_第9张图片

# 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 二叉树的建立

数据结构--二叉树的遍历和线索二叉树_第10张图片

 

// 二叉树的创建
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 二叉树的复制

数据结构--二叉树的遍历和线索二叉树_第11张图片

 

// 复制二叉树
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 计算二叉树的深度

数据结构--二叉树的遍历和线索二叉树_第12张图片

 

// 计算二叉树的深度
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 计算二叉树的结点总数

数据结构--二叉树的遍历和线索二叉树_第13张图片

 

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

2.5 计算叶子节点数

数据结构--二叉树的遍历和线索二叉树_第14张图片

// 计算叶子节点数
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);
	}
} 

 

三、线索二叉树

数据结构--二叉树的遍历和线索二叉树_第15张图片

 

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

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

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

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

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

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

数据结构--二叉树的遍历和线索二叉树_第16张图片

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

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

数据结构--二叉树的遍历和线索二叉树_第17张图片

 数据结构--二叉树的遍历和线索二叉树_第18张图片

 

 

你可能感兴趣的:(数据结构,b树,散列表,链表,c语言)