第五章 树与二叉树--以下代码由C语言实现

王道学习

5.1 知识框架

5.2 树的基本概念

5.2.1 树的定义

树是n (n≥0)个节点的有限集。当n=0时,称为空树。在任意一棵非空树中应满足:

1)有且仅有一个特定的称为根的结点。

2)当n>1时,其余节点可分为m (m>0)个互不相交的有限集T,T2…,Tm,其中每个集合本身又是一棵树,并且称为根的子树。

显然,树的定义是递归的,即在树的定义中又用到了其自身,树是一种递归的数据结构。树作为一种逻辑结构,同时也是一种分层结构,具有以下两个特点:

1)树的根结点没有前驱,除根结点外的所有结点有且只有一个前驱。

2)树中所有结点可以有零个或多个后继。

树适合于表示具有层次结构的数据。树中的某个结点(除根结点外)最多只和上一层的一个结点(即其父结点)有直接关系,根结点没有直接上层结点,因此在n个结点的树中有n-1条边。而树中每个结点与其下一层的零个或多个结点(即其子女结点)有直接关系。


在这里插入图片描述

5.2.2 基本术语

在这里插入描述
1)考虑结点K。根A到结点K的唯一路径上的任意结点,称为结点K的祖先。如结点B是结点K的祖先,而结点K是结点B的子孙。路径上最接近结点K的结点E称为K的双亲,而K为结点E的孩子。根A是树中唯一没有双亲的结点。有相同双亲的结点称为兄弟,如结点K和结点L有相同的双亲E,即K和L为兄弟。

2)树中一个结点的孩子个数称为该结点的度,树中结点的最大度数称为树的度。如结点B的度为2,结点D的度为3,树的度为3。

3)度大于0的结点称为分支结点(又称非终端结点);度为0(没有子女结点)的结点称为叶子结点(又称终端结点)。在分支结点中,每个结点的分支数就是该结点的度。

4)结点的深度、高度和层次。结点的层次从树根开始定义,根结点为第1层,它的子结点为第2层,以此类推。双亲在同一层的结点互为堂兄弟,图5.1中结点G与E,F,H,I,J互为堂兄弟。

结点的深度是从根结点开始自顶向下逐层累加的。

结点的高度是从叶结点开始自底向上逐层累加的。

树的高度或深度)是树中结点的最大层数。图5.1中树的高度为4。

5)有序树和无序树。树中结点的各子树从左到右是有次序的,不能互换,称该树为有序树,否则称为无序树。假设图5.1为有序树,若将子结点位置互换,则变成一棵不同的树。

6)路径和路径长度。树中两个结点之间的路径是由这两个结点之间所经过的结点序列构成的,而路径长度是路径上所经过的边的个数。

注意:由于树中的分支是有向的,即从双亲指向孩子,所以树中的路径是从上向下的,同一双亲的两个孩子之间不存在路径。

7)森林。森林是m(m≥0)棵互不相交的树的集合。森林的概念与树的概念十分相近因为只要把树的根结点删去就成了森林。反之,只要给m棵独立的树加上一个结点,并把这m棵树作为该结点的子树,则森林就变成了树。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.2.3 树的性质

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.2.4 本节试题精选

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.3 二叉树的概念

5.3.1 二叉树的定义及其主要特性

1、二叉树的定义
在这里插入图片描述
在这里插入图片描述
二叉树与度为2的有序树的区别:

①度为2的树至少有3个结点,而二叉树可以为空。

②度为2的有序树的孩子的左右次序是相对于另一孩子而言的,若某个结点只有一个孩子,则这个孩子就无须区分其左右次序,而二叉树无论其孩子数是否为2.均需确定其左右次序,即二叉树的结点次序不是相对于另一结点而言,而是确定的。)

2、几个特殊的二叉树
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
3、二叉树的性质
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.3.2 二叉树的存储结构

1、顺序存储
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

//二叉树--顺序存储--适合完全二叉树 
#include <stdio.h>
#define MAXSIZE 100

struct TreeNode{
	
	//结点中的数据元素 
	int value; 
	
	//判断结点是否为空  0为空  1不为空 
	int isEmpty; 
	
}; 

typedef struct TreeNode TreeNode;

/*
	初始化tree 
*/
void initTree(TreeNode *tree){
	
	int i=1;
	for(;i<=MAXSIZE-1;i++){
		tree[i].isEmpty=0;
	}
	
}

/*
	输出初始化的结果	
*/
void printfInitTree(TreeNode tree[]){
	int i=1;
	for(;i<=MAXSIZE-1;i++){
		printf("%d,",tree[i].isEmpty);
	}
}

int main(){
	
	TreeNode tree[MAXSIZE];
	initTree(tree);
	printfInitTree(tree);
	
	tree[1].value=1;
	tree[1].isEmpty=1;
	
	tree[2].value=2;
	tree[2].isEmpty=1;
	
	tree[3].value=3;
	tree[3].isEmpty=1;
	
	tree[4].value=4;
	tree[4].isEmpty=1;
	
	tree[5].value=5;
	tree[5].isEmpty=1;
	
	tree[6].value=6;
	tree[6].isEmpty=1;
	
	tree[7].value=7;
	tree[7].isEmpty=1;
	
	tree[8].value=8;
	tree[8].isEmpty=1;
	
	tree[9].value=9;
	tree[9].isEmpty=1;
	
	tree[10].value=10;
	tree[10].isEmpty=1;
	
	tree[11].value=11;
	tree[11].isEmpty=1;
	
	tree[12].value=12;
	tree[12].isEmpty=1;
	
	return 0;
}

2、链式存储
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

5.3.3 本节试题精选

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

23、对于任意一棵高度为5且10个结点的二叉树,若采用顺序存储结构保存,每个结点占1个存储单元(仅存放结点的数据信息),则存放该二叉树需要的存储单元数量至少是()
A 31 B 16 C 15 D 10

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
23
二叉树采用顺序存储时,用数组下标来表示结点之间的父子关系。对于一颗高度为5的二叉树,为了满足任意性,其1-5层的所有结点都要被存储起来,即考虑为一棵高度为5的满二叉树,共需要满足存储单元的数量为1+2+4+8+16=31

5.4 二叉树的遍历和线索二叉树

5.4.1 二叉树的遍历

二叉树的遍历是指按某条搜索路径访问树中每个结点,使得每个结点均被访问一次,而且仅被访问一次。由于二叉树是一种非线性结构,每个结点都可能有两棵子树,因而需要寻找一种规律,以便使二叉树上的结点能排列在一个线性队列上,进而便于遍历。

由二叉树的递归定义可知,遍历一棵二叉树便要决定对根结点N、左子树L和右子树R的访问顺序。按照先遍历左子树再遍历右子树的原则,常见的遍历次序有先序(NLR)、中序(LNR)和后序(LRN)三种遍历算法,其中“序”指的是根结点在何时被访问。

在这里插入图片描述
1、先序遍历
在这里插入图片描述
2、中序遍历
在这里插入图片描述
3、后序遍历
在这里插入图片描述三种遍历算法中,递归遍历左、右子树的顺序都是固定的,只是访问根结点的顺序不同。不管采用哪种遍历算法,每个结点都访问一次且仅访问一次,故时间复杂度都是O(n)。在递归遍历中,递归工作栈的栈深恰好为树的深度,所以在最坏情况下,二叉树是有n个结点且深度为n的单支树,遍历算法的空间复杂度为O(n)。

4、递归算法和非递归算法的转换




//二叉树--链式存储
#include <stdio.h>
#include <stdlib.h> 
#define MAXSIZE 100

struct BiTNode{
	
	//数据域 
	int value; 
	
	//左孩子 
	struct BiTNode *lChild;
	
	//右孩子 
	struct BiTNode *rChild;
}; 

typedef struct BiTNode BiTNode;

typedef struct BiTNode* BiTree;

struct LNode{
	BiTNode* data;
	struct LNode *next;
	
};

typedef struct LNode LNode;
typedef struct LNode* SqStack;

