数据结构课程设计——基于二叉链表的二叉树实现(C语言)

写在开头

       《数据结构(C语言版)》严蔚敏等著)一书在描述算法时使用的是类C语言。这种语言是介于伪码语言和程序设计语言之间的一种表示形式,它保留了C语言的精华,同时也添加了一些C++的成分。这种语言不拘泥与C语言的语法细节,便于理解、阅读,也能方便的转换成C语言,便于简明扼要的描述算法,突出算法的思路。
       然而,用类C语言语言来描述算法的形式使算法显得比较零散,无法体现出系统的整体性(即将各个基本运算的功能组织在一个系统中的方法),会使初学C语言的同学难以深入理解数据结构中逻辑结构与物理结构的关系。
       在完成数据结构课程设计“基于二叉链表的二叉树实现”时,我尝试以纯C语言的形式实现基于二叉链表的二叉树。

课程推荐

华中科技大学《数据结构》慕课(李国徽、袁凌、祝建华、许贵平、周时阳)

文章推荐

二叉树的基本概念

       二叉树是一种树型结构,即 n n n个结点的有限集。它的特点是每个结点至多只有两棵子树(即二叉树中不存在度大于2的结点)。此外,二叉树的子树有左右之分,其次序不能任意颠倒。

  • 根节点:一棵树最上面的节点称为根节点。
  • 父节点、子节点:如果一个节点下面连接多个节点,那么该节点称为其下面节点的父亲节点,它下面的节点称为其孩子节点。
  • 叶子节点:没有任何子节点的节点称为叶子节点。
  • 兄弟节点:具有相同父节点的节点互称为兄弟节点。

抽象数据类型二叉树的定义

A D T   B i n a r y T r e e   { ADT\space BinaryTree\space \{ ADT BinaryTree {
数 据 对 象 D : D 是 具 有 相 同 特 性 的 数 据 元 素 的 集 合 。   数据对象D:D是具有相同特性的数据元素的集合。  DD
数 据 关 系 R : 数据关系R: R
   若 D = ∅ , 则 R = ∅ , 称 B i n a r y T r e e 为 空 二 叉 树 ; \space \space 若D=\varnothing,则R=\varnothing,称BinaryTree为空二叉树;   D=R=BinaryTree
   若 D ≠ ∅ , 则 R = { H } , H 是 如 下 二 元 关 系 : \space \space 若D\ne \varnothing,则R=\{H\},H是如下二元关系:   D=R={H}H
     ( 1 ) 在 D 中 存 在 唯 一 的 称 为 根 的 数 据 元 素 r o o t , 它 在 关 系 H 中 无 前 驱 ; \space \space \space \space (1)在D中存在唯一的称为根的数据元素root,它在关系H中无前驱;     1DrootH
     ( 2 ) 若 D − { r o o t } ≠ ∅ , 则 存 在 D − { r o o t } = { D l , D r } , 且 D l ∩ D r = ∅ ;   \space \space \space \space (2)若D-\{root\}\ne\varnothing,则存在D-\{root\}=\{D_l,D_r\},且D_l \cap D_r=\varnothing;      2D{root}=D{root}={Dl,Dr}DlDr=;
     ( 3 ) 若 D l ≠ ∅ , 则 D l 中 存 在 唯 一 的 元 素 x l , < r o o t , x l > ∈ H , 且 存 在 D l 上 的 关 系 H l ⊂ H ; \space \space \space \space (3)若D_l \ne \varnothing ,则D_l中存在唯一的元素x_l,<root,x_l>∈H,且存在D_l上的关系H_l\subset H;     3Dl=Dlxl<root,xl>HDlHlH
               若 D r ≠ ∅ , 则 D r 中 存 在 唯 一 的 元 素 x r , < r o o t , x r > ∈ H , 且 存 在 D r 上 的 关 系 H r ⊂ H ; \space \space \space \space \space \space \space \space \space \space \space \space \space \space 若D_r \ne \varnothing,则D_r中存在唯一的元素x_r,<root,x_r> \in H,且存在D_r上的关系H_r \subset H;               Dr=Drxr<root,xr>HDrHrH
               H = { < r o o t , x l > , < r o o t , x r > , H l , H r } \space \space \space \space \space \space \space \space \space \space \space \space \space \space H= \{ <root,x_l>,<root,x_r>,H_l,H_r \}               H={<root,xl>,<root,xr>,Hl,Hr}
     ( 4 ) ( D l , { H l } ) 是 一 棵 符 合 本 定 义 的 二 叉 树 , 称 为 根 的 左 子 树 ; \space \space \space \space (4)(D_l,\{ H_l \})是一棵符合本定义的二叉树,称为根的左子树;     4Dl{Hl}
               ( D r , { H r } ) 也 是 一 棵 符 合 本 定 义 的 二 叉 树 , 称 为 根 的 右 子 树 。 \space \space \space \space \space \space \space \space \space \space \space \space \space \space (D_r,\{ H_r \})也是一棵符合本定义的二叉树,称为根的右子树。               Dr{Hr}
基 本 操 作 P : 基本操作P: P二叉树基本操作定义
} \} }

课程设计任务描述

实验任务

       采用二叉链表作为二叉树的物理结构,构造一个具有菜单的功能演示系统,实现二叉树的基本运算。其中,在主函数中完成函数调用所需实参值的准备和函数执行结果的显示,并给出适当的操作提示。程序还应该定义初始化二叉树、销毁二叉树、创建二叉树、清空二叉树、判定空二叉树和求二叉树深度等基本运算对应的函数。在此基础上,可以选择以文件的形式高效保存二叉树数据逻辑结构 ( D , { R } ) (D,\{ R \} ) (D,{R})的完整信息,实现对二叉树的存储和加载,即既可以将生成的二叉树存入到相应的文件中,也可以从文件中获取二叉树进行操作。同时,演示系统还可实现多个二叉树的管理。

二叉树基本操作定义

       依据最小完备性和常用性相结合的原则,以函数形式定义了二叉树的初始化二叉树、销毁二叉树、创建二叉树、清空二叉树、判定空二叉树和求二叉树深度等20种基本运算,具体运算功能定义如下:

  • 初始化二叉树InitBiTree(&T):初始条件是二叉树T不存在;操作结果是构造空二叉树。
  • 销毁二叉树DestroyBiTree(&T):初始条件是二叉树T已存在;操作结果是销毁二叉树T。
  • 创建二叉树CreateBiTree(&T,definition):初始条件是definition 给出二叉树T的定义;操作结果是按definition构造二叉树T。
  • 清空二叉树ClearBiTree (&T):初始条件是二叉树T存在; 操作结果是将二叉树T清空。
  • 判定空二叉树BiTreeEmpty(T):初始条件是二叉树T存在;操作结果是若T为空二叉树,则返回TRUE,否则,返回FALSE。
  • 求二叉树深度BiTreeDepth(T):初始条件是二叉树T存在;操作结果是返回T的深度。
  • 获得根结点Root(T):初始条件是二叉树T已存在;操作结果是返回二叉树T的根节点。
  • 获得结点Value(T,e):初始条件是二叉树T已存在,e是T中的某个结点;操作结果是返回节点e的值。
  • 结点赋值Assign(T,&e,value):初始条件是二叉树T已存在,e是T中的某个结点;操作结果是结点e赋值为value。
  • 获得双亲结点Parent(T,e):初始条件是二叉树T已存在,e是T中的某个结点。操作结果是若e是T的非根结点,则返回它的双亲结点指针;否则返回NULL。
  • 获得左孩子结点LeftChild(T,e):初始条件是二叉树T存在,e是T中某个节点。操作结果是返回e的左孩子结点;若e无左孩子,则返回NULL。
  • 获得右孩子结点RightChild(T,e):初始条件是二叉树T已存在,e是T中某个结点。操作结果是返回e的右孩子结点;若e无右孩子,则返回NULL。
  • 获得左兄弟结点LeftSibling(T,e):初始条件是二叉树T存在。e是T中某个结点;操作结果是返回e的左兄弟结点指针;若e是T的左孩子或者无左兄弟,则返回NULL。
  • 获得右兄弟结点RightSibling(T,e):初始条件是二叉树T已存在。e是T中某个结点;操作结果是返回e的右兄弟结点指针;若e是T的右孩子或者无有兄弟,则返回NULL。
  • 插入子树InsertChild(T,p,LR,c):初始条件是二叉树T存在,p指向T中的某个结点,LR为0或1,非空二叉树c与T不相交且右子树为空;操作结果是根据LR为0或者1,插入c为T中p所指结点的左或右子树,p所指结点的原有左子树或右子树则为c的右子树。
  • 删除子树DeleteChild(T,p,LR):初始条件是二叉树T存在,p指向T中的某个结点,LR为0或1;操作结果是根据LR为0或者1,删除c为T中p所指结点的左或右子树。
  • 前序遍历PreOrderTraverse(T,Visit()):初始条件是二叉树T存在,Visit是对结点操作的应用函数;操作结果是先序遍历T,对每个结点调用函数Visit一次且一次,一旦调用失败,则操作失败。
  • 中序遍历InOrderTraverse(T,Visit()):初始条件是二叉树T存在,Visit是对结点操作的应用函数;操作结果是中序遍历T,对每个结点调用函数Visit一次且一次,一旦调用失败,则操作失败。
  • 后序遍历PostOrderTraverse(T,Visit()):初始条件是二叉树T存在,Visit是对结点操作的应用函数;操作结果是后序遍历T,对每个结点调用函数Visit一次且一次,一旦调用失败,则操作失败。
  • 层序遍历LevelOrderTraverse(T,Visit()):初始条件是二叉树T存在,Visit是对结点操作的应用函数;操作结果是层序遍历T,对每个结点调用函数Visit一次且一次,一旦调用失败,则操作失败。

基于二叉链表的二叉树的实现

状态返回值类型和数据元素类型的定义

typedef int status;
typedef int ElemType;

二叉链表节点类型的定义

       系统采用二叉链表结构存储二叉树,二叉链表节点含数据域、左孩子节点指针、右孩子节点指针三部分。

typedef struct Node
{
	struct Node *LeftChild;
	ElemType data;
	struct Node *RightChild;
}Node,*BiTree;

多二叉树的头指针构成的链表节点类型的定义

typedef struct BiTreeHeadPointer
{
	BiTree head;
	struct BiTreeHeadPointer *next;
}BiTreeHeadPointer,*BiTreeList;

“二叉树不存在”与“空二叉树”的定义

       由于在二叉树基本运算操作的初始条件中对“二叉树不存在”和“空二叉树”做了区分。为了区分“二叉树不存在”和“空二叉树”,我们可能就要引入“带表头节点的二叉链表”(暂且称这个节点为“二叉链表的头节点”或“树头节点”)。
       然而,在将基本运算操作转化成C语言的函数时,大多数复杂的操作是通过循环和递归实现的。“树头节点”的出现使得递归的实现变得更加复杂。
       所以,我们不妨舍弃这种做法,做如下定义:

  • T==NULL时,该二叉树不存在。
  • T!=NULL&&T->data==0x7fffffff(无穷大)时,该二叉树是空二叉树。

