举例演示链式二叉树的各类操作——包括遍历、求总的(叶子)节点个数、深度、查找、删除节点等

参考博客:数据结构-链式二叉树
参考视频:郝斌之链式二叉树遍历具体演示

在这里插入图片描述
创建如上图所示的二叉树,并使用链式二叉树实现,先序、中序和后序遍历,求叶子结点和总的节点个数,求二叉树的深度以及删除节点等操作。

/*******************************************************
* 功能: 实现链式二叉树的相关操作,包括创建、遍历、删除
*       查找、销毁以及求总的节点和叶子结点数和数的深度等
* 作者: khq
* 时间: 2020年4月20日
********************************************************/

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>

//定义二叉树的参数
typedef struct BTree{
	char data;  //数据域
	struct BTree *lchild;  //左子树
	struct BTree *rchild;  //右子树
}BTNODE,*PBTREE;

//方法声明
PBTREE creatBTree();   //创建二叉树
void preTraverse(PBTREE);  //先序遍历
void inTraverse(PBTREE);  //中序遍历
void postTraverse(PBTREE);  //后序遍历
int getLeafCount(PBTREE);  //求叶子结点数
int getTotalNodeCount(PBTREE);  //获取总的节点数
int getTreeDepth(PBTREE);  //获取树的深度
void destoryBTNode(PBTREE);  //销毁二叉树上的节点

/*******************************************************
*  查找有没有节点的数据为x,若有,返回true,并将该节点
* 的地址给p,否则,返回false,*不可或缺 
********************************************************/
bool findNode(PBTREE,char,PBTREE *);  

/********************************************************
* 已知二叉树含有某节点,求该节点的父节点,并指出该节点
* 是父节点的左孩子还是右孩子,并保存父节点的地址
********************************************************/
bool getParentNode(PBTREE,char,PBTREE *,int *);  
bool deleteBTNode(PBTREE,char);  //删除某一节点

int main(void){
	printf("开始创建二叉树......\n");
	PBTREE bTree = creatBTree();
	printf("先序遍历二叉树结果......\n");
	preTraverse(bTree);
	printf("\n中序遍历二叉树的结果......\n");
	inTraverse(bTree);
	printf("\n后序遍历二叉树的结果......\n");
	postTraverse(bTree); 
	printf("\n该二叉树的叶子结点数为: %d\n",getLeafCount(bTree));
	printf("该二叉树总的节点数为: %d\n",getTotalNodeCount(bTree));
	printf("该二叉树的深度为: %d\n",getTreeDepth(bTree));
	char x = 'H';
	PBTREE pT;
	printf("在二叉树中查找节点:%c \n",x);
	if(findNode(bTree,x,&pT))
		printf("该二叉树中含有数据为%c的节点.\n",pT->data);
	else
		printf("该二叉树中不包含数据为%c的节点.\n",x);
	PBTREE parent;
	int lr;
	if(getParentNode(bTree,x,&parent,&lr)){
		printf("节点%c的父节点是%c.\n",x,parent->data);
		if(lr==0)
			printf("节点%c是父节点%c的左孩子\n.",x,parent->data);
		else
			printf("节点%c是父节点%c的右孩子.\n",x,parent->data);
	}else
		printf("节点%c在该二叉树中没有父节点.\n",x);
	printf("删除节点%c.\n",x);
	if(deleteBTNode(bTree,x))
		printf("节点%c删除成功.\n",x);
	else
		printf("删除失败!\n");
	printf("删除节点%c后,先序遍历二叉树结果......\n",x);
	preTraverse(bTree);
	return 0;
}

//创建二叉树
PBTREE creatBTree(){	  //返回根节点的地址,也就是pA的地址
	//创建所需要的节点
	PBTREE pA = (PBTREE)malloc(sizeof(BTNODE));
	PBTREE pB = (PBTREE)malloc(sizeof(BTNODE));
	PBTREE pC = (PBTREE)malloc(sizeof(BTNODE));
	PBTREE pD = (PBTREE)malloc(sizeof(BTNODE));
	PBTREE pE = (PBTREE)malloc(sizeof(BTNODE));
	PBTREE pF = (PBTREE)malloc(sizeof(BTNODE));
	PBTREE pG = (PBTREE)malloc(sizeof(BTNODE));
	PBTREE pH = (PBTREE)malloc(sizeof(BTNODE));
	PBTREE pI = (PBTREE)malloc(sizeof(BTNODE));
	PBTREE pJ = (PBTREE)malloc(sizeof(BTNODE));
	PBTREE pK = (PBTREE)malloc(sizeof(BTNODE));
	PBTREE pL = (PBTREE)malloc(sizeof(BTNODE));

	//每个节点存储相应的数据
	pA->data = 'A';
	pB->data = 'B';
	pC->data = 'C';
	pD->data = 'D';
	pE->data = 'E';
	pF->data = 'F';
	pG->data = 'G';
	pH->data = 'H';
	pI->data = 'I';
	pJ->data = 'J';
	pK->data = 'K';
	pL->data = 'L';

	//各个节点之间通过指针相连
	pA->lchild = pB;
	pA->rchild = pF;
	pB->lchild = pC;
	pB->rchild = pD;
	pC->lchild = pE;
	pC->rchild = NULL;
	pD->lchild = pD->rchild = NULL;
	pE->lchild = pE->rchild = NULL;
	pF->lchild = pG;
	pF->rchild = pH;
	pG->lchild = pI;
	pG->rchild = pJ;
	pH->lchild = NULL;
	pH->rchild = pL;
	pI->lchild = pI->rchild = NULL;
	pJ->lchild = NULL;
	pJ->rchild = pK;
	pK->lchild = pK->rchild = NULL;
	pL->lchild = pL->rchild = NULL;

	return pA;  //返回根节点的地址
}