/*
	初始化链式栈:
		1、头指针指向头结点 
		2、头结点的next初始化为NULL
	
	返回一个SqStack型变量:
		具体的值--成功
		NULL--失败	 
*/
SqStack initStack(SqStack sqStack){
	
	LNode* newLNode=(LNode*)malloc(sizeof(LNode));
	
	if(newLNode==NULL){
		return NULL;
	} 
	
	(*newLNode).next=NULL;
	
	sqStack=newLNode;
	
	return sqStack;
}

/*
	判空栈 
	
	返回值
		0--空 
		1--非空 
*/
int stackEmpty(SqStack sqStack){
	
	if(sqStack==NULL){
		return 0;
	}
	
	if((*sqStack).next!=NULL){
		return 1;
	}else{
		return 0;	
	}	
}

/*
	进栈
	
	返回值
		0--失败
		1--成功 
*/
int push(SqStack sqStack,BiTNode* data){
	
	//指向头结点 
	LNode *tmp=sqStack;
	
	if(tmp==NULL){
		return 0;
	}
	
	LNode *newLNode=(LNode *)malloc(sizeof(LNode));
	if(newLNode==NULL){
		return 0;
	}
	(*newLNode).data=data;
	(*newLNode).next=(*tmp).next;
	(*tmp).next=newLNode;
	
	return 1;	
}

/*
	出栈
	
	返回值
		0--失败
		1--成功 
*/
BiTNode * pop(SqStack sqStack){
	
	//指向头结点 
	LNode *tmp=sqStack;
	
	//指向第一个结点 
	LNode *p=(*tmp).next;
	
	BiTNode *data=(*p).data;
	(*tmp).next=(*p).next;
	
	free(p);
	
	return data;	
}

/*
	初始化tree 
*/
BiTNode* initTree(BiTree root){
	
	root=NULL;
	
	return root;
}

/*
	构造树 
*/
BiTNode* constructTree(BiTree root){
	
	BiTNode *p11=(BiTNode *)malloc(sizeof(BiTNode));
	(*p11).value=11;
	(*p11).lChild=NULL;
	(*p11).rChild=NULL;
	
	BiTNode *p12=(BiTNode *)malloc(sizeof(BiTNode));
	(*p12).value=12;
	(*p12).lChild=NULL;
	(*p12).rChild=NULL;
	
	BiTNode *p5=(BiTNode *)malloc(sizeof(BiTNode));
	(*p5).value=5;
	(*p5).lChild=NULL;
	(*p5).rChild=p11;
	
	BiTNode *p6=(BiTNode *)malloc(sizeof(BiTNode));
	(*p6).value=6;
	(*p6).lChild=p12;
	(*p6).rChild=NULL;
	
	BiTNode *p7=(BiTNode *)malloc(sizeof(BiTNode));
	(*p7).value=7;
	(*p7).lChild=NULL;
	(*p7).rChild=NULL;
	
	BiTNode *p2=(BiTNode *)malloc(sizeof(BiTNode));
	(*p2).value=2;
	(*p2).lChild=NULL;
	(*p2).rChild=p5;
	
	BiTNode *p3=(BiTNode *)malloc(sizeof(BiTNode));
	(*p3).value=3;
	(*p3).lChild=p6;
	(*p3).rChild=p7;
	
	BiTNode *p1=(BiTNode *)malloc(sizeof(BiTNode));
	(*p1).value=1;
	(*p1).lChild=p2;
	(*p1).rChild=p3;
	
	root=p1;
	
	return root;
}

/*
	中序遍历--左根右 
*/
void inOrder(BiTree biTree){
	if(biTree!=NULL){
		inOrder((*biTree).lChild);
		printf("%d ",(*biTree).value);
		inOrder((*biTree).rChild);
	}
}


int main(){
	
	BiTNode *q=NULL;
	BiTree root;
	SqStack sqStack;
	
	//构造树
	root=initTree(root);
	root=constructTree(root);

	//构造栈
	sqStack=initStack(sqStack);
	
	printf("\n");
	
	printf("中序:");
	inOrder(root);
	
	printf("\n");

	printf("中序的非递归代码:");
	while(root!=NULL || 1==stackEmpty(sqStack)){
		if(root!=NULL){
			push(sqStack,root);
			root=root->lChild;
		}else{
			root=pop(sqStack);
			printf("%d ",root->value);
			root=root->rChild;
		}
	}

	
	return 0;
}

//二叉树--链式存储
#include <stdio.h>
#include <stdlib.h> 
#define MAXSIZE 100

struct BiTNode{
	
	//数据域 
	int value; 
	
	//左孩子 
	struct BiTNode *lChild;
	
	//右孩子 
	struct BiTNode *rChild;
}; 

typedef struct BiTNode BiTNode;

typedef struct BiTNode* BiTree;

struct LNode{
	BiTNode* data;
	struct LNode *next;
	
};

typedef struct LNode LNode;
typedef struct LNode* SqStack;

/*
	初始化链式栈:
		1、头指针指向头结点 
		2、头结点的next初始化为NULL
	
	返回一个SqStack型变量:
		具体的值--成功
		NULL--失败	 
*/
SqStack initStack(SqStack sqStack){
	
	LNode* newLNode=(LNode*)malloc(sizeof(LNode));
	
	if(newLNode==NULL){
		return NULL;
	} 
	
	(*newLNode).next=NULL;
	
	sqStack=newLNode;
	
	return sqStack;
}

/*
	判空栈 
	
	返回值
		0--空 
		1--非空 
*/
int stackEmpty(SqStack sqStack){
	
	if(sqStack==NULL){
		return 0;
	}
	
	if((*sqStack).next!=NULL){
		return 1;
	}else{
		return 0;	
	}	
}

/*
	进栈
	
	返回值
		0--失败
		1--成功 
*/
int push(SqStack sqStack,BiTNode* data){
	
	//指向头结点 
	LNode *tmp=sqStack;
	
	if(tmp==NULL){
		return 0;
	}
	
	LNode *newLNode=(LNode *)malloc(sizeof(LNode));
	if(newLNode==NULL){
		return 0;
	}
	(*newLNode).data=data;
	(*newLNode).next=(*tmp).next;
	(*tmp).next=newLNode;
	
	return 1;	
}

/*
	出栈
	
	返回值
		0--失败
		1--成功 
*/
BiTNode * pop(SqStack sqStack){
	
	//指向头结点 
	LNode *tmp=sqStack;
	
	//指向第一个结点 
	LNode *p=(*tmp).next;
	
	BiTNode *data=(*p).data;
	(*tmp).next=(*p).next;
	
	free(p);
	
	return data;	
}

/*
	初始化tree 
*/
BiTNode* initTree(BiTree root){
	
	root=NULL;
	
	return root;
}

/*
	构造树 
*/
BiTNode* constructTree(BiTree root){
	
	BiTNode *p11=(BiTNode *)malloc(sizeof(BiTNode));
	(*p11).value=11;
	(*p11).lChild=NULL;
	(*p11).rChild=NULL;
	
	BiTNode *p12=(BiTNode *)malloc(sizeof(BiTNode));
	(*p12).value=12;
	(*p12).lChild=NULL;
	(*p12).rChild=NULL;
	
	BiTNode *p5=(BiTNode *)malloc(sizeof(BiTNode));
	(*p5).value=5;
	(*p5).lChild=NULL;
	(*p5).rChild=p11;
	
	BiTNode *p6=(BiTNode *)malloc(sizeof(BiTNode));
	(*p6).value=6;
	(*p6).lChild=p12;
	(*p6).rChild=NULL;
	
	BiTNode *p7=(BiTNode *)malloc(sizeof(BiTNode));
	(*p7).value=7;
	(*p7).lChild=NULL;
	(*p7).rChild=NULL;
	
	BiTNode *p2=(BiTNode *)malloc(sizeof(BiTNode));
	(*p2).value=2;
	(*p2).lChild=NULL;
	(*p2).rChild=p5;
	
	BiTNode *p3=(BiTNode *)malloc(sizeof(BiTNode));
	(*p3).value=3;
	(*p3).lChild=p6;
	(*p3).rChild=p7;
	
	BiTNode *p1=(BiTNode *)malloc(sizeof(BiTNode));
	(*p1).value=1;
	(*p1).lChild=p2;
	(*p1).rChild=p3;
	
	root=p1;
	
	return root;
}