宏定义

       此处用编译预处理(宏定义)的方法,定义了TRUE、FALSE、OK、ERROR、OVERFLOW等六个值,表示真、假、成功、失败、溢出等状态。此外,还定义MAX_SIZE、Set_MAXSIZE、FILENAME_LENGTH,分别用于表示链表头指针数组的最大长度、层序遍历临时数组的最大长度以及文件路径的最大长度。

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR -1
#define OVERFLOW -2
#define MAX_SIZE 20
#define Set_MAXSIZE 50
#define FILENAME_LENGTH 30

节点访问函数

status visit (ElemType e)
{
	printf(" %d ",e);
	return OK;
}

同时管理多个二叉树的实现

  • 演示系统1采用顺序存储的线性表数组)的方式管理多个二叉树,可实现多个二叉树的管理。
    在这里插入图片描述
  • 演示系统2采用链式存储的线性表单链表)的方式管理多个二叉树,可实现多个二叉树的管理。
    采用链表管理多个二叉树

算法实现例讲——层序遍历算法

使用队列实现层序遍历算法

       这种方法比较常见,但是,使用C语言来实现使用队列并不简单,所以这里就不赘述了。对该算法有兴趣的可以参考:

使用数组模拟队列实现层序遍历算法

       这里,我们需要建立起层序遍历节点指针数组,用于存储层序遍历的每个结点的地址。游走监视哨i从1开始,指向数组的下一个空位,j指向正在遍历的节点的父亲节点。将根节点放入数组的第一个位置。利用循环,若Queue[ j ]不为空,访问Queue[ j ],此后将Queue[ j ]的左孩子节点和右孩子节点的地址依次放入数组(i不断向后移动)。此后,j自增。直至i<=j。返回成功。

status LevelOrderTraverse(BiTree T,status (*visit)(ElemType e))
{
	Node *Queue[Set_MAXSIZE]={NULL};					//节点数组:存储层序遍历的每个结点指针
	Node *LeftChild=NULL,*RightChild=NULL;
	//游走监视哨:i指向数组的下一个空位,j指向正在遍历的节点的父亲节点
	int i=1,j=0;
	Queue[0]=T;											//首先遍历根节点
	while(i>j)											//循环结束条件:j>=i
	{
		if (Queue[j])									//若Queue[j]!=NULL,访问其左右孩子节点
        {
			visit(Queue[j]->data);						//访问j指向的节点
			LeftChild=Queue[j]->LeftChild;
			RightChild=Queue[j]->RightChild;
			if(LeftChild) Queue[i++]=LeftChild;			//存储j的非空左孩子结点,i++
			if(RightChild) Queue[i++]=RightChild;		//存储j的非空右孩子结点,i++
        }
        j++;											//j指向上一层的下一个节点
	}
	return OK;
}

使用类似递归的方式实现层序遍历算法

       此算法的核心是对递归、参数的传递与概念的理解。不难发现,节点在第i层的实际含义是从根节点到该节点的路径长度为i
       此算法参考了二叉树的层序遍历(递归与非递归),同时依据演示系统的其他部分对算法进行了改动,优化了LevelTraverse函数。

//按层遍历:初始条件是二叉树T存在;操作结果是层序遍历T,对每个结点调用函数visit一次。
status LevelOrderTraverse(BiTree T,status (*visit)(ElemType e))
{
	int Depth=BiTreeDepth(T),Level_Destination;			//获取二叉树的深度
	for(Level_Destination=1;Level_Destination<=Depth;Level_Destination++)
		LevelTraverse(T,1,Level_Destination,visit);		//依次输出每一层
	return OK;
}

//遍历输出二叉树的某一层:初始条件是二叉树T存在;操作结果是遍历输出二叉树的第i层。
status LevelTraverse(BiTree T,int Level_Now,int Level_Destination,status (*visit)(ElemType e))
{
	if(T==NULL) return ERROR;							//ERROR:该节点为空节点,返回
	//若该节点在目标层,输出该节点
	if(Level_Now==Level_Destination) visit(T->data);
	else
	{
		//若该节点不在目标层,依次检查其左、右孩子节点是否在目标层(保证层序从左到右)
		LevelTraverse(T->LeftChild,Level_Now+1,Level_Destination,visit);
		LevelTraverse(T->RightChild,Level_Now+1,Level_Destination,visit);
	}
	return OK;
}

演示系统菜单功能示意图

集成开发环境(IDE)

       以下代码在Microsoft Visual C++ 2010 Express下预编译,编译,汇编,链接通过(有警告warning)。

系统的代码实现

演示系统1(采用顺序存储的线性表管理多个二叉树)

//Binary Tree on Linked Storage Structure
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>

//编译预处理
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR -1
#define OVERFLOW -2
#define MAX_SIZE 20
#define Set_MAXSIZE 50
#define FILENAME_LENGTH 30

//定义状态返回值类型和数据元素类型
typedef int status;
typedef int ElemType;

//定义二叉链表节点类型
typedef struct Node
{
	struct Node *LeftChild;
	ElemType data;
	struct Node *RightChild;
}Node,*BiTree;

//函数声明
status InitBiTree(BiTree *T,BiTree BiTreeSet[]);
status DestroyBiTree(BiTree *T,BiTree BiTreeSet[]);
status CreateBiTree(BiTree *T);
status ClearBiTree(BiTree *T,BiTree BiTreeSet[]);
status BiTreeEmpty(BiTree T);
int BiTreeDepth(BiTree T);
Node *Root(BiTree T);
ElemType Value(BiTree T,Node *e);
status Assign(BiTree T,Node *e,ElemType value);
Node *Parent(BiTree T,Node *e);
Node *LeftChild(BiTree T,Node *e);
Node *RightChild(BiTree T,Node *e);
Node *LeftSibling(BiTree T,Node *e);
Node *RightSibling(BiTree T,Node *e);
status InsertChild(BiTree T,Node *p,int LR,BiTree c);
status DeleteChild(BiTree T,Node *p,int LR,BiTree BiTreeSet[]);
status PreOrderTraverse(BiTree T,status (*visit)(ElemType e));
status InOrderTraverse(BiTree T,status (*visit)(ElemType e));
status PostOrderTraverse(BiTree T,status (*visit)(ElemType e));
status LevelOrderTraverse(BiTree T,status (*visit)(ElemType e));
//status LevelTraverse(BiTree T,int Level_Now,int Level_Destination,status (*visit)(ElemType e))
status GetNode(BiTree T,int num,Node **node);
status SaveBiTree(BiTree T);
status WriteNodeToFile(BiTree T,FILE *fp);
status LoadBiTree(BiTree *T,BiTree BiTreeSet[]);
status ReadNodeFromFile(BiTree *T,FILE *fp);
status CreatAnotherBiTree(BiTree *T,BiTree BiTreeSet[]);
status ChooseBiTree(BiTree *T,BiTree BiTreeSet[]);

status visit (ElemType e)
{
	printf(" %d ",e);
	return OK;
}

