二叉树是一种应用十分广泛的数据结构,本文所述的二叉树的基本操作主要包括创建二叉树型的数据,对二叉树进行遍历(三种遍历方式)、增加节点、删除单个节点(重点)、销毁二叉树、插入一个节点、查询节点。
#pragma once
#include<stdio.h>
#include<stdlib.h>
typedef struct BitTree //结构体变量
{
int data;
struct BitTree *left;
struct BitTree *right;
}Bst,*Bstp;
int InsertData(struct BitTree *bt,int key) //插入一个数据,用于创建二叉树
{
if(key>bt->data) //判断是否插到右子树
{
if (bt->right == NULL) //判断是否右子树是否可插入
{
bt->right = (struct BitTree *)malloc(sizeof(struct BitTree));
bt->right->left = bt->right->right = NULL;
bt->right->data = key;
/*printf("%d\n", bt->right->data);*/
return 1;
}
else
{
InsertData(bt->right, key);
}
}
else if(key<bt->data) //判断是否插到左子树
{
if (bt->left == NULL)
{
bt->left = (struct BitTree *)malloc(sizeof(struct BitTree));
if (bt->left == NULL)
printf("left malloc error\n");
bt->left->left = bt->left->right = NULL;
bt->left->data = key;
return 1;
}
else
{
InsertData(bt->left, key); //递归到下一个子树的“根节点”
}
}
else //如果该数值与节点值相等,不做任何处理,继续插入下一个值
{
return 1;
}
}
void Previsit(Bstp a) //先序遍历
{
if (a != NULL)
{
printf(" %d ", a->data); //先输出根节点的数据
Previsit(a->left); //再遍历左子树
Previsit(a->right); //最后再遍历右子树
}
else
return;
}
void Inorder(Bstp a) //中序遍历
{
if (a != NULL)
{
Inorder(a->left);
printf(" %d ", a->data);
Inorder(a->right);
}
else
return;
}
void PostOrder(Bstp a)//后序遍历
{
if (a != NULL)
{
PostOrder(a->left);
PostOrder(a->right);
printf(" %d ", a->data);
}
else
return;
}
void VisitTree(Bstp x) //综合三种遍历方式的子函数,在主函数调用
{
printf("先序遍历:");
Previsit(x);
printf("\n中序遍历:");
Inorder(x);
printf("\n后序遍历:");
PostOrder(x);
printf("\n");
}
Bstp CreatTree(void)//创建二叉树的综合性子函数,返回值为已创建二叉树的根节点地址
{
int num;
struct BitTree *anew=NULL;
printf("请输入数据:");
scanf_s("%d", &num); //先把输入的第一个数创建为根节点防止调用函数时传递野指针
if (num >= 0)
{
anew = (Bstp)malloc(sizeof(Bst));
anew->data = num;
anew->left = anew->right = NULL;
}
else
{
printf("Error!\n");
return NULL;
}
do //进入循环体,开始递归单个添加数据
{
scanf_s("%d", &num);
if(num>=0)
InsertData(anew, num);
} while (num >= 0);
return anew; //返回根节点地址
}
void InserNumber(Bstp x) //插入函数
{
int k;
printf("请输入要插入的数据:");
scanf_s("%d", &k);
InsertData(x, k); //递归插入
printf("\n 插入完成! \n\n");
return;
}
int subFind(Bstp x, int f) //查询子函数,递归查找,查找成功返回1,否则返回0
{
if (f == x->data)
{
return 1;
}
else
{
if (f > x->data&&x->right!=NULL)
{
subFind(x->right, f);
}
else if(f<x->data&&x->left!=NULL)
{
subFind(x->left, f);
}
else
{
return 0;
}
}
}
void PrintFind(Bstp x,int f)// 用于打印查找成功后的祖先节点
{
if (f == x->data)
{
printf("%d ", x->data);
}
else
{
if (f > x->data&&x->right != NULL)
{
printf("%d ", x->data);
PrintFind(x->right, f);
}
else if (f < x->data&&x->left != NULL)
{
printf("%d ", x->data);
PrintFind(x->left, f);
}
}
}
void FindAnum(Bstp x) //查询函数
{
int f;
printf("请输入你要查找的数据:");
scanf_s("%d", &f);
if (subFind(x,f))
{
printf("\n查找成功!\n");
printf("\n祖先及其该节点为:");
PrintFind(x,f);
printf("\n");
}
else
{
printf("\n查找失败!\n");
}
return;
}
void myfree(Bstp x) //销毁函数
{
extern int Node;
if (x!= NULL)
{
myfree(x->left); //按照左右的先后顺序释放内存
myfree(x->right);
free(x);
Node++; //每释放一块内存,该数就会自增一次
return;
}
}
//锁定要删除的数据的位置,返回该数据的首地址
Bstp LocaTar(Bstp x, int k)
{
Bstp loca = x;
Bstp fath;
fath = x;
/*如果目标节点已经找到返回该节点指针*/
if (loca->data == k)
{
return loca;
}
/*否则进入递归环节*/
else
{
/*先判断在左子树还是在右子树*/
if (loca->data < k) //左
{
fath = loca;
loca = loca->right;
LocaTar(loca, k); //递归
}
else //右
{
fath = loca;
loca = loca->left;
LocaTar(loca, k); //递归
}
}
}
//用于锁定待删除数据的双亲首地址
Bstp LocaFath(Bstp x, int k)
{
Bstp fath=x; //初始化双亲地址为根节点
Bstp local=NULL, locar=NULL;
if (fath->data == k)
{
return fath;
}
local = fath->left; //为了进入循环
locar = fath->right;
//当不是叶子节点时,说明还可以往下寻找目标节点
while (local != NULL || locar != NULL)
{
local = fath->left;
locar = fath->right;
//一旦找到目标节点就终止循环
if (local != NULL && locar != NULL)
{
if (local->data == k)
{
break;
}
if (locar->data == k)
{
break;
}
}
else if (local == NULL && locar != NULL)
{
if (locar->data == k)
{
break;
}
}
else if (local != NULL && locar == NULL)
{
if (local->data == k)
{
break;
}
}
if (fath->data > k)
{
fath = local;
}
else
{
fath = locar;
}
}
return fath;
}
Bstp delenode(Bstp t) //t为待删除节点 ,函数返回删除后的子树的根节点的首地址
{
Bstp s = NULL, q = NULL; //用作中间变量
if (t->left == NULL && t->right == NULL) //当t为叶子节点时 直接把t的内存释放掉
{
free(t);
return NULL;
}
if (t->left != NULL) //t有左子树
{
if (t->left->right == NULL) //t的左子树的右子树为空
{
q = t->left;
s = q->left;
t->data = q->data;
t->left = s; //将t的左子树的左子树与修改后的t的左子树关联
free(q); //释放内存
return t;
}
else //t的左子树有右子树
{
q = t;
s = t->left;
while (s->right != NULL) //先循环到右子树的末节点
{
q = s;
s = s->right;
}
q->right = s->left; //更新,替换
t->data = s->data;
free(s); //释放内存
return t;
}
}
else if (t->right!=NULL) //思路与前面的一样
{
if (t->right->left == NULL)
{
q = t->right;
s = q->right;
t->data = q->data;
t->right = s;
free(q);
return t;
}
else
{
q = t;
s = t->right;
while (s->left != NULL)
{
q = s;
s = s->left;
}
q->left = s->right;
t->data = s->data;
free(s);
return t;
}
}
}
void Delete_aNum(Bstp x) //删除一个数据函数
{
int k = 0;
Bstp locat=NULL;
Bstp fath = x;
printf("请输入要删除的数据:");
scanf_s("%d", &k);
printf("\n");
if (subFind(x, k)) //目标节点在该二叉树中
{
locat=LocaTar(x, k); //寻找目标节点
fath = LocaFath(x, k); //寻找目标节点的双亲节点
if (fath == locat) //如果目标节点为根节点
x=delenode(locat);
else if (fath->left == locat) //双亲节点的左子树为目标节点
fath->left = delenode(locat);
else //双亲节点的右子树为目标节点
fath->right = delenode(locat);
}
else
{
printf("\n错误!要删除的节点不在该二叉树中!\n\n");
return;
}
}
搜索公众号“24K纯学渣”,回复“二叉树”即可获取完整的VS2017 C-project!