/*
	先序遍历--根左右 
*/ 
void preOrder(BiTree biTree){
	
	if(biTree!=NULL){
		printf("%d ",(*biTree).value);
		preOrder((*biTree).lChild);
		preOrder((*biTree).rChild);
	}
	
}


int main(){
	
	BiTNode *q=NULL;
	BiTree root;
	SqStack sqStack;
	
	//构造树
	root=initTree(root);
	root=constructTree(root);

	//构造栈
	sqStack=initStack(sqStack);
	
	printf("\n");
	
	printf("先序:");
	preOrder(root);
	
	printf("\n");

	printf("先序的非递归代码:");
	while(root!=NULL || 1==stackEmpty(sqStack)){
		if(root!=NULL){
			printf("%d ",root->value);
			push(sqStack,root);
			root=root->lChild;
		}else{
			root=pop(sqStack);
			root=root->rChild;
		}
	}

	
	return 0;
}

后序遍历的非递归实现是三种遍历方法中最难的。因为在后序遍历中,要保证左孩子和右孩子都已被访问并且左孩子在右孩子前访问才能访问根结点,这就为流程的控制带来了难题。
后序非递归遍历算法的思路分析:从根结点开始,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,但是此时不能出栈并访问,因为如果其有右子树,还需按相同的规则对其右子树进行处理。直至上述操作进行不下去,若栈顶元素想要出栈被访问,要么右子树为空,要么右子树刚被访问完(此时左子树早已访问完),这样就保证了正确的访问顺序。

算法思想:
1、先沿根结点,依次入栈,直到左孩子为空
2、读取栈顶元素;如果其右孩子不空且未被访问过,将右子树转执行
3、否则,栈顶元素出栈并访问

//二叉树--链式存储
#include <stdio.h>
#include <stdlib.h> 
#define MAXSIZE 100

struct BiTNode{
	
	//数据域 
	int value; 
	
	//左孩子 
	struct BiTNode *lChild;
	
	//右孩子 
	struct BiTNode *rChild;
}; 

typedef struct BiTNode BiTNode;

typedef struct BiTNode* BiTree;

struct LNode{
	BiTNode* data;
	struct LNode *next;
	
};

typedef struct LNode LNode;
typedef struct LNode* SqStack;

/*
	初始化链式栈:
		1、头指针指向头结点 
		2、头结点的next初始化为NULL
	
	返回一个SqStack型变量:
		具体的值--成功
		NULL--失败	 
*/
SqStack initStack(SqStack sqStack){
	
	LNode* newLNode=(LNode*)malloc(sizeof(LNode));
	
	if(newLNode==NULL){
		return NULL;
	} 
	
	(*newLNode).next=NULL;
	
	sqStack=newLNode;
	
	return sqStack;
}

/*
	判空栈 
	
	返回值
		0--空 
		1--非空 
*/
int stackEmpty(SqStack sqStack){
	
	if(sqStack==NULL){
		return 0;
	}
	
	if((*sqStack).next!=NULL){
		return 1;
	}else{
		return 0;	
	}	
}

/*
	进栈
	
	返回值
		0--失败
		1--成功 
*/
int push(SqStack sqStack,BiTNode* data){
	
	//指向头结点 
	LNode *tmp=sqStack;
	
	if(tmp==NULL){
		return 0;
	}
	
	LNode *newLNode=(LNode *)malloc(sizeof(LNode));
	if(newLNode==NULL){
		return 0;
	}
	(*newLNode).data=data;
	(*newLNode).next=(*tmp).next;
	(*tmp).next=newLNode;
	
	return 1;	
}

/*
	出栈
	
	返回值
		0--失败
		1--成功 
*/
BiTNode * pop(SqStack sqStack){
	
	//指向头结点 
	LNode *tmp=sqStack;
	
	//指向第一个结点 
	LNode *p=(*tmp).next;
	
	BiTNode *data=(*p).data;
	(*tmp).next=(*p).next;
	
	free(p);
	
	return data;	
}

/*
	获取栈顶元素
	
	返回值
		0--失败
		1--成功 
*/
BiTNode * getTop(SqStack sqStack){
	
	//指向头结点 
	LNode *tmp=sqStack;
	
	//指向第一个结点 
	LNode *p=(*tmp).next;
	
	BiTNode *data=(*p).data;
	
	return data;	
}

/*
	初始化tree 
*/
BiTNode* initTree(BiTree root){
	
	root=NULL;
	
	return root;
}

/*
	构造树 
*/
BiTNode* constructTree(BiTree root){
	
	BiTNode *p11=(BiTNode *)malloc(sizeof(BiTNode));
	(*p11).value=11;
	(*p11).lChild=NULL;
	(*p11).rChild=NULL;
	
	BiTNode *p12=(BiTNode *)malloc(sizeof(BiTNode));
	(*p12).value=12;
	(*p12).lChild=NULL;
	(*p12).rChild=NULL;
	
	BiTNode *p5=(BiTNode *)malloc(sizeof(BiTNode));
	(*p5).value=5;
	(*p5).lChild=NULL;
	(*p5).rChild=p11;
	
	BiTNode *p6=(BiTNode *)malloc(sizeof(BiTNode));
	(*p6).value=6;
	(*p6).lChild=p12;
	(*p6).rChild=NULL;
	
	BiTNode *p7=(BiTNode *)malloc(sizeof(BiTNode));
	(*p7).value=7;
	(*p7).lChild=NULL;
	(*p7).rChild=NULL;
	
	BiTNode *p2=(BiTNode *)malloc(sizeof(BiTNode));
	(*p2).value=2;
	(*p2).lChild=NULL;
	(*p2).rChild=p5;
	
	BiTNode *p3=(BiTNode *)malloc(sizeof(BiTNode));
	(*p3).value=3;
	(*p3).lChild=p6;
	(*p3).rChild=p7;
	
	BiTNode *p1=(BiTNode *)malloc(sizeof(BiTNode));
	(*p1).value=1;
	(*p1).lChild=p2;
	(*p1).rChild=p3;
	
	root=p1;
	
	return root;
}

/*
	后序遍历--左右根 
*/
void postOrder(BiTree biTree){
	if(biTree!=NULL){
		postOrder((*biTree).lChild);
		postOrder((*biTree).rChild);
		printf("%d ",(*biTree).value);
	}
}


int main(){
	
	BiTNode *q=NULL;
	BiTNode *r=NULL;
	BiTree root;
	SqStack sqStack;
	
	//构造树
	root=initTree(root);
	root=constructTree(root);

	//构造栈
	sqStack=initStack(sqStack);
	
	printf("\n");
	
	printf("后序:");
	postOrder(root);
	
	printf("\n");

	printf("后序的非递归代码:");
	while(root!=NULL || 1==stackEmpty(sqStack)){
		if(root!=NULL){
			push(sqStack,root);
			root=root->lChild;
		}else{
			//获取栈顶元素
			root=getTop(sqStack);
			//右子树存在,且未被访问过
			//可以看出root指针指向栈顶元素时,如果元素存在右子树,且r指针保留了访问过的右子树,就会阻止访问,
			//直接使栈顶元素出栈这也是后序遍历不同于先序、中序,所要特别处理的地方。
			if(root->rChild!=NULL&&root->rChild!=r){
				root=root->rChild;
			}else{
				//弹出结点并访问
				root=pop(sqStack);
				printf("%d ",root->value);
				//记录最近访问的结点
				r=root;
				//结点访问完,重置指针
				root=NULL;
			}
		}
	}

	
	return 0;
}