int main(void)
{
	int op=1,state;		//op=1:程序入口,state:接受返回值,表示函数返回状态
	int i,e,LR;			//LR:左子树(LR=0),右子树(LR=1)
	BiTree T=NULL;		//T:二叉树名、头指针
	BiTree BiTreeSet[MAX_SIZE]={NULL};				//BiTreeSet:存储二叉树的头指针
	Node *Temp=NULL,*NewTree=NULL;
	while(op)
	{
		system("cls");
		printf("\n\n");
		printf("      Menu for Binary Tree on Linked Storage Structure      \n");
		printf("------------------------------------------------------------\n");
		printf("        0. Exit \n");
		printf("        1. InitBiTree          2. DestroyBiTree \n");
		printf("        3. CreateBiTree        4. ClearBiTree \n");
		printf("        5. BiTreeEmpty         6. BiTreeDepth \n");
		printf("    	7. BiTreeRoot          8. GetNodeValue \n");
		printf("    	9. AssignNode         10. GetNodeParent \n");
		printf("       11. GetLeftChild       12. GetRightChild \n");
		printf("       13. GetLeftSibling     14. GetRightSibling \n");
		printf("       15. InsertChild        16. DeleteChild \n");
		printf("       17. PreOrderTraverse   18. InOrderTraverse \n");
		printf("       19. PostOrderTraverse  20. LevelOrderTraverse \n");
		printf("       21. SaveBiTree         22. LoadBiTree \n");
		printf("       23. CreatAnothBiTree   24. ChooseBiTree \n");
		printf("------------------------------------------------------------\n");
		printf("    请选择你的操作[0~24]:");

		//若输入数字之外的字符,清空标准输入流里的数据,并将op置为default
		if(scanf("%d",&op)!=1) {fflush(stdin);op=25;}

		switch(op)
		{
		   	case 1:
			   	state=InitBiTree(&T,BiTreeSet);
			   	if(state==OK) printf("二叉树初始化成功!\n");
			   	else printf("二叉树已存在!\n");
			   	system("pause");
			   	break;

		   	case 2:
			   	if(T==NULL) printf("二叉树不存在,无需销毁!\n");
			   	else
			   	{
				   	if(DestroyBiTree(&T,BiTreeSet)==OK) printf("二叉树销毁成功!\n");
				   	else printf("二叉树销毁失败!\n");
			   	}
			   	system("pause");
			   	break;

		   	case 3:
			    if(T==NULL) printf("二叉树不存在!\n");
			    else if(T->data!=0x7fffffff) printf("非空二叉树已存在!若要对其进行创建操作,请先清空该树!\n");
			    else
			    {
				    printf("请输入先序遍历结果的二叉树,叶子节点的左右孩子节点为0:");
				    if(CreateBiTree(&T)==OK) printf("创建成功!\n");
				    else printf("创建失败!\n");
			    }
			    system("pause");
			    break;

		   	case 4:
				state=ClearBiTree(&T,BiTreeSet);
				if(state==OK) printf("二叉树清空成功!\n");
				else printf("二叉树清空失败!\n");
				system("pause");
				break;
		   

           	case 5:
               	state=BiTreeEmpty(T);
               	if(state==TRUE) printf("该树是空树!\n");
               	else if(state==FALSE) printf("该树不是空树!\n");
               	system("pause");
               	break;

		   	case 6:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else printf("该二叉树的深度为%d!\n",BiTreeDepth(T));
			   	system("pause");
               	break;

		   	case 7:
			   if(T==NULL) printf("二叉树不存在!\n");
			   else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   else printf("该二叉树根节点的数据元素为%d!\n",Root(T)->data);
			   system("pause");
               break;

		   case 8:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
			   		printf("输入i,获取二叉树层序遍历下第i个数据元素的值:");
			   		scanf("%d",&i);
			  		if(GetNode(T,i,&Temp)==ERROR) printf("输入错误,不存在第%d个数据元素!\n",i);
			   		else
			   		{
				   		state=Value(T,Temp);
				   		if(state==ERROR) printf("操作失败!\n");
				   		else printf("二叉树层序遍历下第%d个数据元素的值为%d!\n",i,Value(T,Temp));
			   		}
			   	}
			   	system("pause");
               	break;

		   case 9:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
			   		printf("输入i,e,将二叉树层序遍历下第i个数据元素赋值为 e :");
			   		scanf("%d%d",&i,&e);
			  		if(GetNode(T,i,&Temp)==ERROR) printf("输入错误,不存在第%d个数据元素!\n",i);
			   		else
			   		{
				   		state=Assign(T,Temp,e);
				   		if(state==ERROR) printf("操作失败!\n");
				   		else printf("赋值成功!\n");
			   		}
				}
			   system("pause");
               break;

		   	case 10:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
			   		printf("输入i,获取二叉树层序遍历下第i个数据元素的父亲节点的值 :");
			   		scanf("%d",&i);
			  		if(GetNode(T,i,&Temp)==ERROR) printf("输入错误,不存在第%d个数据元素!\n",i);
			   		else
			   		{
				   		Temp=Parent(T,Temp);
				   		if(Temp==NULL) printf("操作失败!该节点没有父亲节点!\n");
				   		else printf("二叉树层序遍历下第%d个数据元素的父亲节点的值为%d!\n",i,Value(T,Temp));
			   		}
			   	}
			   	system("pause");
               	break;

		   	case 11:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
			   		printf("输入i,获取二叉树层序遍历下第i个数据元素的左孩子节点的值 :");
			   		scanf("%d",&i);
			  		if(GetNode(T,i,&Temp)==ERROR) printf("输入错误,不存在第%d个数据元素!\n",i);
			   		else
			   		{
				   		Temp=LeftChild(T,Temp);
				   		if(Temp==NULL) printf("操作失败!该节点没有左孩子节点!\n");
				   		else printf("二叉树层序遍历下第%d个数据元素的左孩子节点的值为%d!\n",i,Value(T,Temp));
			   		}
			   	}
			   	system("pause");
               	break;

		   	case 12:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
			   		printf("输入i,获取二叉树层序遍历下第i个数据元素的右孩子节点的值 :");
			   		scanf("%d",&i);
			  		if(GetNode(T,i,&Temp)==ERROR) printf("输入错误,不存在第%d个数据元素!\n",i);
			   		else
			   		{
				   		Temp=RightChild(T,Temp);
				   		if(Temp==NULL) printf("操作失败!该节点没有右孩子节点!\n");
				   		else printf("二叉树层序遍历下第%d个数据元素的右孩子节点的值为%d!\n",i,Value(T,Temp));
			   		}
			   	}
			   	system("pause");
               	break;

		    case 13:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
			   		printf("输入i,获取二叉树层序遍历下第i个数据元素的左兄弟节点的值 :");
			   		scanf("%d",&i);
			  		if(GetNode(T,i,&Temp)==ERROR) printf("输入错误,不存在第%d个数据元素!\n",i);
			   		else
			   		{
				   		Temp=LeftSibling(T,Temp);
				   		if(Temp==NULL) printf("操作失败!该节点没有左兄弟节点!\n");
				   		else printf("二叉树层序遍历下第%d个数据元素的左兄弟节点的值为%d!\n",i,Value(T,Temp));
			   		}
			   	}
			   	system("pause");
               	break;

		   	case 14:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
			   		printf("输入i,获取二叉树层序遍历下第i个数据元素的右兄弟节点的值 :");
			   		scanf("%d",&i);
			  		if(GetNode(T,i,&Temp)==ERROR) printf("输入错误,不存在第%d个数据元素!\n",i);
			   		else
			   		{
				   		Temp=RightSibling(T,Temp);
				   		if(Temp==NULL) printf("操作失败!该节点没有右兄弟节点!\n");
				   		else printf("二叉树层序遍历下第%d个数据元素的右兄弟节点的值为%d!\n",i,Value(T,Temp));
			   		}
			   	}
			   	system("pause");
               	break;

		   	case 15:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
			   		printf("输入i,以二叉树层序遍历下第i个节点为根节点,插入新树 :");
			   		scanf("%d",&i);
			   		printf("请选择:\n0.插入到该节点的左子树。\n1.插入到该节点的右子树。\n");
			   		scanf("%d",&LR);
			  		if(GetNode(T,i,&Temp)==ERROR) printf("输入错误,不存在第%d个数据元素!\n",i);
			  		else if(LR!=0&&LR!=1) printf("输入错误!请输入0或1以选择插入到该节点的左子树或右子树。\n");
			   		else
			   		{
						//初始化NewTree,将NewTree置为空树
						NewTree=(BiTree)malloc(sizeof(Node));
						NewTree->data=0x7fffffff;
						NewTree->LeftChild=NewTree->RightChild=NULL;
				   		printf("请输入先序遍历结果的二叉树,叶子节点的左右孩子节点为0,同时保证该二叉树右子树为空:\n");
				   		CreateBiTree(&NewTree);
				   		state=InsertChild(T,Temp,LR,NewTree);
				   		if(state==ERROR) printf("操作失败!\n");
				   		else printf("操作成功!\n");
			   		}
			   	}
			   	system("pause");
               	break;

		  	case 16:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
			   		printf("输入i,删除以二叉树层序遍历下第i个数据元素为根节点的子树:");
			   		scanf("%d",&i);
			   		printf("请选择:\n0.删除以该节点为根节点的左子树。\n1.删除以该节点为根节点的右子树。\n");
			   		scanf("%d",&LR);
			  		if(GetNode(T,i,&Temp)==ERROR) printf("输入错误,不存在第%d个数据元素!\n",i);
			   		else
			   		{
				   		state=DeleteChild(T,Temp,LR,BiTreeSet);
				   		if(state==ERROR) printf("操作失败!\n");
				   		else printf("删除成功!\n");
			   		}
			   	}
			   	system("pause");
               	break;

		   	case 17:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
				   	if(PreOrderTraverse(T,visit)==OK) printf("\n前序遍历成功!\n");
				   	else printf("\n前序遍历失败!\n");
			   	}
			   	system("pause");
			   	break;


		   	case 18:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
				   	if(InOrderTraverse(T,visit)==OK) printf("\n中序遍历成功!\n");
				   	else printf("\n中序遍历失败!\n");
			   	}
			   	system("pause");
			   	break;

		   	case 19:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
				   	if(PostOrderTraverse(T,visit)==OK) printf("\n后序遍历成功!\n");
				   	else printf("\n后序遍历失败!\n");
			   	}
			   	system("pause");
			   	break;

		   	case 20:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
				   	if(LevelOrderTraverse(T,visit)==OK) printf("\n层序遍历成功!\n");
				   	else printf("\n层序遍历失败!\n");
			   	}
			   	system("pause");
			   	break;  

		   	case 21:
			   	if(SaveBiTree(T)==OK) printf("二叉树保存成功!\n");
			   	else printf("二叉树保存失败!\n");
			   	system("pause");
			   	break;

		   	case 22:
			   	if(LoadBiTree(&T,BiTreeSet)==OK) printf("二叉树加载成功!\n");
			   	else printf("二叉树加载失败!\n");
			   	system("pause");
			   	break;

		   	case 23:
			   	if(CreatAnotherBiTree(&T,BiTreeSet)==OK) printf("创建新的二叉树成功!\n");
			   	else printf("操作失败!\n");
			   	system("pause");
			  	break;

		   	case 24:
			   	if(ChooseBiTree(&T,BiTreeSet)==OK) printf("成功选中该二叉树!\n");
			   	else printf("操作失败!\n");
			   	system("pause");
			   	break;

		   	case 0:
			   	break;

		   	default:
			   	printf("输入无效!菜单功能选择失败!\n");
			   	system("pause");
			   	break;
			   	
		}//end of switch

	}//end of while

	printf("欢迎下次再使用本系统!\n");
	return 0;
}//end of main()

//初始化二叉树:初始条件是二叉树T不存在;操作结果是构造空二叉树T。
//二叉树不存在:T==NULL
//空二叉树:T!=NULL&&T->data==0x7fffffff
status InitBiTree(BiTree *T,BiTree BiTreeSet[])
{
	int i;
	if((*T)==NULL)										//初始条件:二叉树T不存在
	{
		(*T)=(BiTree)malloc(sizeof(Node));				//为根节点分配空间
		(*T)->data=0x7fffffff;							//数据域置为0x7fffffff,将该树置为空二叉树
		(*T)->LeftChild=(*T)->RightChild=NULL;			//左右孩子节点指针置为NULL
		for(i=0;i<MAX_SIZE;i++) if(BiTreeSet[i]==NULL) break;		//找到二叉树头指针数组第一个为NULL的位置
		if(i==MAX_SIZE) exit(OVERFLOW);					//ERROR:OVERFLOW
		BiTreeSet[i]=(*T);								//将该二叉树添加至链表头指针数组
		return OK;
	}
	else return ERROR;									//ERROR:二叉树已经存在
}

//销毁二叉树:初始条件是二叉树T已存在;操作结果是销毁二叉树T。
status DestroyBiTree(BiTree *T,BiTree BiTreeSet[])
{
	int i;
	if((*T)==NULL) return OK;							//返回OK:空节点
	DestroyBiTree(&(*T)->LeftChild,BiTreeSet);			//销毁左子树
	DestroyBiTree(&(*T)->RightChild,BiTreeSet);			//销毁右子树
	for(i=0;i<MAX_SIZE;i++) if(BiTreeSet[i]==*T) break;	//在二叉树头指针数组中查找该头指针
	if(i<MAX_SIZE)										//若该二叉树存在于头指针数组中时,将其删除
	{
		//在二叉树头指针数组中删除该头指针,后续元素前移
		//特殊情况:
		//1.数组存储了MAX_SIZE个二叉树;
		//2.T为第MAX_SIZE个二叉树
		while(i<MAX_SIZE-1&&BiTreeSet[i]!=NULL)
		{
			BiTreeSet[i]=BiTreeSet[i+1];
			i++;
		}
		BiTreeSet[MAX_SIZE-1]=NULL;						//处理BiTreeSet[MAX_SIZE-1]
	}
	free(*T);											//释放根节点
	(*T)=NULL;											//头指针置空
	return OK;
}

//创建二叉树:初始条件是definition 给出二叉树T的定义;操作结果是按definition构造二叉树T。
status CreateBiTree(BiTree *T)
{
	ElemType Data;
	if(scanf("%d",&Data)!=EOF&&Data!=0)					//输入二叉树节点的值(非0)
	{
		if((*T)==NULL)									//若节点为NULL,创建节点
		{
			(*T)=(BiTree)malloc(sizeof(Node));			//分配空间
			(*T)->LeftChild=(*T)->RightChild=NULL;		//左右孩子节点指针置为NULL
			if((*T)==NULL) exit(OVERFLOW);				//ERROR:OVERFLOW
		}
		(*T)->data=Data;								//节点数据域赋值
		CreateBiTree(&(*T)->LeftChild);					//递归:创建该节点的左子树
		CreateBiTree(&(*T)->RightChild);				//递归:创建该节点的右子树
		return OK;
	}
	else return ERROR;									//ERROR:根节点为0
}