/*
* 递归实现大部分算法
*/

//先序遍历二叉树
void preTraverse(PBTREE pBT){
	if(NULL != pBT){  //不可忽略
		printf("%c ",pBT->data);  //先访问(子树的)根节点的数据
		if(NULL != pBT->lchild){
			preTraverse(pBT->lchild);  //再访问左子树
		}
		if(NULL != pBT->rchild){
			preTraverse(pBT->rchild);  //再访问右子树
		}
	}
} 

//中序遍历二叉树 
void inTraverse(PBTREE pBT){
	if(NULL != pBT){ 
		if(NULL != pBT->lchild){
			inTraverse(pBT->lchild);  //先访问左子树
		}
		printf("%c ",pBT->data);  //再访问(子树的)根节点的数据
		if(NULL != pBT->rchild){
			inTraverse(pBT->rchild);  //再访问右子树
		}
	}
}

//后序遍历二叉树
void postTraverse(PBTREE pBT){
	if(NULL != pBT){
		if(NULL != pBT->lchild){
			postTraverse(pBT->lchild);  //先访问左子树
		}
		if(NULL != pBT->rchild){
			postTraverse(pBT->rchild);  //再访问右子树
		}
		printf("%c ",pBT->data);  //再访问(子树的)根节点的数据
	}
}

//求叶子结点数(没有子节点的节点)
int getLeafCount(PBTREE pBT){
	if(NULL == pBT)
		return 0;
	if(NULL==pBT->lchild && pBT->rchild==NULL)
		return 1;
	return getLeafCount(pBT->lchild)+getLeafCount(pBT->rchild);
}

//求总的节点数
int getTotalNodeCount(PBTREE pBT){
	if(NULL == pBT)
		return 0;
	else{
		return getTotalNodeCount(pBT->lchild) + getTotalNodeCount(pBT->rchild) + 1;  //1表示树(子树)的根节点
	}
}

//求树的深度
int getTreeDepth(PBTREE pBT){
	int d,d1,d2;
	if(NULL == pBT)
		d = 0;
	else{
		d1 = getTreeDepth(pBT->lchild);
		d2 = getTreeDepth(pBT->rchild);
		d = (d1>d2)?(d1+1):(d2+1);
	}
	return d;
}

//销毁所有节点
void destoryBTNode(PBTREE pBT){
	if(NULL!=pBT){
		destoryBTNode(pBT->lchild);
		destoryBTNode(pBT->rchild);
		free(pBT);
		pBT=NULL;
	}
}

//查找有没有节点的数据为x,若有,返回true,并将该节点的地址给p,否则,返回false
//总结:对什么类型的数据的值进行修改,就传入该类型的地址,指针的地址也就是指针的指针
bool findNode(PBTREE pBT,char x,PBTREE *p){  //小心p为野指针,加上*,让其用来保存地址,指针的指针
	if(NULL == pBT){		
		*p = NULL;
		return false;
	}else if(pBT->data == x){
		*p = pBT;   //相当于pT = pBT;
//		printf("找到%c\n",p->data);
		return true;
	}else{
		if(findNode(pBT->lchild,x,p))
			return true; 
		else if(findNode(pBT->rchild,x,p))
			return true;
		else{
			p = NULL;
			return false;
		}
	}
}

//已知二叉树含有某节点,求该节点的父节点,并指出该节点是父节点的左孩子还是右孩子,并保存父节点的地址
bool getParentNode(PBTREE pBT,char x,PBTREE *pnt,int *LR){
	if(pBT->data == x){  //该节点是根节点,无父节点
		*pnt = NULL;
		LR = NULL;
		return false;
	} else if(pBT->lchild && pBT->lchild->data == x){  //在左子树上查找
		*LR = 0;
		*pnt = pBT;
		return true;
	} else if(pBT->rchild && pBT->rchild->data == x){  //在右子树上查找
		*LR = 1;
		*pnt = pBT;
		return true;
	}else{
		if(pBT->lchild && getParentNode(pBT->lchild,x,pnt,LR)){  //在左子树上递归查找
			return true;
		}else if(pBT->rchild && getParentNode(pBT->rchild,x,pnt,LR)){  //在右子树上递归查找
			return true;
		}else{
			*pnt = NULL;
			LR = NULL;
			return false;
		}
	}	
}

bool deleteBTNode(PBTREE pBT,char x){  //删除某一节点
	PBTREE p,parent;
	int LR;
	if(findNode(pBT,x,&p)){  //先找到该节点的位置
		if(getParentNode(pBT,x,&parent,&LR)){  //找到该节点的父节点
			if(LR==0){
				destoryBTNode(parent->lchild);
				return true;
			}else{
				destoryBTNode(parent->rchild);
				return true;
			}
		}else{  //如果是根节点
			destoryBTNode(pBT);
			return true;
		}  			
	} else  //没有找到该节点
		return false;	
}

结果显示:
在这里插入图片描述
至于节点的查找和删除等其他操作接下来继续研究,搞懂它,加油!——2020年4月19


未完成的已经补上来了,在查找(父)节点时,注意传入的指针类型,也即:对什么类型的数据的值进行修改,就传入该类型的地址,指针的地址也就是指针的指针

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值