5、层次遍历
在这里插入图片描述在这里插入图片描述在这里插入图片描述

在这里插入图片描述

6、由遍历序列构造二叉树

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.4.2 代码阶段性总结

以下代码所用的二叉树如下图
在这里插入图片描述

//二叉树--链式存储
#include <stdio.h>
#include <stdlib.h> 
#define MAXSIZE 100

struct BiTNode{
	
	//数据域 
	int value; 
	
	//左孩子 
	struct BiTNode *lChild;
	
	//右孩子 
	struct BiTNode *rChild;
}; 

typedef struct BiTNode BiTNode;

typedef struct BiTNode* BiTree;

struct LinkNode{
	BiTNode* data;
	struct LinkNode *next;
};

typedef struct LinkNode LinkNode;

struct LinkQueue{
	LinkNode *front;
	LinkNode *rear;
};

typedef struct LinkQueue LinkQueue;

/*
	初始化tree 
*/
BiTNode* initTree(BiTree root){
	
	root=NULL;
	
	return root;
}

/*
	构造树 
*/
BiTNode* constructTree(BiTree root){
	
	BiTNode *p11=(BiTNode *)malloc(sizeof(BiTNode));
	(*p11).value=11;
	(*p11).lChild=NULL;
	(*p11).rChild=NULL;
	
	BiTNode *p12=(BiTNode *)malloc(sizeof(BiTNode));
	(*p12).value=12;
	(*p12).lChild=NULL;
	(*p12).rChild=NULL;
	
	BiTNode *p5=(BiTNode *)malloc(sizeof(BiTNode));
	(*p5).value=5;
	(*p5).lChild=NULL;
	(*p5).rChild=p11;
	
	BiTNode *p6=(BiTNode *)malloc(sizeof(BiTNode));
	(*p6).value=6;
	(*p6).lChild=p12;
	(*p6).rChild=NULL;
	
	BiTNode *p7=(BiTNode *)malloc(sizeof(BiTNode));
	(*p7).value=7;
	(*p7).lChild=NULL;
	(*p7).rChild=NULL;
	
	BiTNode *p2=(BiTNode *)malloc(sizeof(BiTNode));
	(*p2).value=2;
	(*p2).lChild=NULL;
	(*p2).rChild=p5;
	
	BiTNode *p3=(BiTNode *)malloc(sizeof(BiTNode));
	(*p3).value=3;
	(*p3).lChild=p6;
	(*p3).rChild=p7;
	
	BiTNode *p1=(BiTNode *)malloc(sizeof(BiTNode));
	(*p1).value=1;
	(*p1).lChild=p2;
	(*p1).rChild=p3;
	
	root=p1;
	
	return root;
}

/*
	先序遍历--根左右 
*/ 
void preOrder(BiTree biTree){
	
	if(biTree!=NULL){
		printf("%d ",(*biTree).value);
		preOrder((*biTree).lChild);
		preOrder((*biTree).rChild);
	}
	
}

/*
	中序遍历--左根右 
*/
void inOrder(BiTree biTree){
	if(biTree!=NULL){
		inOrder((*biTree).lChild);
		printf("%d ",(*biTree).value);
		inOrder((*biTree).rChild);
	}
}

/*
	后序遍历--左右根 
*/
void postOrder(BiTree biTree){
	if(biTree!=NULL){
		postOrder((*biTree).lChild);
		postOrder((*biTree).rChild);
		printf("%d ",(*biTree).value);
	}
}

/*
	树的深度 
*/
int treeDepth(BiTree root){
	
	if(root==NULL){
		return 0;
	}else{
		int l=treeDepth((*root).lChild);
		int r=treeDepth((*root).rChild);
		
		return l>r?l+1:r+1;
	}
	
}

/*
	初始化队列
	
	返回值
		0--失败
		1--成功 
*/
int initQueue(LinkQueue *queue){
	LinkNode *newNode=(LinkNode *)malloc(sizeof(LinkNode));
	if(newNode==NULL){
		return 0;
	}
	
	(*newNode).next=NULL;
	
	(*queue).front=newNode;
	(*queue).rear=newNode;
}

/*
	入队操作
	
	返回值
		0--失败 
		1--成功 
*/
int enQueue(LinkQueue *queue,BiTNode* data){
	
	LinkNode *newNode=(LinkNode *)malloc(sizeof(LinkNode));
	if(newNode==NULL){
		return 0;
	}
	(*newNode).data=data;
	(*newNode).next=NULL; 
	
	(*queue).rear->next=newNode;
	
	(*queue).rear=newNode;
	
	return 1;
		
}

/*
	出队操作
*/
BiTNode* deQueue(LinkQueue *queue){
	
	LinkNode *front=(*queue).front;
	LinkNode *rear=(*queue).rear; 
	
	//被出队的结点--头结点的下一个结点 
	LinkNode *tmpNode=(*front).next;
	BiTNode* result=(*tmpNode).data;
	(*front).next=(*tmpNode).next;
	if((*tmpNode).next==NULL){
		(*queue).rear=front;	
	}
	
	free(tmpNode); 
	
	return result;
		
}

/*
	判断队列是否为空
		1--为空
		0--不为空 
*/
int queueEmpty(LinkQueue queue){
	if(queue.front==queue.rear){
		return 1;
	}else{
		return 0;
	}
}

/*
	层次遍历 
*/
void levelOrder(BiTree root){
	
	if(root==NULL){
		return ;
	}
	
	LinkQueue linkQueue;
	
	initQueue(&linkQueue);
	
	enQueue(&linkQueue,root);
	
	BiTNode* p;
	
	while(queueEmpty(linkQueue)==0){
		
		p=deQueue(&linkQueue);
		
		printf("%d ",(*p).value);
		
		if((*p).lChild!=NULL){
			enQueue(&linkQueue,(*p).lChild);
		}
		if((*p).rChild!=NULL){
			enQueue(&linkQueue,(*p).rChild);
		}	
		
	}
	
}

BiTNode *tmpResult=NULL;

/*
	利用先序遍历,找到某一节点,并赋值给tmpResult
*/
void preOrderTwo(BiTree biTree){
	
	if(biTree!=NULL){
		if((*biTree).value==5){
			tmpResult=biTree;
		}
		preOrderTwo((*biTree).lChild);
		preOrderTwo((*biTree).rChild);
	}
	
}

BiTNode *q1=NULL;

/*
	中序前驱 
		q1-->当前被访问的结点
		pre-->上一个被访问的结点
		target-->求target结点的前驱
		
		只要target==q1,pre就是target的前驱结点
		最后将pre赋值给tmpResult
*/
void inPreBiTNode(BiTree biTree,BiTNode *target){
	BiTNode *pre=NULL;
	if(biTree!=NULL){ 
		inPreBiTNode((*biTree).lChild,target);
		pre=q1;
		q1=biTree;
		if(q1==target){
			tmpResult=pre;	
		}
		inPreBiTNode((*biTree).rChild,target);
	}
}

/*
	中序后继 
		q1-->当前被访问的结点
		pre-->上一个被访问的结点
		target-->求target结点的前驱
		
		只要target==pre,q1就是target的后继结点
		最后将q赋值给tmpResult
*/
void inNextBiTNode(BiTree biTree,BiTNode *target){
	BiTNode *pre=NULL;
	if(biTree!=NULL){ 
		inNextBiTNode((*biTree).lChild,target);
		pre=q1;
		q1=biTree;
		if(pre==target){
			tmpResult=q1;	
		}
		inNextBiTNode((*biTree).rChild,target);
	}
}

BiTNode *q2=NULL;
/*
	先序前驱 
*/ 
void prePreBiTNode(BiTree biTree,BiTNode *target){
	
	BiTNode *pre=NULL;
	if(biTree!=NULL){ 
		pre=q2;
		q2=biTree;
		if(q2==target){
			tmpResult=pre;	
		}
		prePreBiTNode((*biTree).lChild,target);
		prePreBiTNode((*biTree).rChild,target);
	}
	
}