//清空二叉树:初始条件是二叉树T存在;操作结果是将二叉树T清空。
status ClearBiTree(BiTree *T,BiTree BiTreeSet[])
{
	if((*T)==NULL) {printf("二叉树不存在,无需清空!\n");return ERROR;}
	else if((*T)->data==0x7fffffff) {printf("该二叉树为空二叉树!\n");return ERROR;}
	if(DestroyBiTree(T,BiTreeSet)==OK&&InitBiTree(T,BiTreeSet)==OK) return OK;		//清空=销毁+初始化
	else return ERROR;
}

//判定空二叉树:初始条件是二叉树T存在;操作结果是若T为空二叉树则返回TRUE,否则返回FALSE。
status BiTreeEmpty(BiTree T)
{
	if(T==NULL) {printf("二叉树不存在!\n");return ERROR;}
	else if(T->data==0x7fffffff)	return TRUE;		//TRUE:空二叉树
	else return FALSE;									//FALSE:非空二叉树
}


//求二叉树深度:初始条件是二叉树T存在;操作结果是返回T的深度。
int BiTreeDepth(BiTree T)
{
	int Depth=0,Depth_L,Depth_R;						//Depth_L:左子树深度;Depth_R:右子树深度
	if(T==NULL) return 0;								//return 0:二叉树不存在
	else
	{
		Depth_L=BiTreeDepth(T->LeftChild);				//递归:获取左子树深度
		Depth_R=BiTreeDepth(T->RightChild);				//递归:获取右子树深度
		//以该节点为根节点的树的深度是左、右子树深度的最大值加一
		Depth+=1+( Depth_L>Depth_R ? Depth_L:Depth_R);
		return Depth;									//返回深度
	}
}

//获得根结点:初始条件是二叉树T已存在;操作结果是返回T的根。
Node *Root(BiTree T)
{
	return T;
}

//获得结点:初始条件是二叉树T已存在,e是T中的某个结点;操作结果是返回e的值。
ElemType Value(BiTree T,Node *e)
{
	return e->data;										//返回该节点数据域的值
}

//结点赋值:初始条件是二叉树T已存在,e是T中的某个结点;操作结果是结点e赋值为value。
status Assign(BiTree T,Node *e,ElemType value)
{
	e->data=value;										//节点数据域赋值
	return OK;
}

//获得双亲结点:初始条件是二叉树T已存在,e是T中的某个结点。
//操作结果是若e是T的非根结点,则返回它的双亲结点指针,否则返回NULL。
Node *Parent(BiTree T,Node *e)
{
	Node *Queue[Set_MAXSIZE]={NULL};					//节点数组:存储层序遍历的每个结点指针
	Node *LeftChild=NULL,*RightChild=NULL;
	//游走监视哨:i指向数组的下一个空位,j指向正在遍历的节点的父亲节点
	int i=1,j=0;
	Queue[0]=T;											//首先遍历根节点
	while(i>j)											//循环结束条件:j>=i
	{
		if (Queue[j])									//若Queue[j]!=NULL,访问其左右孩子节点
        {
			LeftChild=Queue[j]->LeftChild;
			RightChild=Queue[j]->RightChild;
			if(LeftChild) Queue[i++]=LeftChild;			//存储j的非空左孩子结点,i++
			if(RightChild) Queue[i++]=RightChild;		//存储j的非空右孩子结点,i++
        }
        j++;											//j指向上一层的下一个节点
	}
	//遍历该数组,寻找左孩子或者右孩子为e的节点
	for(i=0;Queue[i]!=NULL;i++)	
		if(Queue[i]->LeftChild==e||Queue[i]->RightChild==e) break;
	return Queue[i];									//返回该节点
}

//获得左孩子结点:初始条件是二叉树T存在,e是T中某个节点。
//操作结果是返回e的左孩子结点指针。若e无左孩子,则返回NULL。
Node *LeftChild(BiTree T,Node *e)
{
	return e->LeftChild;								//返回其左孩子节点
}

//获得右孩子结点:初始条件是二叉树T已存在,e是T中某个结点。
//操作结果是返回e的右孩子结点指针。若e无右孩子,则返回NULL。
Node *RightChild(BiTree T,Node *e)
{
	return e->RightChild;								//返回其右孩子节点
}

//获得左兄弟结点:初始条件是二叉树T存在,e是T中某个结点。
//操作结果是返回e的左兄弟结点指针。若e是T的左孩子或者无左兄弟,则返回NULL。
Node *LeftSibling(BiTree T,Node *e)
{
	Node *parents=Parent(T,e);							//parents:获取该节点的父亲节点
	if(parents==NULL) return NULL;						//ERROR:该节点没有父亲节点
	//若该节点是其父亲节点的右孩子节点,返回该节点的左兄弟
	if(parents->RightChild==e) return parents->LeftChild;
	else return NULL;									//ERROR:该节点是其父亲节点的左孩子节点
}

//获得右兄弟结点:初始条件是二叉树T已存在,e是T中某个结点。
//操作结果是返回e的右兄弟结点指针。若e是T的右孩子或者无右兄弟,则返回NULL。
Node *RightSibling(BiTree T,Node *e)
{
	Node *parents=Parent(T,e);							//parents:获取该节点的父亲节点
	if(parents==NULL) return NULL;						//ERROR:该节点没有父亲节点
	//若该节点是其父亲节点的左孩子节点,返回该节点的右兄弟
	if(parents->LeftChild==e) return parents->RightChild;
	else return NULL;									//ERROR:该节点是其父亲节点的右孩子节点
}

//插入子树:初始条件是二叉树T存在,p指向T中的某个结点,LR为0或1。
//非空二叉树c与T不相交且右子树为空。
//操作结果是根据LR为0或者1,插入c为T中p所指结点的左或右子树,p所指结点的原有左子树或右子树则为c的右子树。
status InsertChild(BiTree T,Node *p,int LR,BiTree c)
{
	if(c->RightChild!=NULL) return ERROR;				//ERROR:c的右子树不为空
	if(LR==0)											//插入到左子树
	{
		c->RightChild=p->LeftChild;						//将p的左子树移动到c的右子树
		p->LeftChild=c;									//将c插入到p的左子树
	}
	else if(LR==1) 										//插入到右子树
	{
		c->RightChild=p->RightChild;					//将p的右子树移动到c的右子树
		p->RightChild=c;								//将c插入到p的右子树
	}
	return OK;
}

//删除子树:初始条件是二叉树T存在,p指向T中的某个结点,LR为0或1。
//操作结果是根据LR为0或者1,删除c为T中p所指结点的左或右子树。
status DeleteChild(BiTree T,Node *p,int LR,BiTree BiTreeSet[])
{
	if(LR==0) {DestroyBiTree(&(p->LeftChild),BiTreeSet);return OK;}			//销毁左子树
	else if(LR==1) {DestroyBiTree(&(p->RightChild),BiTreeSet);return OK;}	//销毁右子树
	else return ERROR;									//ERROR:LR!=0&&LR!=1(输入错误)
}

//前序遍历:初始条件是二叉树T存在;操作结果:先序遍历T,对每个结点调用函数visit一次。
status PreOrderTraverse(BiTree T,status (*visit)(ElemType e))
{
	if(T==NULL) return OK;								//return OK:空树
	visit(T->data);										//访问该根节点
	PreOrderTraverse(T->LeftChild,visit);				//递归:遍历左子树
	PreOrderTraverse(T->RightChild,visit);				//递归:遍历右子树
	return OK;
}

//中序遍历:初始条件是二叉树T存在;操作结果是中序遍历T,对每个结点调用函数visit一次。
status InOrderTraverse(BiTree T,status (*visit)(ElemType e))
{
	if(T==NULL) return OK;								//return OK:空树
	InOrderTraverse(T->LeftChild,visit);				//递归:遍历左子树
	visit(T->data);										//访问该根节点
	InOrderTraverse(T->RightChild,visit);				//递归:遍历右子树
	return OK;
}

//后序遍历:初始条件是二叉树T存在;操作结果是后序遍历T,对每个结点调用函数visit一次。
status PostOrderTraverse(BiTree T,status (*visit)(ElemType e))
{
	if(T==NULL) return OK;								//return OK:空树
	PostOrderTraverse(T->LeftChild,visit);				//递归:遍历左子树
	PostOrderTraverse(T->RightChild,visit);				//递归:遍历右子树
	visit(T->data);										//访问该根节点
	return OK;
}

//按层遍历:初始条件是二叉树T存在;操作结果是层序遍历T,对每个结点调用函数visit一次。
status LevelOrderTraverse(BiTree T,status (*visit)(ElemType e))
{
	Node *Queue[Set_MAXSIZE]={NULL};					//节点数组:存储层序遍历的每个结点指针
	Node *LeftChild=NULL,*RightChild=NULL;
	//游走监视哨:i指向数组的下一个空位,j指向正在遍历的节点的父亲节点
	int i=1,j=0;
	Queue[0]=T;											//首先遍历根节点
	while(i>j)											//循环结束条件:j>=i
	{
		if (Queue[j])									//若Queue[j]!=NULL,访问其左右孩子节点
        {
			visit(Queue[j]->data);						//访问j指向的节点
			LeftChild=Queue[j]->LeftChild;
			RightChild=Queue[j]->RightChild;
			if(LeftChild) Queue[i++]=LeftChild;			//存储j的非空左孩子结点,i++
			if(RightChild) Queue[i++]=RightChild;		//存储j的非空右孩子结点,i++
        }
        j++;											//j指向上一层的下一个节点
	}
	return OK;
}

/*
//按层遍历:初始条件是二叉树T存在;操作结果是层序遍历T,对每个结点调用函数visit一次。
status LevelOrderTraverse(BiTree T,status (*visit)(ElemType e))
{
	int Depth=BiTreeDepth(T),Level_Destination;			//获取二叉树的深度
	for(Level_Destination=1;Level_Destination<=Depth;Level_Destination++)
		LevelTraverse(T,1,Level_Destination,visit);		//依次输出每一层
	return OK;
}

//遍历输出二叉树的某一层:初始条件是二叉树T存在;操作结果是遍历输出二叉树的第i层。
//节点在第i层的另一层含义:从根节点到该节点的路径长度为i
status LevelTraverse(BiTree T,int Level_Now,int Level_Destination,status (*visit)(ElemType e))
{
	if(T==NULL) return ERROR;							//ERROR:该节点为空节点,返回
	//若该节点在目标层,输出该节点
	if(Level_Now==Level_Destination) visit(T->data);
	else
	{
		//若该节点不在目标层,依次检查其左、右孩子节点是否在目标层(保证层序从左到右)
		LevelTraverse(T->LeftChild,Level_Now+1,Level_Destination,visit);
		LevelTraverse(T->RightChild,Level_Now+1,Level_Destination,visit);
	}
	return OK;
}
*/

