参考博客:数据结构-链式二叉树
参考视频:郝斌之链式二叉树遍历具体演示
创建如上图所示的二叉树,并使用链式二叉树实现,先序、中序和后序遍历,求叶子结点和总的节点个数,求二叉树的深度以及删除节点等操作。
/*******************************************************
* 功能: 实现链式二叉树的相关操作,包括创建、遍历、删除
* 查找、销毁以及求总的节点和叶子结点数和数的深度等
* 作者: 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
未完成的已经补上来了,在查找(父)节点时,注意传入的指针类型,也即:对什么类型的数据的值进行修改,就传入该类型的地址,指针的地址也就是指针的指针