/*
	先序后继 
*/
void preNextBiTNode(BiTree biTree,BiTNode *target){
	
	BiTNode *pre=NULL;
	if(biTree!=NULL){ 
		pre=q2;
		q2=biTree;
		if(pre==target){
			tmpResult=q2;	
		}
		preNextBiTNode((*biTree).lChild,target);
		preNextBiTNode((*biTree).rChild,target);
	}
}

BiTNode *q3=NULL;

/*
	后序前驱 
*/ 
void postPreBiTNode(BiTree biTree,BiTNode *target){
	
	BiTNode *pre=NULL;
	if(biTree!=NULL){ 
		postPreBiTNode((*biTree).lChild,target);
		postPreBiTNode((*biTree).rChild,target);
		pre=q3;
		q3=biTree;
		if(q3==target){
			tmpResult=pre;	
		}
	}
	
}

/*
	后序后继 
*/
void postNextBiTNode(BiTree biTree,BiTNode *target){
	
	BiTNode *pre=NULL;
	if(biTree!=NULL){ 
		postNextBiTNode((*biTree).lChild,target);
		postNextBiTNode((*biTree).rChild,target);
		pre=q3;
		q3=biTree;
		if(pre==target){
			tmpResult=q3;	
		}
	}
}

int main(){
	
	BiTNode *q=NULL;
	
	BiTree root;
	
	root=initTree(root);
	
	root=constructTree(root);
	
	printf("先序:");
	preOrder(root);
	
	printf("\n");
	
	printf("中序:");
	inOrder(root);
	
	printf("\n");
	
	printf("后序:");
	postOrder(root); 
	
	printf("\n");
	
	printf("深度:");
	printf("%d",treeDepth(root));
	
	printf("\n");
	
	printf("层次:");
	levelOrder(root);
	
	printf("\n");
	
	preOrderTwo(root);
	
	printf("\n");
	
	inPreBiTNode(root,tmpResult);
	
	printf("结点5的中序前驱是:%d",(*tmpResult).value);
	
	printf("\n");
	
	preOrderTwo(root);
	
	printf("\n");
	
	inNextBiTNode(root,tmpResult);
	
	printf("结点5的中序后继是:%d",(*tmpResult).value);
	
	printf("\n");
	
	preOrderTwo(root);
	
	printf("\n");
	
	prePreBiTNode(root,tmpResult);
	
	printf("结点5的先序前驱是:%d",(*tmpResult).value);
	
	printf("\n");
	
	preOrderTwo(root);
	
	printf("\n");
	
	preNextBiTNode(root,tmpResult);
	
	printf("结点5的先序后继是:%d",(*tmpResult).value);
	
	printf("\n");
	
	preOrderTwo(root);
	
	printf("\n");
	
	postPreBiTNode(root,tmpResult);
	
	printf("结点5的后序前驱是:%d",(*tmpResult).value);
	
	printf("\n");
	
	preOrderTwo(root);
	
	printf("\n");
	
	postNextBiTNode(root,tmpResult);
	
	printf("结点5的后序后继是:%d",(*tmpResult).value);
	
	return 0;
}
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100

struct BiTNode{
	int value;
	struct BiTNode *lChild;
	struct BiTNode *rChild;
};

typedef struct BiTNode BiTNode;
typedef struct BiTNode* BiTree;

struct LinkNode{
	BiTNode *data;
	struct LinkNode *next;
};

typedef struct LinkNode LinkNode;

struct LinkQueue{
	LinkNode *front;
	LinkNode *rear;
};

typedef struct LinkQueue LinkQueue;

BiTNode* initTree(BiTree root){
	root=NULL;
	return root;
}

BiTNode* constructTree(BiTree root){
	BiTNode *p11=(BiTNode *)malloc(sizeof(BiTNode));
	p11->value=11;
	p11->lChild=NULL;
	p11->rChild=NULL;
	
	BiTNode *p12=(BiTNode *)malloc(sizeof(BiTNode));
	p12->value=12;
	p12->lChild=NULL;
	p12->rChild=NULL;
	
	BiTNode *p5=(BiTNode *)malloc(sizeof(BiTNode));
	p5->value=5;
	p5->lChild=NULL;
	p5->rChild=p11;
	
	BiTNode *p6=(BiTNode *)malloc(sizeof(BiTNode));
	p6->value=6;
	p6->lChild=p12;
	p6->rChild=NULL;
	
	BiTNode *p7=(BiTNode *)malloc(sizeof(BiTNode));
	p7->value=7;
	p7->lChild=NULL;
	p7->rChild=NULL;
	
	BiTNode *p2=(BiTNode *)malloc(sizeof(BiTNode));
	p2->value=2;
	p2->lChild=NULL;
	p2->rChild=p5;
	
	BiTNode *p3=(BiTNode *)malloc(sizeof(BiTNode));
	p3->value=3;
	p3->lChild=p6;
	p3->rChild=p7;
	
	BiTNode *p1=(BiTNode *)malloc(sizeof(BiTNode));
	p1->value=1;
	p1->lChild=p2;
	p1->rChild=p3;
	
	root=p1;
	
	return root;
}

void preOrder(BiTree biTree){
	
	if(biTree!=NULL){
		printf("%d",biTree->value);
		preOrder(biTree->lChild);
		preOrder(biTree->rChild);
	}
	
}

void inOrder(BiTree biTree){
	if(biTree!=NULL){
		inOrder(biTree->lChild);
		printf("%d",biTree->value);
		inOrder(biTree->rChild);
	}
}

void postOrder(BiTree biTree){
	if(biTree!=NULL){
		postOrder(biTree->lChild);
		postOrder(biTree->rChild);
		printf("%d",biTree->value);
	}
}

int treeDepth(BiTree root){
	if(root==NULL){
		return 0;
	}else{
		int l=treeDepth(root->lChild);
		int r=treeDepth(root->rChild);
		
		return l>r?l+1:r+1;
	}
}

int initQueue(LinkQueue *queue){
	LinkNode *newNode=(LinkNode *)malloc(sizeof(LinkNode));
	if(newNode==NULL){
		return 0;
	}
	
	newNode->next=NULL;
	
	queue->front=newNode;
	
	queue->rear=newNode;
	
	return 1;
}

int enQueue(LinkQueue *queue,BiTNode *data){
	
	LinkNode *newNode=(LinkNode *)malloc(sizeof(LinkNode));
	if(newNode==NULL){
		return 0;
	}
	
	newNode->data=data;
	newNode->next=NULL;
	
	queue->rear->next=newNode;
	
	queue->rear=newNode;
	
	return 1;
}

int queueEmpty(LinkQueue queue){
	if(queue.front==queue.rear){
		return 1;
	}else{
		return 0;
	}
}

BiTNode* deQueue(LinkQueue *queue){
	
	LinkNode *front=queue->front;
	LinkNode *rear=queue->rear;
	
	LinkNode *tmpNode=front->next;
	BiTNode* result=tmpNode->data;
	front->next=tmpNode->next;
	if(tmpNode->next==NULL){
		queue->rear=front;
	}
	
	free(tmpNode);
	
	return result;
	
} 

void levelOrder(BiTree root){
	
	if(root==NULL){
		return ;
	}
	
	LinkQueue linkQueue;
	
	initQueue(&linkQueue);
	
	enQueue(&linkQueue,root);
	
	BiTNode* p;
	
	while(queueEmpty(linkQueue)==0){
		p=deQueue(&linkQueue);
		printf("%d ",p->value);
		if(p->lChild!=NULL){
			enQueue(&linkQueue,p->lChild);
		}
		if(p->rChild!=NULL){
			enQueue(&linkQueue,p->rChild);
		}
	}
}

BiTNode *tmpResult=NULL;

void preOrderTwo(BiTree biTree){
	if(biTree!=NULL){
		if(biTree->value==5){
			tmpResult=biTree;
		}
		preOrderTwo(biTree->lChild);
		preOrderTwo(biTree->rChild);
	}
}