//获取节点:初始条件是二叉树T存在;操作结果是获取第num个节点
status GetNode(BiTree T,int num,Node **node)
{
	Node *Queue[Set_MAXSIZE]={NULL};					//节点数组:存储层序遍历的每个结点指针
	Node *LeftChild=NULL,*RightChild=NULL;
	//游走监视哨:i指向数组的下一个空位,j指向正在遍历的节点的父亲节点
	int i=1,j=0;
	Queue[0]=T;											//首先遍历根节点
	while(i>j)											//循环结束条件:j>=i
	{
		if (Queue[j])									//若Queue[j]!=NULL,访问其左右孩子节点
        {
			LeftChild=Queue[j]->LeftChild;
			RightChild=Queue[j]->RightChild;
			if(LeftChild) Queue[i++]=LeftChild;			//存储j的非空左孩子结点,i++
			if(RightChild) Queue[i++]=RightChild;		//存储j的非空右孩子结点,i++
        }
        j++;											//j指向上一层的下一个节点
	}
	if(num<1||num>i) return ERROR;						//ERROR:没有第num个节点
	else {(*node)=Queue[num-1];return OK;}				//将节点赋值给node,实现获取
}

//保存二叉树:初始条件是二叉树T存在且该二叉树不为空树;操作结果是将该二叉树保存到用户指定的文件中
status SaveBiTree(BiTree T)
{
	char filename[FILENAME_LENGTH]={0};
	FILE *fp=NULL;
	if(T==NULL) {printf("二叉树不存在!\n");return ERROR;}
	else if(T->data==0x7fffffff) {printf("该二叉树为空二叉树!\n");return ERROR;}
	printf("输入文件路径(长度应在%d字符以内),将二叉树保存到该文件中:",FILENAME_LENGTH);
	scanf("%s",filename);								//输入文件路径
	fp=fopen(filename,"w");								//打开文件
	if(fp==NULL) return ERROR;							//ERROR:打开文件错误
	if(WriteNodeToFile(T,fp)==ERROR) return ERROR;		//ERROR:写入节点错误
	fclose(fp);											//关闭文件
	return OK;
}

//将节点写入文件:初始条件是文件已打开;操作结果是将该节点保存到用户指定的文件中
status WriteNodeToFile(BiTree T,FILE *fp)
{
	if(fp==NULL) return ERROR;							//ERROR:未打开文件
	if(T==NULL) {fprintf(fp,"0 ");return OK;}			//空节点:将0写入文件
	else												//非空节点
	{
		fprintf(fp,"%d ",T->data);						//将该节点写入文件
		WriteNodeToFile(T->LeftChild,fp);				//递归:将该节点的左孩子结点写入文件
		WriteNodeToFile(T->RightChild,fp);				//递归:将该节点的右孩子结点写入文件
		return OK;
	}
}

//加载二叉树:初始条件是二叉树T存在;操作结果是将用户指定的文件中的二叉树加载出来
status LoadBiTree(BiTree *T,BiTree BiTreeSet[])
{
	char filename[FILENAME_LENGTH]={0};
	FILE *fp=NULL;
	if((*T)==NULL) {printf("二叉树不存在!\n");return ERROR;}
	if((*T)->data!=0x7fffffff) {*T=NULL;InitBiTree(T,BiTreeSet);}	//若该二叉树不是空二叉树,初始化该二叉树
	printf("输入文件路径(长度应在%d字符以内),加载文件中的二叉树:",FILENAME_LENGTH);
	scanf("%s",filename);								//输入文件路径
	fp=fopen(filename,"r");								//打开文件
	if(fp==NULL) return ERROR;							//ERROR:打开文件错误
	if(ReadNodeFromFile(T,fp)==ERROR) return ERROR;	//ERROR:读取节点错误
	fclose(fp);											//关闭文件
	return OK;
}

//加载文件中的节点:初始条件是文件已打开;操作结果是将用户指定的文件中的节点加载到二叉树T中
status ReadNodeFromFile(BiTree *T,FILE *fp)
{
	ElemType Data;
	if(fscanf(fp,"%d ",&Data)!=EOF&&Data!=0)			//读取文件中二叉树节点的值(非0)
	{
		if((*T)==NULL)									//若节点为NULL,创建节点
		{
			(*T)=(BiTree)malloc(sizeof(Node));			//分配空间
			(*T)->LeftChild=(*T)->RightChild=NULL;		//左右孩子节点指针置为NULL
			if((*T)==NULL) exit(OVERFLOW);				//ERROR:OVERFLOW
		}
		(*T)->data=Data;								//节点数据域赋值
		ReadNodeFromFile(&(*T)->LeftChild,fp);			//递归:读取该节点的左孩子结点
		ReadNodeFromFile(&(*T)->RightChild,fp);			//递归:读取该节点的右孩子结点
		return OK;
	}
	else return ERROR;									//ERROR:ctrl+z或Data==0
}

//创建另一颗二叉树:初始条件是已经存在一颗二叉树
status CreatAnotherBiTree(BiTree *T,BiTree BiTreeSet[])
{
	BiTree *Temp=T;										//保存该二叉树头指针
	if((*T)==NULL) {printf("没有已存在的二叉树,无需再次创建二叉树!\n");return ERROR;}
	(*T)=NULL;											//二叉树头指针置空
	InitBiTree(T,BiTreeSet);							//初始化该二叉树
	printf("请输入先序遍历结果的二叉树,叶子节点的左右孩子节点为0:");
	if(CreateBiTree(T)==OK) return OK;					//创建二叉树
	else												//创建失败
	{
		DestroyBiTree(T,BiTreeSet);						//销毁该二叉树
		T=Temp;											//将保存好的头指针赋值给T
		return ERROR;
	}
}

//选择二叉树:初始条件是已经存在至少一棵二叉树
status ChooseBiTree(BiTree *T,BiTree BiTreeSet[])
{
	int i=0,n;
	BiTree p=NULL;
	if(BiTreeSet[0]==NULL) {printf("没有可选择的二叉树!\n");return ERROR;}
	while(BiTreeSet[i]!=NULL)							//遍历二叉树头指针数组
	{
		p=BiTreeSet[i];
		printf("第%d个二叉树:",i+1);
		if(p->data!=0x7fffffff)							//若该二叉树不是空树
			PreOrderTraverse(p,visit);					//遍历该二叉树
		printf("\n");
		i++;
	}
	printf("输入n,选择第n个二叉树进行操作:");
	scanf("%d",&n);
	if(n>i||n<1) {printf("不存在第%d个二叉树!\n",n);return ERROR;}
	(*T)=BiTreeSet[n-1];								//实现选择二叉树
	if((*T)==NULL) return ERROR;
	else return OK;
}

演示系统2(采用链式存储的线性表管理多个二叉树)

//Binary Tree on Linked Storage Structure
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>

//编译预处理
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR -1
#define OVERFLOW -2
#define Set_MAXSIZE 50
#define FILENAME_LENGTH 30

//定义状态返回值类型和数据元素类型
typedef int status;
typedef int ElemType;

//定义二叉链表节点类型
typedef struct Node
{
	struct Node *LeftChild;
	ElemType data;
	struct Node *RightChild;
}Node,*BiTree;

//定义多二叉树的头指针构成的链表节点类型
typedef struct BiTreeHeadPointer
{
	BiTree head;
	struct BiTreeHeadPointer *next;
}BiTreeHeadPointer,*BiTreeList;

//函数声明
status InitBiTree(BiTree *T,BiTreeList BiTree_L);
status DestroyBiTree(BiTree *T,BiTreeList BiTree_L);
status CreateBiTree(BiTree *T);
status ClearBiTree(BiTree *T,BiTreeList BiTree_L);
status BiTreeEmpty(BiTree T);
int BiTreeDepth(BiTree T);
Node *Root(BiTree T);
ElemType Value(BiTree T,Node *e);
status Assign(BiTree T,Node *e,ElemType value);
Node *Parent(BiTree T,Node *e);
Node *LeftChild(BiTree T,Node *e);
Node *RightChild(BiTree T,Node *e);
Node *LeftSibling(BiTree T,Node *e);
Node *RightSibling(BiTree T,Node *e);
status InsertChild(BiTree T,Node *p,int LR,BiTree c);
status DeleteChild(BiTree T,Node *p,int LR,BiTreeList BiTree_L);
status PreOrderTraverse(BiTree T,status (*visit)(ElemType e));
status InOrderTraverse(BiTree T,status (*visit)(ElemType e));
status PostOrderTraverse(BiTree T,status (*visit)(ElemType e));
status LevelOrderTraverse(BiTree T,status (*visit)(ElemType e));
//status LevelTraverse(BiTree T,int Level_Now,int Level_Destination,status (*visit)(ElemType e))
status GetNode(BiTree T,int num,Node **node);
status SaveBiTree(BiTree T);
status WriteNodeToFile(BiTree T,FILE *fp);
status LoadBiTree(BiTree *T,BiTreeList BiTree_L);
status ReadNodeFromFile(BiTree *T,FILE *fp);
status CreatAnotherBiTree(BiTree *T,BiTreeList BiTree_L);
status ChooseBiTree(BiTree *T,BiTreeList BiTree_L);

status visit (ElemType e)
{
	printf(" %d ",e);
	return OK;
}