BiTNode *q1=NULL;
void inPreBiTNode(BiTree biTree,BiTNode *target){
	BiTNode *pre=NULL;
	if(biTree!=NULL){
		inPreBiTNode(biTree->lChild,target);
		pre=q1;
		q1=biTree;
		if(q1==target){
			tmpResult=pre;
		}
		inPreBiTNode(biTree->rChild,target);
	}
}
void inNextBiTNode(BiTree biTree,BiTNode *target){
	BiTNode *pre=NULL;
	if(biTree!=NULL){
		inNextBiTNode(biTree->lChild,target);
		pre=q1;
		q1=biTree;
		if(pre==target){
			tmpResult=q1;
		}
		inNextBiTNode(biTree->rChild,target);
	}
}

BiTNode *q2=NULL;
void prePreBiTNode(BiTree biTree,BiTNode *target){
	BiTNode *pre=NULL;
	if(biTree!=NULL){
		pre=q2;
		q2=biTree;
		if(q2==target){
			tmpResult=pre;
		}
		prePreBiTNode(biTree->lChild,target);
		prePreBiTNode(biTree->rChild,target);
	}
}
void preNextBiTNode(BiTree biTree,BiTNode *target){
	BiTNode *pre=NULL;
	if(biTree!=NULL){
		pre=q2;
		q2=biTree;
		if(pre==target){
			tmpResult=q2;
		}
		preNextBiTNode(biTree->lChild,target);
		preNextBiTNode(biTree->rChild,target);
	}
}

BiTNode *q3=NULL;
void postPreBiTNode(BiTree biTree,BiTNode *target){
	BiTNode *pre=NULL;
	if(biTree!=NULL){
		postPreBiTNode(biTree->lChild,target);
		postPreBiTNode(biTree->rChild,target);
		pre=q3;
		q3=biTree;
		if(q3==target){
			tmpResult=pre;
		}
	}
}
void postNextBiTNode(BiTree biTree,BiTNode *target){
	BiTNode *pre=NULL;
	if(biTree!=NULL){
		postNextBiTNode(biTree->lChild,target);
		postNextBiTNode(biTree->rChild,target);
		pre=q3;
		q3=biTree;
		if(pre==target){
			tmpResult=q3;
		}
	}
}



int main(){
	
	BiTNode *q=NULL;
	
	BiTree root;
	
	root=initTree(root);
	
	root=constructTree(root);
	
	printf("先序:");
	preOrder(root);
	
	printf("\n");
	
	printf("中序:");
	inOrder(root);
	
	printf("\n");
	
	printf("后序:");
	postOrder(root); 
	
	printf("\n");
	
	printf("深度:");
	printf("%d",treeDepth(root));
	
	printf("\n");
	
	printf("层次:");
	levelOrder(root);
	
	printf("\n");
	
	preOrderTwo(root);
	
	printf("\n");
	
	inPreBiTNode(root,tmpResult);
	
	printf("结点5的中序前驱是:%d",(*tmpResult).value);
	
	printf("\n");
	
	preOrderTwo(root);
	
	printf("\n");
	
	inNextBiTNode(root,tmpResult);
	
	printf("结点5的中序后继是:%d",(*tmpResult).value);
	
	printf("\n");
	
	preOrderTwo(root);
	
	printf("\n");
	
	prePreBiTNode(root,tmpResult);
	
	printf("结点5的先序前驱是:%d",(*tmpResult).value);
	
	printf("\n");
	
	preOrderTwo(root);
	
	printf("\n");
	
	preNextBiTNode(root,tmpResult);
	
	printf("结点5的先序后继是:%d",(*tmpResult).value);
	
	printf("\n");
	
	preOrderTwo(root);
	
	printf("\n");
	
	postPreBiTNode(root,tmpResult);
	
	printf("结点5的后序前驱是:%d",(*tmpResult).value);
	
	printf("\n");
	
	preOrderTwo(root);
	
	printf("\n");
	
	postNextBiTNode(root,tmpResult);
	
	printf("结点5的后序后继是:%d",(*tmpResult).value);
	
	return 0;
}

5.4.3 线索二叉树

1、线索二叉树的基本概念
遍历二叉树是以一定的规则将二叉树中的结点排列成一个线性序列,从而得到几种遍历序列,使得该序列中的每个结点(第一个和最后一个结点除外)都有一个直接前驱和直接后继。

在这里插入图片描述
规定:若无左子树,令lchild指向其前驱结点;若无右子树,令rchild指向其后继结点。如图5.10所示,还需增加两个标志域标识指针域是指向左(右)孩子还是指向前驱后继)。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
2、线索二叉树的构造
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
右指针存放的是后继,后继的确定是上一个结点pre确定,上一个结点早就遍历完了,所以不会出现循环现象

左指针存放的是前驱,先序的左是第二个遍历,如果左指针存放了根,接下来遍历左子树,就会造成循环;而中序和后序是先遍历左,所以不会造成循环

3、线索二叉树找前驱/后继
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.4.4 线索二叉树代码

中序线索二叉树

//二叉树--链式存储
#include <stdio.h>
#include <stdlib.h> 
#define MAXSIZE 100

struct ThreadNode{
	
	//数据域 
	int value; 
	
	//左孩子 
	struct ThreadNode *lChild;
	
	//右孩子 
	struct ThreadNode *rChild;
	
	//1--前驱结点  0--左孩子 
	int ltag;
	
	//1--后继结点  0--右孩子 
	int rtag;
	
}; 

typedef struct ThreadNode ThreadNode;

typedef struct ThreadNode* ThreadTree;


/*
	初始化tree 
*/
ThreadTree* initTree(ThreadTree root){
	
	root=NULL;
	
	return root;
}

/*
	构造树 
*/
ThreadTree* constructTree(ThreadTree root){
	
	ThreadNode *p11=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p11).ltag=0;
	(*p11).rtag=0;
	(*p11).value=11;
	(*p11).lChild=NULL;
	(*p11).rChild=NULL;
	
	ThreadNode *p12=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p12).ltag=0;
	(*p12).rtag=0;
	(*p12).value=12;
	(*p12).lChild=NULL;
	(*p12).rChild=NULL;
	
	ThreadNode *p5=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p5).ltag=0;
	(*p5).rtag=0;
	(*p5).value=5;
	(*p5).lChild=NULL;
	(*p5).rChild=p11;
	
	ThreadNode *p6=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p6).ltag=0;
	(*p6).rtag=0;
	(*p6).value=6;
	(*p6).lChild=p12;
	(*p6).rChild=NULL;
	
	ThreadNode *p7=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p7).ltag=0;
	(*p7).rtag=0;
	(*p7).value=7;
	(*p7).lChild=NULL;
	(*p7).rChild=NULL;
	
	ThreadNode *p2=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p2).ltag=0;
	(*p2).rtag=0;
	(*p2).value=2;
	(*p2).lChild=NULL;
	(*p2).rChild=p5;
	
	ThreadNode *p3=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p3).ltag=0;
	(*p3).rtag=0;
	(*p3).value=3;
	(*p3).lChild=p6;
	(*p3).rChild=p7;
	
	ThreadNode *p1=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p1).ltag=0;
	(*p1).rtag=0;
	(*p1).value=1;
	(*p1).lChild=p2;
	(*p1).rChild=p3;
	
	root=p1;
	
	return root;
}

//指向当前被访问的结点 
ThreadNode *q=NULL;

/*
	创建中序线索二叉树  
*/
void createInThread(ThreadTree root){
	
	if(root!=NULL){
		inThread(root);
		if((*q).rChild==NULL){
			(*q).rtag=1;
		}
	} 
	
}

/*
	中序线索二叉树 
*/
void inThread(ThreadTree root){
	ThreadNode *pre=NULL;
	if(root!=NULL){ 
		inThread((*root).lChild);
		pre=q;
		q=root;
		if((*q).lChild==NULL){
			(*q).lChild=pre;
			(*q).ltag=1;
		}
		if(pre!=NULL&&(*pre).rChild==NULL){
			(*pre).rChild=q;
			(*pre).rtag=1;
		}
		inThread((*root).rChild);
	}
}

/*
	找到以p为根的子树中,第一个被中序遍历的结点 
*/ 
ThreadNode* inFirstNode(ThreadNode *p){
	//循环找到最左下结点(不一定是叶子结点)
	while((*p).ltag==0){
		p=(*p).lChild;
	} 
	
	return p;
}

/*
	中序线索二叉树中找到结点p的后继结点 
*/
ThreadNode* inNextNode(ThreadNode *p){
	//右子树中最左下结点
	if((*p).rtag==0){
		return inFirstNode((*p).rChild);
	}else{
		return (*p).rChild;
	}	
} 

/*
	对中序线索二叉树进行中序遍历(利用线索实现的非递归算法) 
*/
void inOrder(ThreadTree root){
	ThreadNode *p=inFirstNode(root);
	for(;p!=NULL;p=inNextNode(p)){
		printf("%d ",(*p).value);
	}
}

/*
	找到以p为根的子树中,最后一个被中序遍历的结点 
*/ 
ThreadNode* inLastNode(ThreadNode *p){
	
	//循环找到最右下结点(不一定是叶子结点)
	while((*p).rtag==0){
		p=(*p).rChild;
	} 
	
	return p;
}

/*
	中序线索二叉树中找到结点p的前驱结点 
*/
ThreadNode* inPreNode(ThreadNode *p){
	//左子树中最右下结点
	if((*p).ltag==0){
		return inLastNode((*p).lChild);
	}else{
		return (*p).lChild;
	}	
} 

/*
	对中序线索二叉树进行逆中序遍历
*/
void revInOrder(ThreadTree root){
	ThreadNode *p=inLastNode(root);
	for(;p!=NULL;p=inPreNode(p)){
		printf("%d ",(*p).value);
	}
}



int main(){
	
	ThreadTree root;
	
	root=initTree(root);
	
	root=constructTree(root);
	
	createInThread(root);
	
	inOrder(root);
	
	printf("\n");
	
	revInOrder(root);
	 
	return 0;
}

先序线索二叉树

//二叉树--链式存储
#include <stdio.h>
#include <stdlib.h> 
#define MAXSIZE 100

struct ThreadNode{
	
	//数据域 
	int value; 
	
	//左孩子 
	struct ThreadNode *lChild;
	
	//右孩子 
	struct ThreadNode *rChild;
	
	//1--前驱结点  0--左孩子 
	int ltag;
	
	//1--后继结点  0--右孩子 
	int rtag;
	
}; 

typedef struct ThreadNode ThreadNode;

typedef struct ThreadNode* ThreadTree;


/*
	初始化tree 
*/
ThreadTree* initTree(ThreadTree root){
	
	root=NULL;
	
	return root;
}

/*
	构造树 
*/
ThreadTree* constructTree(ThreadTree root){
	
	ThreadNode *p11=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p11).ltag=0;
	(*p11).rtag=0;
	(*p11).value=11;
	(*p11).lChild=NULL;
	(*p11).rChild=NULL;
	
	ThreadNode *p12=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p12).ltag=0;
	(*p12).rtag=0;
	(*p12).value=12;
	(*p12).lChild=NULL;
	(*p12).rChild=NULL;
	
	ThreadNode *p5=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p5).ltag=0;
	(*p5).rtag=0;
	(*p5).value=5;
	(*p5).lChild=NULL;
	(*p5).rChild=p11;
	
	ThreadNode *p6=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p6).ltag=0;
	(*p6).rtag=0;
	(*p6).value=6;
	(*p6).lChild=p12;
	(*p6).rChild=NULL;
	
	ThreadNode *p7=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p7).ltag=0;
	(*p7).rtag=0;
	(*p7).value=7;
	(*p7).lChild=NULL;
	(*p7).rChild=NULL;
	
	ThreadNode *p2=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p2).ltag=0;
	(*p2).rtag=0;
	(*p2).value=2;
	(*p2).lChild=NULL;
	(*p2).rChild=p5;
	
	ThreadNode *p3=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p3).ltag=0;
	(*p3).rtag=0;
	(*p3).value=3;
	(*p3).lChild=p6;
	(*p3).rChild=p7;
	
	ThreadNode *p1=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p1).ltag=0;
	(*p1).rtag=0;
	(*p1).value=1;
	(*p1).lChild=p2;
	(*p1).rChild=p3;
	
	root=p1;
	
	return root;
}


//指向当前被访问的结点 
ThreadNode *q1=NULL;

/*
	创建先序线索二叉树 
*/
void createPreThread(ThreadTree root){
	
	if(root!=NULL){
		preThread(root);
		if((*q1).rChild==NULL){
			(*q1).rtag=1;
		}
	} 
	
}

/*
	先序线索二叉树 
*/
void preThread(ThreadTree root){
	ThreadNode *pre=NULL;
	if(root!=NULL){
		pre=q1;
		q1=root;
		if((*q1).lChild==NULL){
			(*q1).lChild=pre;
			(*q1).ltag=1;
		}
		if(pre!=NULL&&(*pre).rChild==NULL){
			(*pre).rChild=q1;
			(*pre).rtag=1;
		}
		
		if((*root).ltag==0){
			preThread((*root).lChild);
		} 
		preThread((*root).rChild);
	}
}


/*
	找到以p为根的子树中,第一个被先序遍历的结点 
*/ 
ThreadNode* preFirstNode(ThreadNode *p){
	
	if(p!=NULL){
		return p;
	} 
	
	return NULL;
}

/*
	先序线索二叉树中找到结点p的后继结点 
*/
ThreadNode* preNextNode(ThreadNode *p){
	
	//右指针存放的是后继,直接返回 
	if((*p).rtag==1){
		return (*p).rChild;
	}else{
		
		//右指针存放的不是后继 
		
		//判断有没有左孩子,有直接返回,否则返回右孩子 
		if((*p).ltag==0){
			return (*p).lChild;
		}else{
			return (*p).rChild;
		} 
		
	}	
} 

int main(){
	 
	return 0;
}

后序线索二叉树

//二叉树--链式存储
#include <stdio.h>
#include <stdlib.h> 
#define MAXSIZE 100

struct ThreadNode{
	
	//数据域 
	int value; 
	
	//左孩子 
	struct ThreadNode *lChild;
	
	//右孩子 
	struct ThreadNode *rChild;
	
	//1--前驱结点  0--左孩子 
	int ltag;
	
	//1--后继结点  0--右孩子 
	int rtag;
	
}; 

typedef struct ThreadNode ThreadNode;

typedef struct ThreadNode* ThreadTree;


/*
	初始化tree 
*/
ThreadTree* initTree(ThreadTree root){
	
	root=NULL;
	
	return root;
}

/*
	构造树 
*/
ThreadTree* constructTree(ThreadTree root){
	
	ThreadNode *p11=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p11).ltag=0;
	(*p11).rtag=0;
	(*p11).value=11;
	(*p11).lChild=NULL;
	(*p11).rChild=NULL;
	
	ThreadNode *p12=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p12).ltag=0;
	(*p12).rtag=0;
	(*p12).value=12;
	(*p12).lChild=NULL;
	(*p12).rChild=NULL;
	
	ThreadNode *p5=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p5).ltag=0;
	(*p5).rtag=0;
	(*p5).value=5;
	(*p5).lChild=NULL;
	(*p5).rChild=p11;
	
	ThreadNode *p6=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p6).ltag=0;
	(*p6).rtag=0;
	(*p6).value=6;
	(*p6).lChild=p12;
	(*p6).rChild=NULL;
	
	ThreadNode *p7=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p7).ltag=0;
	(*p7).rtag=0;
	(*p7).value=7;
	(*p7).lChild=NULL;
	(*p7).rChild=NULL;
	
	ThreadNode *p2=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p2).ltag=0;
	(*p2).rtag=0;
	(*p2).value=2;
	(*p2).lChild=NULL;
	(*p2).rChild=p5;
	
	ThreadNode *p3=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p3).ltag=0;
	(*p3).rtag=0;
	(*p3).value=3;
	(*p3).lChild=p6;
	(*p3).rChild=p7;
	
	ThreadNode *p1=(ThreadNode *)malloc(sizeof(ThreadNode));
	(*p1).ltag=0;
	(*p1).rtag=0;
	(*p1).value=1;
	(*p1).lChild=p2;
	(*p1).rChild=p3;
	
	root=p1;
	
	return root;
}