int main(void)
{
	int op=1,state;		//op=1:程序入口,state:接受返回值,表示函数返回状态
	int i,e,LR;			//LR:左子树(LR=0),右子树(LR=1)
	BiTree T=NULL;		//T:二叉树名、头指针
	Node *Temp=NULL,*NewTree=NULL;

	//BiTree_L:二叉树的头指针构成的线性表
	BiTreeList BiTree_L=(BiTreeList)malloc(sizeof(BiTreeHeadPointer));
	BiTree_L->head=NULL;
	BiTree_L->next=NULL;

	while(op)
	{
		system("cls");
		printf("\n\n");
		printf("      Menu for Binary Tree on Linked Storage Structure      \n");
		printf("------------------------------------------------------------\n");
		printf("        0. Exit \n");
		printf("        1. InitBiTree          2. DestroyBiTree \n");
		printf("        3. CreateBiTree        4. ClearBiTree \n");
		printf("        5. BiTreeEmpty         6. BiTreeDepth \n");
		printf("    	7. BiTreeRoot          8. GetNodeValue \n");
		printf("    	9. AssignNode         10. GetNodeParent \n");
		printf("       11. GetLeftChild       12. GetRightChild \n");
		printf("       13. GetLeftSibling     14. GetRightSibling \n");
		printf("       15. InsertChild        16. DeleteChild \n");
		printf("       17. PreOrderTraverse   18. InOrderTraverse \n");
		printf("       19. PostOrderTraverse  20. LevelOrderTraverse \n");
		printf("       21. SaveBiTree         22. LoadBiTree \n");
		printf("       23. CreatAnothBiTree   24. ChooseBiTree \n");
		printf("------------------------------------------------------------\n");
		printf("    请选择你的操作[0~24]:");

		//若输入数字之外的字符,清空标准输入流里的数据,并将op置为default
		if(scanf("%d",&op)!=1) {fflush(stdin);op=25;}

		switch(op)
		{
		   	case 1:
			   	state=InitBiTree(&T,BiTree_L);
			   	if(state==OK) printf("二叉树初始化成功!\n");
			   	else printf("二叉树已存在!\n");
			   	system("pause");
			   	break;

		   	case 2:
			   	if(T==NULL) printf("二叉树不存在,无需销毁!\n");
			   	else
			   	{
				   	if(DestroyBiTree(&T,BiTree_L)==OK) printf("二叉树销毁成功!\n");
				   	else printf("二叉树销毁失败!\n");
			   	}
			   	system("pause");
			   	break;

		   	case 3:
			    if(T==NULL) printf("二叉树不存在!\n");
			    else if(T->data!=0x7fffffff) printf("非空二叉树已存在!若要对其进行创建操作,请先清空该树!\n");
			    else
			    {
				    printf("请输入先序遍历结果的二叉树,叶子节点的左右孩子节点为0:");
				    if(CreateBiTree(&T)==OK) printf("创建成功!\n");
				    else printf("创建失败!\n");
			    }
			    system("pause");
			    break;

		   	case 4:
				state=ClearBiTree(&T,BiTree_L);
				if(state==OK) printf("二叉树清空成功!\n");
				else printf("二叉树清空失败!\n");
				system("pause");
				break;
		   

           	case 5:
               	state=BiTreeEmpty(T);
               	if(state==TRUE) printf("该树是空树!\n");
               	else if(state==FALSE) printf("该树不是空树!\n");
               	system("pause");
               	break;

		   	case 6:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else printf("该二叉树的深度为%d!\n",BiTreeDepth(T));
			   	system("pause");
               	break;

		   	case 7:
			   if(T==NULL) printf("二叉树不存在!\n");
			   else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   else printf("该二叉树根节点的数据元素为%d!\n",Root(T)->data);
			   system("pause");
               break;

		   case 8:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
			   		printf("输入i,获取二叉树层序遍历下第i个数据元素的值:");
			   		scanf("%d",&i);
			  		if(GetNode(T,i,&Temp)==ERROR) printf("输入错误,不存在第%d个数据元素!\n",i);
			   		else
			   		{
				   		state=Value(T,Temp);
				   		if(state==ERROR) printf("操作失败!\n");
				   		else printf("二叉树层序遍历下第%d个数据元素的值为%d!\n",i,Value(T,Temp));
			   		}
			   	}
			   	system("pause");
               	break;

		   case 9:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
			   		printf("输入i,e,将二叉树层序遍历下第i个数据元素赋值为 e :");
			   		scanf("%d%d",&i,&e);
			  		if(GetNode(T,i,&Temp)==ERROR) printf("输入错误,不存在第%d个数据元素!\n",i);
			   		else
			   		{
				   		state=Assign(T,Temp,e);
				   		if(state==ERROR) printf("操作失败!\n");
				   		else printf("赋值成功!\n");
			   		}
				}
			   system("pause");
               break;

		   	case 10:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
			   		printf("输入i,获取二叉树层序遍历下第i个数据元素的父亲节点的值 :");
			   		scanf("%d",&i);
			  		if(GetNode(T,i,&Temp)==ERROR) printf("输入错误,不存在第%d个数据元素!\n",i);
			   		else
			   		{
				   		Temp=Parent(T,Temp);
				   		if(Temp==NULL) printf("操作失败!该节点没有父亲节点!\n");
				   		else printf("二叉树层序遍历下第%d个数据元素的父亲节点的值为%d!\n",i,Value(T,Temp));
			   		}
			   	}
			   	system("pause");
               	break;

		   	case 11:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
			   		printf("输入i,获取二叉树层序遍历下第i个数据元素的左孩子节点的值 :");
			   		scanf("%d",&i);
			  		if(GetNode(T,i,&Temp)==ERROR) printf("输入错误,不存在第%d个数据元素!\n",i);
			   		else
			   		{
				   		Temp=LeftChild(T,Temp);
				   		if(Temp==NULL) printf("操作失败!该节点没有左孩子节点!\n");
				   		else printf("二叉树层序遍历下第%d个数据元素的左孩子节点的值为%d!\n",i,Value(T,Temp));
			   		}
			   	}
			   	system("pause");
               	break;

		   	case 12:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
			   		printf("输入i,获取二叉树层序遍历下第i个数据元素的右孩子节点的值 :");
			   		scanf("%d",&i);
			  		if(GetNode(T,i,&Temp)==ERROR) printf("输入错误,不存在第%d个数据元素!\n",i);
			   		else
			   		{
				   		Temp=RightChild(T,Temp);
				   		if(Temp==NULL) printf("操作失败!该节点没有右孩子节点!\n");
				   		else printf("二叉树层序遍历下第%d个数据元素的右孩子节点的值为%d!\n",i,Value(T,Temp));
			   		}
			   	}
			   	system("pause");
               	break;

		    case 13:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
			   		printf("输入i,获取二叉树层序遍历下第i个数据元素的左兄弟节点的值 :");
			   		scanf("%d",&i);
			  		if(GetNode(T,i,&Temp)==ERROR) printf("输入错误,不存在第%d个数据元素!\n",i);
			   		else
			   		{
				   		Temp=LeftSibling(T,Temp);
				   		if(Temp==NULL) printf("操作失败!该节点没有左兄弟节点!\n");
				   		else printf("二叉树层序遍历下第%d个数据元素的左兄弟节点的值为%d!\n",i,Value(T,Temp));
			   		}
			   	}
			   	system("pause");
               	break;

		   	case 14:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
			   		printf("输入i,获取二叉树层序遍历下第i个数据元素的右兄弟节点的值 :");
			   		scanf("%d",&i);
			  		if(GetNode(T,i,&Temp)==ERROR) printf("输入错误,不存在第%d个数据元素!\n",i);
			   		else
			   		{
				   		Temp=RightSibling(T,Temp);
				   		if(Temp==NULL) printf("操作失败!该节点没有右兄弟节点!\n");
				   		else printf("二叉树层序遍历下第%d个数据元素的右兄弟节点的值为%d!\n",i,Value(T,Temp));
			   		}
			   	}
			   	system("pause");
               	break;

		   	case 15:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
			   		printf("输入i,以二叉树层序遍历下第i个节点为根节点,插入新树 :");
			   		scanf("%d",&i);
			   		printf("请选择:\n0.插入到该节点的左子树。\n1.插入到该节点的右子树。\n");
			   		scanf("%d",&LR);
			  		if(GetNode(T,i,&Temp)==ERROR) printf("输入错误,不存在第%d个数据元素!\n",i);
			  		else if(LR!=0&&LR!=1) printf("输入错误!请输入0或1以选择插入到该节点的左子树或右子树。\n");
			   		else
			   		{
						//初始化NewTree,将NewTree置为空树
						NewTree=(BiTree)malloc(sizeof(Node));
						NewTree->data=0x7fffffff;
						NewTree->LeftChild=NewTree->RightChild=NULL;
				   		printf("请输入先序遍历结果的二叉树,叶子节点的左右孩子节点为0,同时保证该二叉树右子树为空:\n");
				   		CreateBiTree(&NewTree);
				   		state=InsertChild(T,Temp,LR,NewTree);
				   		if(state==ERROR) printf("操作失败!\n");
				   		else printf("操作成功!\n");
			   		}
			   	}
			   	system("pause");
               	break;

		  	case 16:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
			   		printf("输入i,删除以二叉树层序遍历下第i个数据元素为根节点的子树:");
			   		scanf("%d",&i);
			   		printf("请选择:\n0.删除以该节点为根节点的左子树。\n1.删除以该节点为根节点的右子树。\n");
			   		scanf("%d",&LR);
			  		if(GetNode(T,i,&Temp)==ERROR) printf("输入错误,不存在第%d个数据元素!\n",i);
			   		else
			   		{
				   		state=DeleteChild(T,Temp,LR,BiTree_L);
				   		if(state==ERROR) printf("操作失败!\n");
				   		else printf("删除成功!\n");
			   		}
			   	}
			   	system("pause");
               	break;

		   	case 17:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
				   	if(PreOrderTraverse(T,visit)==OK) printf("\n前序遍历成功!\n");
				   	else printf("\n前序遍历失败!\n");
			   	}
			   	system("pause");
			   	break;


		   	case 18:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
				   	if(InOrderTraverse(T,visit)==OK) printf("\n中序遍历成功!\n");
				   	else printf("\n中序遍历失败!\n");
			   	}
			   	system("pause");
			   	break;

		   	case 19:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
				   	if(PostOrderTraverse(T,visit)==OK) printf("\n后序遍历成功!\n");
				   	else printf("\n后序遍历失败!\n");
			   	}
			   	system("pause");
			   	break;

		   	case 20:
			   	if(T==NULL) printf("二叉树不存在!\n");
			   	else if(T->data==0x7fffffff) printf("该二叉树为空二叉树!\n");
			   	else
			   	{
				   	if(LevelOrderTraverse(T,visit)==OK) printf("\n层序遍历成功!\n");
				   	else printf("\n层序遍历失败!\n");
			   	}
			   	system("pause");
			   	break;  

		   	case 21:
			   	if(SaveBiTree(T)==OK) printf("二叉树保存成功!\n");
			   	else printf("二叉树保存失败!\n");
			   	system("pause");
			   	break;

		   	case 22:
			   	if(LoadBiTree(&T,BiTree_L)==OK) printf("二叉树加载成功!\n");
			   	else printf("二叉树加载失败!\n");
			   	system("pause");
			   	break;

		   	case 23:
			   	if(CreatAnotherBiTree(&T,BBiTree_L)==OK) printf("创建新的二叉树成功!\n");
			   	else printf("操作失败!\n");
			   	system("pause");
			  	break;

		   	case 24:
			   	if(ChooseBiTree(&T,BiTree_L)==OK) printf("成功选中该二叉树!\n");
			   	else printf("操作失败!\n");
			   	system("pause");
			   	break;

		   	case 0:
			   	break;

		   	default:
			   	printf("输入无效!菜单功能选择失败!\n");
			   	system("pause");
			   	break;

		}//end of switch

	}//end of while
	
	printf("欢迎下次再使用本系统!\n");
	return 0;
}//end of main()

//初始化二叉树:初始条件是二叉树T不存在;操作结果是构造空二叉树T。
//二叉树不存在:T==NULL
//空二叉树:T!=NULL&&T->data==0x7fffffff
status InitBiTree(BiTree *T,BiTreeList BiTree_L)
{
	BiTreeHeadPointer *p=BiTree_L;
	if ((*T)==NULL)
	{
		(*T)=(BiTree)malloc(sizeof(Node));				//为根节点分配空间
		(*T)->data=0x7fffffff;							//数据域置为0x7fffffff,将该树置为空二叉树
		(*T)->LeftChild=(*T)->RightChild=NULL;			//左右孩子节点指针置为NULL
		while(p->next!=NULL) p=p->next;					//遍历至表尾
		p->next=(BiTreeList)malloc(sizeof(BiTreeHeadPointer));		//为节点分配空间
		if(p->next==NULL) exit(OVERFLOW);				//ERROR:OVERFLOW
		p->next->head=(*T);								//数据域录入该二叉树的表头指针
		p->next->next=NULL;								//指针域置空
		return OK;
	}
	else return ERROR;									//ERROR:二叉树已经存在
}