//指向当前被访问的结点 
ThreadNode *q3=NULL;

/*
	创建后序线索二叉树  
*/
void createPostThread(ThreadTree root){
	
	if(root!=NULL){
		postThread(root);
		if((*q3).rChild==NULL){
			(*q3).rtag=1;
		}
	} 
	
}

/*
	后序线索二叉树 
*/
void postThread(ThreadTree root){
	ThreadNode *pre=NULL;
	if(root!=NULL){ 
		postThread((*root).lChild);
		postThread((*root).rChild);
		pre=q3;
		q3=root;
		if((*q3).lChild==NULL){
			(*q3).lChild=pre;
			(*q3).ltag=1;
		}
		if(pre!=NULL&&(*pre).rChild==NULL){
			(*pre).rChild=q3;
			(*pre).rtag=1;
		}
	}
}

/*
	后序线索二叉树中找到结点p的前驱结点 
*/
ThreadNode* postPreNode(ThreadNode *p){
	
	//左指针存放的是前驱,直接返回 
	if((*p).ltag==1){
		return (*p).ltag;
	}else{
		
		//左指针存放的不是前驱 
		
		//判断有没有右孩子,有直接返回,否则返回左孩子 
		if((*p).rtag==0){
			return (*p).rtag;
		}else{
			return (*p).lChild;
		} 
		
	}	
} 


int main(){
	 
	return 0;
}
 

5.4.5 本节试题精选

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

13、B
在这里插入图片描述
23、C
在这里插入图片描述

30、C
在二叉中序线索树中,某结点若有左孩子,则按照中序“左根右”的顺序,该结点的前驱结点为左子树中最右的一个结点(注意,并不一定是最右叶结点)。

31、C
在这里插入图片描述
34、B
在这里插入图片描述

5.5 树、森林

5.5.1 树的存储结构

1、双亲表示法
在这里插入图片描述注意:区别树的顺序存储结构与二叉树的顺序存储结构。在树的顺序存储结构中,数组下标代表结点的编号,下标中所存的内容指示了结点之间的关系。而在二叉树的顺序存储结构中,数组下标既代表了结点的编号,又指示了二叉树中各结点之间的关系。当然,二叉树属于树,因此二叉树都可以用树的存储结构来存储,但树却不都能用二叉树的存储结构来存储。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2、孩子表示法
在这里插入图片描述
3、孩子兄弟表示法
在这里插入图片描述

5.5.2 树、森林与二叉树的转换

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.5.3 树、森林的遍历

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.5.4 本节试题精选

7、8、9作为结论,8是根据7做出来的



5.6 树与二叉树的应用

5.6.1 BST--二叉排序树

1、二叉排序树的定义
在这里插入图片描述
2、二叉排序树的查找
在这里插入图片描述
在这里插入图片描述
3、二叉排序树的插入
在这里插入图片描述
4、二叉排序树的构造
在这里插入图片描述
5、二叉排序树的删除
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
6、二叉排序树的查找效率分析
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.6.2 二叉排序树代码

//二叉排序树
#include <stdio.h>
#include <stdlib.h> 

struct BSTNode{
	
	//数据域 
	int key; 
	
	//左孩子 
	struct BSTNode *lChild;
	
	//右孩子 
	struct BSTNode *rChild;
	
}; 

typedef struct BSTNode BSTNode;

typedef struct BSTNode* BSTree;

/*
	创建树 
*/ 
BSTree createTree(int key){
	BSTNode *newNode=(BSTNode*)malloc(sizeof(BSTNode));
	(*newNode).key=key;
	(*newNode).lChild=NULL;
	(*newNode).rChild=NULL;
	
	BSTree root=newNode;
	
	return root;
}

/*
	在二叉排序树中查找值为key的结点--非递归 
*/
BSTNode * bstSearchOne(BSTree t, int key){
	
	BSTNode *tempNode=t;
	
	while(tempNode!=NULL&&key!=(*tempNode).key){
		if(key<(*tempNode).key){
			tempNode=(*tempNode).lChild;
		}else{
			tempNode=(*tempNode).rChild;
		}
	}
	
	return tempNode;
} 

/*
	在二叉排序树中查找值为key的结点--递归 
*/
BSTNode * bstSearchTwo(BSTree t, int key){
	
	if(t==NULL){
		return NULL;
	}
	
	if(key==(*t).key){
		return t;
	}
	
	if(key<(*t).key){
		return bstSearchTwo((*t).lChild,key);
	}
	
	if(key>(*t).key){
		return bstSearchTwo((*t).rChild,key);
	}
} 

/*
	在二叉排序树中插入值为key的结点--非递归
	前提--二叉树中根结点不为空,已有数据 
	
		返回值:0--失败  1--成功 
*/

int bstInsertOne(BSTree t, int key){
	
	BSTNode *tempNode=t;
	BSTNode *node=NULL;
	
	BSTNode *newNode=(BSTNode*)malloc(sizeof(BSTNode));
	(*newNode).key=key;
	(*newNode).lChild=NULL;
	(*newNode).rChild=NULL;
	
	while(tempNode!=NULL){
		
		if(key==(*tempNode).key){
			return 0;
		}
		
		node=tempNode;
		
		if(key<(*tempNode).key){
			tempNode=(*tempNode).lChild;
			if(tempNode==NULL){
				(*node).lChild=newNode;
				return 1;
			}
		}else{
			tempNode=(*tempNode).rChild;
			if(tempNode==NULL){
				(*node).rChild=newNode;
				return 1;
			}
		}
	}
} 

/*
	在二叉排序树中插入值为key的结点--递归
	前提--二叉树中根结点不为空,已有数据 
	
		返回值:0--失败  1--成功 
*/

int bstInsertTwo(BSTree t, int key){
	
	BSTNode *tempNode=t;
	BSTNode *node=NULL;
	
	if(key==(*t).key){
		return 0;
	}
	
	if(key<(*tempNode).key){
		node=tempNode;
		tempNode=(*tempNode).lChild;
		if(tempNode==NULL){
			BSTNode *newNode=(BSTNode*)malloc(sizeof(BSTNode));
			(*newNode).key=key;
			(*newNode).lChild=NULL;
			(*newNode).rChild=NULL;
			(*node).lChild=newNode;
			return 1;
		}
		return bstSearchTwo(tempNode,key);
	}
	
	if(key>(*tempNode).key){
		node=tempNode;
		tempNode=(*tempNode).rChild;
		if(tempNode==NULL){
			BSTNode *newNode=(BSTNode*)malloc(sizeof(BSTNode));
			(*newNode).key=key;
			(*newNode).lChild=NULL;
			(*newNode).rChild=NULL;
			(*node).rChild=newNode;
			return 1;
		}
		return bstSearchTwo(tempNode,key);
	}
} 

int main(){
	 
	return 0;
}

5.6.3 AVL--平衡二叉树

1、平衡二叉树的定义
在这里插入图片描述
2、调整最小不平衡子树
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3、查找效率分析
在这里插入图片描述
在这里插入图片描述

5.6.4 哈夫曼树和哈夫曼编码

1、哈夫曼树的定义
在这里插入图片描述
在这里插入图片描述
2、哈夫曼树的构造
在这里插入图片描述
3、哈夫曼编码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.6.5 并查集

介绍

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

优化

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.6.6 本节试题精选

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

posted @ 2022-07-05 18:31  KeepArlen  阅读(131)  评论(0)    收藏  举报