//销毁二叉树:初始条件是二叉树T已存在;操作结果是销毁二叉树T。
status DestroyBiTree(BiTree *T,BiTreeList BiTree_L)
{
	BiTreeHeadPointer *pre_p=BiTree_L,*p=BiTree_L->next;//pre_p:p的前一个结点
	if((*T)==NULL) return OK;							//返回OK:空节点
	DestroyBiTree(&(*T)->LeftChild,BiTree_L);			//销毁左子树
	DestroyBiTree(&(*T)->RightChild,BiTree_L);			//销毁右子树
	while(p!=NULL&&p->head!=(*T))
	{
		pre_p=p;										//更新pre_p
		p=p->next;										//遍历至表尾
	}
	if(p!=NULL)
	{
		//若该二叉树在二叉树头指针构成的线性表上,将其从线性表中删除
		pre_p->next=p->next;							//执行删除操作
		free(p);										//释放节点空间
	}
	free(*T);											//释放根节点
	(*T)=NULL;											//头指针置空
	return OK;
}

//创建二叉树:初始条件是definition 给出二叉树T的定义;操作结果是按definition构造二叉树T。
status CreateBiTree(BiTree *T)
{
	ElemType Data;
	if(scanf("%d",&Data)!=EOF&&Data!=0)					//输入二叉树节点的值(非0)
	{
		if((*T)==NULL)									//若节点为NULL,创建节点
		{
			(*T)=(BiTree)malloc(sizeof(Node));			//分配空间
			(*T)->LeftChild=(*T)->RightChild=NULL;		//左右孩子节点指针置为NULL
			if((*T)==NULL) exit(OVERFLOW);				//ERROR:OVERFLOW
		}
		(*T)->data=Data;								//节点数据域赋值
		CreateBiTree(&(*T)->LeftChild);					//递归:创建该节点的左子树
		CreateBiTree(&(*T)->RightChild);				//递归:创建该节点的右子树
		return OK;
	}
	else return ERROR;									//ERROR:根节点为0
}

//清空二叉树:初始条件是二叉树T存在;操作结果是将二叉树T清空。
status ClearBiTree(BiTree *T,BiTreeList BiTree_L)
{
	if((*T)==NULL) {printf("二叉树不存在,无需清空!\n");return ERROR;}
	else if((*T)->data==0x7fffffff) {printf("该二叉树为空二叉树!\n");return ERROR;}
	if(DestroyBiTree(T,BiTree_L)==OK&&InitBiTree(T,BiTree_L)==OK) return OK;		//清空=销毁+初始化
	else return ERROR;
}

//判定空二叉树:初始条件是二叉树T存在;操作结果是若T为空二叉树则返回TRUE,否则返回FALSE。
status BiTreeEmpty(BiTree T)
{
	if(T==NULL) {printf("二叉树不存在!\n");return ERROR;}
	else if(T->data==0x7fffffff)	return TRUE;		//TRUE:空二叉树
	else return FALSE;									//FALSE:非空二叉树
}


//求二叉树深度:初始条件是二叉树T存在;操作结果是返回T的深度。
int BiTreeDepth(BiTree T)
{
	int Depth=0,Depth_L,Depth_R;						//Depth_L:左子树深度;Depth_R:右子树深度
	if(T==NULL) return 0;								//return 0:二叉树不存在
	else
	{
		Depth_L=BiTreeDepth(T->LeftChild);				//递归:获取左子树深度
		Depth_R=BiTreeDepth(T->RightChild);				//递归:获取右子树深度
		//以该节点为根节点的树的深度是左、右子树深度的最大值加一
		Depth+=1+( Depth_L>Depth_R ? Depth_L:Depth_R);
		return Depth;									//返回深度
	}
}

//获得根结点:初始条件是二叉树T已存在;操作结果是返回T的根。
Node *Root(BiTree T)
{
	return T;
}

//获得结点:初始条件是二叉树T已存在,e是T中的某个结点;操作结果是返回e的值。
ElemType Value(BiTree T,Node *e)
{
	return e->data;										//返回该节点数据域的值
}

//结点赋值:初始条件是二叉树T已存在,e是T中的某个结点;操作结果是结点e赋值为value。
status Assign(BiTree T,Node *e,ElemType value)
{
	e->data=value;										//节点数据域赋值
	return OK;
}

//获得双亲结点:初始条件是二叉树T已存在,e是T中的某个结点。
//操作结果是若e是T的非根结点,则返回它的双亲结点指针,否则返回NULL。
Node *Parent(BiTree T,Node *e)
{
	Node *Queue[Set_MAXSIZE]={NULL};					//节点数组:存储层序遍历的每个结点指针
	Node *LeftChild=NULL,*RightChild=NULL;
	//游走监视哨:i指向数组的下一个空位,j指向正在遍历的节点的父亲节点
	int i=1,j=0;
	Queue[0]=T;											//首先遍历根节点
	while(i>j)											//循环结束条件:j>=i
	{
		if (Queue[j])									//若Queue[j]!=NULL,访问其左右孩子节点
        {
			LeftChild=Queue[j]->LeftChild;
			RightChild=Queue[j]->RightChild;
			if(LeftChild) Queue[i++]=LeftChild;			//存储j的非空左孩子结点,i++
			if(RightChild) Queue[i++]=RightChild;		//存储j的非空右孩子结点,i++
        }
        j++;											//j指向上一层的下一个节点
	}
	//遍历该数组,寻找左孩子或者右孩子为e的节点
	for(i=0;Queue[i]!=NULL;i++)	
		if(Queue[i]->LeftChild==e||Queue[i]->RightChild==e) break;
	return Queue[i];									//返回该节点
}

//获得左孩子结点:初始条件是二叉树T存在,e是T中某个节点。
//操作结果是返回e的左孩子结点指针。若e无左孩子,则返回NULL。
Node *LeftChild(BiTree T,Node *e)
{
	return e->LeftChild;								//返回其左孩子节点
}

//获得右孩子结点:初始条件是二叉树T已存在,e是T中某个结点。
//操作结果是返回e的右孩子结点指针。若e无右孩子,则返回NULL。
Node *RightChild(BiTree T,Node *e)
{
	return e->RightChild;								//返回其右孩子节点
}

//获得左兄弟结点:初始条件是二叉树T存在,e是T中某个结点。
//操作结果是返回e的左兄弟结点指针。若e是T的左孩子或者无左兄弟,则返回NULL。
Node *LeftSibling(BiTree T,Node *e)
{
	Node *parents=Parent(T,e);							//parents:获取该节点的父亲节点
	if(parents==NULL) return NULL;						//ERROR:该节点没有父亲节点
	//若该节点是其父亲节点的右孩子节点,返回该节点的左兄弟
	if(parents->RightChild==e) return parents->LeftChild;
	else return NULL;									//ERROR:该节点是其父亲节点的左孩子节点
}

//获得右兄弟结点:初始条件是二叉树T已存在,e是T中某个结点。
//操作结果是返回e的右兄弟结点指针。若e是T的右孩子或者无右兄弟,则返回NULL。
Node *RightSibling(BiTree T,Node *e)
{
	Node *parents=Parent(T,e);							//parents:获取该节点的父亲节点
	if(parents==NULL) return NULL;						//ERROR:该节点没有父亲节点
	//若该节点是其父亲节点的左孩子节点,返回该节点的右兄弟
	if(parents->LeftChild==e) return parents->RightChild;
	else return NULL;									//ERROR:该节点是其父亲节点的右孩子节点
}

//插入子树:初始条件是二叉树T存在,p指向T中的某个结点,LR为0或1。
//非空二叉树c与T不相交且右子树为空。
//操作结果是根据LR为0或者1,插入c为T中p所指结点的左或右子树,p所指结点的原有左子树或右子树则为c的右子树。
status InsertChild(BiTree T,Node *p,int LR,BiTree c)
{
	if(c->RightChild!=NULL) return ERROR;				//ERROR:c的右子树不为空
	if(LR==0)											//插入到左子树
	{
		c->RightChild=p->LeftChild;						//将p的左子树移动到c的右子树
		p->LeftChild=c;									//将c插入到p的左子树
	}
	else if(LR==1) 										//插入到右子树
	{
		c->RightChild=p->RightChild;					//将p的右子树移动到c的右子树
		p->RightChild=c;								//将c插入到p的右子树
	}
	return OK;
}

//删除子树:初始条件是二叉树T存在,p指向T中的某个结点,LR为0或1。
//操作结果是根据LR为0或者1,删除c为T中p所指结点的左或右子树。
status DeleteChild(BiTree T,Node *p,int LR,BiTreeList BiTree_L)
{
	if(LR==0) {DestroyBiTree(&(p->LeftChild),BiTree_L);return OK;}			//销毁左子树
	else if(LR==1) {DestroyBiTree(&(p->RightChild),BiTree_L);return OK;}	//销毁右子树
	else return ERROR;									//ERROR:LR!=0&&LR!=1(输入错误)
}

//前序遍历:初始条件是二叉树T存在;操作结果:先序遍历T,对每个结点调用函数visit一次。
status PreOrderTraverse(BiTree T,status (*visit)(ElemType e))
{
	if(T==NULL) return OK;								//return OK:空树
	visit(T->data);										//访问该根节点
	PreOrderTraverse(T->LeftChild,visit);				//递归:遍历左子树
	PreOrderTraverse(T->RightChild,visit);				//递归:遍历右子树
	return OK;
}

//中序遍历:初始条件是二叉树T存在;操作结果是中序遍历T,对每个结点调用函数visit一次。
status InOrderTraverse(BiTree T,status (*visit)(ElemType e))
{
	if(T==NULL) return OK;								//return OK:空树
	InOrderTraverse(T->LeftChild,visit);				//递归:遍历左子树
	visit(T->data);										//访问该根节点
	InOrderTraverse(T->RightChild,visit);				//递归:遍历右子树
	return OK;
}

//后序遍历:初始条件是二叉树T存在;操作结果是后序遍历T,对每个结点调用函数visit一次。
status PostOrderTraverse(BiTree T,status (*visit)(ElemType e))
{
	if(T==NULL) return OK;								//return OK:空树
	PostOrderTraverse(T->LeftChild,visit);				//递归:遍历左子树
	PostOrderTraverse(T->RightChild,visit);				//递归:遍历右子树
	visit(T->data);										//访问该根节点
	return OK;
}

//按层遍历:初始条件是二叉树T存在;操作结果是层序遍历T,对每个结点调用函数visit一次。
status LevelOrderTraverse(BiTree T,status (*visit)(ElemType e))
{
	Node *Queue[Set_MAXSIZE]={NULL};					//节点数组:存储层序遍历的每个结点指针
	Node *LeftChild=NULL,*RightChild=NULL;
	//游走监视哨:i指向数组的下一个空位,j指向正在遍历的节点的父亲节点
	int i=1,j=0;
	Queue[0]=T;											//首先遍历根节点
	while(i>j)											//循环结束条件:j>=i
	{
		if (Queue[j])									//若Queue[j]!=NULL,访问其左右孩子节点
        {
			visit(Queue[j]->data);						//访问j指向的节点
			LeftChild=Queue[j]->LeftChild;
			RightChild=Queue[j]->RightChild;
			if(LeftChild) Queue[i++]=LeftChild;			//存储j的非空左孩子结点,i++
			if(RightChild) Queue[i++]=RightChild;		//存储j的非空右孩子结点,i++
        }
        j++;											//j指向上一层的下一个节点
	}
	return OK;
}

/*
//按层遍历:初始条件是二叉树T存在;操作结果是层序遍历T,对每个结点调用函数visit一次。
status LevelOrderTraverse(BiTree T,status (*visit)(ElemType e))
{
	int Depth=BiTreeDepth(T),Level_Destination;			//获取二叉树的深度
	for(Level_Destination=1;Level_Destination<=Depth;Level_Destination++)
		LevelTraverse(T,1,Level_Destination,visit);		//依次输出每一层
	return OK;
}

//遍历输出二叉树的某一层:初始条件是二叉树T存在;操作结果是遍历输出二叉树的第i层。
//节点在第i层的另一层含义:从根节点到该节点的路径长度为i
status LevelTraverse(BiTree T,int Level_Now,int Level_Destination,status (*visit)(ElemType e))
{
	if(T==NULL) return ERROR;							//ERROR:该节点为空节点,返回
	//若该节点在目标层,输出该节点
	if(Level_Now==Level_Destination) visit(T->data);
	else
	{
		//若该节点不在目标层,依次检查其左、右孩子节点是否在目标层(保证层序从左到右)
		LevelTraverse(T->LeftChild,Level_Now+1,Level_Destination,visit);
		LevelTraverse(T->RightChild,Level_Now+1,Level_Destination,visit);
	}
	return OK;
}
*/

//获取节点:初始条件是二叉树T存在;操作结果是获取第num个节点
status GetNode(BiTree T,int num,Node **node)
{
	Node *Queue[Set_MAXSIZE]={NULL};					//节点数组:存储层序遍历的每个结点指针
	Node *LeftChild=NULL,*RightChild=NULL;
	//游走监视哨:i指向数组的下一个空位,j指向正在遍历的节点的父亲节点
	int i=1,j=0;
	Queue[0]=T;											//首先遍历根节点
	while(i>j)											//循环结束条件:j>=i
	{
		if (Queue[j])									//若Queue[j]!=NULL,访问其左右孩子节点
        {
			LeftChild=Queue[j]->LeftChild;
			RightChild=Queue[j]->RightChild;
			if(LeftChild) Queue[i++]=LeftChild;			//存储j的非空左孩子结点,i++
			if(RightChild) Queue[i++]=RightChild;		//存储j的非空右孩子结点,i++
        }
        j++;											//j指向上一层的下一个节点
	}
	if(num<1||num>i) return ERROR;						//ERROR:没有第num个节点
	else {(*node)=Queue[num-1];return OK;}				//将节点赋值给node,实现获取
}

//保存二叉树:初始条件是二叉树T存在且该二叉树不为空树;操作结果是将该二叉树保存到用户指定的文件中
status SaveBiTree(BiTree T)
{
	char filename[FILENAME_LENGTH]={0};
	FILE *fp=NULL;
	if(T==NULL) {printf("二叉树不存在!\n");return ERROR;}
	else if(T->data==0x7fffffff) {printf("该二叉树为空二叉树!\n");return ERROR;}
	printf("输入文件路径(长度应在%d字符以内),将二叉树保存到该文件中:",FILENAME_LENGTH);
	scanf("%s",filename);								//输入文件路径
	fp=fopen(filename,"w");								//打开文件
	if(fp==NULL) return ERROR;							//ERROR:打开文件错误
	if(WriteNodeToFile(T,fp)==ERROR) return ERROR;		//ERROR:写入节点错误
	fclose(fp);											//关闭文件
	return OK;
}

//将节点写入文件:初始条件是文件已打开;操作结果是将该节点保存到用户指定的文件中
status WriteNodeToFile(BiTree T,FILE *fp)
{
	if(fp==NULL) return ERROR;							//ERROR:未打开文件
	if(T==NULL) {fprintf(fp,"0 ");return OK;}			//空节点:将0写入文件
	else												//非空节点
	{
		fprintf(fp,"%d ",T->data);						//将该节点写入文件
		WriteNodeToFile(T->LeftChild,fp);				//递归:将该节点的左孩子结点写入文件
		WriteNodeToFile(T->RightChild,fp);				//递归:将该节点的右孩子结点写入文件
		return OK;
	}
}

//加载二叉树:初始条件是二叉树T存在;操作结果是将用户指定的文件中的二叉树加载出来
status LoadBiTree(BiTree *T,BiTreeList BiTree_L)
{
	char filename[FILENAME_LENGTH]={0};
	FILE *fp=NULL;
	if((*T)==NULL) {printf("二叉树不存在!\n");return ERROR;}
	if((*T)->data!=0x7fffffff) {*T=NULL;InitBiTree(T,BiTree_L);}	//若该二叉树不是空二叉树,初始化该二叉树
	printf("输入文件路径(长度应在%d字符以内),加载文件中的二叉树:",FILENAME_LENGTH);
	scanf("%s",filename);								//输入文件路径
	fp=fopen(filename,"r");								//打开文件
	if(fp==NULL) return ERROR;							//ERROR:打开文件错误
	if(ReadNodeFromFile(T,fp)==ERROR) return ERROR;	//ERROR:读取节点错误
	fclose(fp);											//关闭文件
	return OK;
}

//加载文件中的节点:初始条件是文件已打开;操作结果是将用户指定的文件中的节点加载到二叉树T中
status ReadNodeFromFile(BiTree *T,FILE *fp)
{
	ElemType Data;
	if(fscanf(fp,"%d ",&Data)!=EOF&&Data!=0)			//读取文件中二叉树节点的值(非0)
	{
		if((*T)==NULL)									//若节点为NULL,创建节点
		{
			(*T)=(BiTree)malloc(sizeof(Node));			//分配空间
			(*T)->LeftChild=(*T)->RightChild=NULL;		//左右孩子节点指针置为NULL
			if((*T)==NULL) exit(OVERFLOW);				//ERROR:OVERFLOW
		}
		(*T)->data=Data;								//节点数据域赋值
		ReadNodeFromFile(&(*T)->LeftChild,fp);			//递归:读取该节点的左孩子结点
		ReadNodeFromFile(&(*T)->RightChild,fp);			//递归:读取该节点的右孩子结点
		return OK;
	}
	else return ERROR;									//ERROR:ctrl+z或Data==0
}

//创建另一颗二叉树:初始条件是已经存在一颗二叉树
status CreatAnotherBiTree(BiTree *T,BiTreeList BiTree_L)
{
	BiTree *Temp=T;										//保存该二叉树头指针
	if((*T)==NULL) {printf("没有已存在的二叉树,无需再次创建二叉树!\n");return ERROR;}
	(*T)=NULL;											//二叉树头指针置空
	InitBiTree(T,BiTree_L);								//初始化该二叉树
	printf("请输入先序遍历结果的二叉树,叶子节点的左右孩子节点为0:");
	if(CreateBiTree(T)==OK) return OK;					//创建二叉树
	else												//创建失败
	{
		DestroyBiTree(T,BiTree_L);						//销毁该二叉树
		T=Temp;											//将保存好的头指针赋值给T
		return ERROR;
	}
}

//选择二叉树:初始条件是已经存在至少一棵二叉树
status ChooseBiTree(BiTree *T,BiTreeList BiTree_L)
{
	int i=1,n;
	BiTreeHeadPointer *p=BiTree_L->next;
	if(p==NULL) {printf("没有可选择的二叉树!\n");return ERROR;}
	while(p!=NULL)										//遍历二叉树头指针链表
	{
		printf("第 %d 个二叉树:",i);
		if(p->head->data!=0x7fffffff)					//若该二叉树不是空树
			PreOrderTraverse(p->head,visit);			//遍历该二叉树
		printf("\n");									//格式控制
		p=p->next;
		i++;
	}
	printf("输入n,选择第n个二叉树进行操作:");
	scanf("%d",&n);
	if(n>i-1||n<1) {printf("不存在第 %d 个二叉树!\n",n);return ERROR;}
	i=1;
	p=BiTree_L->next;
	while(i!=n)	{p=p->next;i++;}						//遍历二叉树头指针链表
	(*T)=p->head;										//实现二叉树的选择
	return OK;
}

演示系统相关问题的说明

  • 这个简单的演示系统是用纯C语言完成的。这也就衍生了以下的一些的问题与说明:
  1. “创建二叉树”函数中,采取了文件尾作为结束标记。正确理解文件尾EOF与CTRL+Z,请参考 :C语言中EOF与Ctrl+Z
  2. 由于C语言中不能使用“引用”,而某些函数需要改变传入参数的值,故在系统中多次使用指针以及指向指针的指针,导致可读性变差。(部分可以考虑使用全局变量代替。)
  3. 文件路径使用了scanf()函数和字符数组输入,这意味着文件路径与文件名不能含有空格,并且有长度限制。
scanf("%s",filename);
  1. C语言中产生函数符号的规则是根据名称产生,这也就注定了C语言不存在函数重载的概念。函数不能重载导致了本系统的实用性受限。关于C语言与C++,请参考:C语言与C++
  2. 本系统多次使用scanf与fscanf函数。这两个函数会导致IDE报“不安全(unsafe)”的警告(warning),甚至在某些IDE会报错(error)。

warning C4996: ‘scanf’: This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

warning C4996: ‘fscanf’: This function or variable may be unsafe. Consider using fscanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

  • 代码风格的说明
  1. 作为数据结构初学者,我几乎在每一行都写了详细的注释。
  2. 本演示系统源于《数据结构(C语言版)》(严蔚敏等著),但没有太多地参考书上的代码和思路,绝大部分是自己的理解。这意味着,不是所有的函数都是最优的函数。
  3. 本演示系统是严格按照实验要求完成的,对系统的完备性和算法的健壮性做了一定的考虑,对函数的初始条件进行了了严格的控制(例如区分“空二叉树”与“二叉树不存在”等),对输入输出操作都进行了提示,甚至显得有些繁琐。
  4. 由于实际的需要,在编写演示系统时,对一些函数的参数进行了调整。甚至还将某些操作拆分成两个函数,所以有些函数可能不符合函数之间应该满足的“高内聚,低耦合”的要求。
  5. 在编写代码时保留了一些个人习惯,如括号配对对齐等,敬请谅解

实验测试参考用例

1 2 4 6 0 0 7 0 0 5 0 0 3 0 0 
1 3 4 9 99 0 0 20 0 0 11 13 0 0 14 0 0 7 0 0 6 2 0 0 5 0 0 
1 2 4 0 0 5 0 0 3 6 0 0 7 0 0 
999 20 40 0 0 50 70 0 0 0 1 0 0 
10 20 40 0 0 50 70 0 0 0 30 0 60 0 0
10 20 0 50 70 0 0 0 30 0 60 0 0 

参考文献

[1] 严蔚敏等. 数据结构(C语言版). 清华大学出版社
[2] Larry Nyhoff. ADTs, Data Structures, and Problem Solving with C++. Second Edition, Calvin College, 2005
[3] 殷立峰. Qt C++跨平台图形界面程序设计基础. 清华大学出版社,2014:192~197
[4] 严蔚敏等.数据结构题集(C语言版). 清华大学出版社

  • 28
    点赞
  • 142
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值