前面我们知道了二叉树的相关概念和性质,也了解了二叉树的相关遍历方法,接下来我们来实现一下其他的有关二叉树的相关基本操作。二叉树及其基本操作(一)(C语言递归实现前中后层序遍历)
//求二叉树节点个数
int TreeSize1(TreeNode *root)
{
if(root == NULL)
{
//空树
return 0;
}
//方法1:递归
if(root->lchild == NULL && root->rchild == NULL)
{
//此时的树只有一个根节点
return 1;
}
//此时树的节点不只有根节点
//所以节点个数就等于根节点的个数1加上左子树的节点个数
//再加上右子树的节点个数
return 1 + TreeSize(root->lchild) + TreeSize(root->rchild);
}
//求树的节点个数方法2的辅助函数
void _TreeSize2(TreeNode* root,int* size)
{
if(root == NULL)
{
//空树
return 0;
}
if(root == NULL || *size < 1)
{
return;
}
++(*size);
_TreeSize(root->lchild,size);
_TreeSize(root->rchild,size);
}
int TreeSize2(TreeNode *root)
{
if(root == NULL)
{
//空树
return 0;
}
//方法2:前序遍历,此时的访问相当于计数+1
int size = 0;
size++;
_TreeSize(root->lchild,&size);
_TreeSize(root->rchild,&size);
return size;
}
节点:包括一个数据元素和若干指向其他子树的分支(指针(索引))。
叶子节点:度为0的节点叫做叶子节点,也叫作终端节点。
节点的度:节点所拥有的子树的个数叫做节点的度。
//求叶子节点个数
int TreeLeafSize(TreeNode *root)
{
if(root == NULL)
{
//空树
return 0;
}
if(root->lchild == NULL && root->rchild == NULL)
{
//此时只有一个根节点,该根节点也是一个叶子节点
return 1;
}
//此时不只有一个根节点
//叶子节点的个数等于根节点的左子树的叶子节点的个数
//再加上右子树的叶子节点的个数
return TreeLeafSize(root->lchild) + TreeLeafSize(root->rchild);
}
//求二叉树的第K层节点的个数
//此时我们可以转换为求根节点的左右子树的K-1层的节点个数
//递归调用函数即可得出结论
int TreeKLevelSize(TreeNode *root,int k)
{
if(root == NULL || k < 1)
{
//空树
return 0;
}
if(k == 1)
{
//此时只有一个根节点,节点个数为1
return 1;
}
return TreeKLevelSize(root->lchild,k-1) + TreeKLevelSize(root->rchild,k-1);
}
树的深度:树中所有节点的层次的最大值称为树的深度,也叫做树的高度。
//求树的高度
int TreeHeight(TreeNode *root)
{
if(root == NULL)
{
return 0;
}
if(root->lchild == NULL && root->rchild == NULL)
{
//此时只有一个根节点
return 1;
}
//调用函数本身,递归的求出根节点的左右子树的高度
int lresult = TreeHeight(root->lchild);
int rresult = TreeHeight(root->rchild);
//取较大值返回,即为树的高度
return 1+(lresult > rresult ? lresult : rresult);
}
//查找一个值,返回其指针
TreeNode *TreeFind(TreeNode *root,TreeDataType to_find)
{
if(root == NULL)
{
//空树
return NULL;
}
//以前序遍历的顺序查找
//先判断根节点的值是否为我们要查找的值
if(root->data == to_find)
{
//此时满足条件说明根节点就是我们需要查找的
return root;
}
//再递归的以根节点的左右子树递归的调用该函数
TreeNode *lresult = TreeFind(root->lchild,to_find);
TreeNode *rresult = TreeFind(root->rchild,to_find);
//判断哪一个符合要求,如果lresult不是我们要找的就直接返回rresult,
//即便rresult也为空不是我们要找的值,也直接返回。
//此时返回的就是一个空指针,说明没有找到我们要找的值
return lresult != NULL ? lresult : rresult;
}
//求一个节点的父节点
TreeNode *Parent(TreeNode *root,TreeNode *child)
{
if(root == NULL)
{
//空树
return NULL;
}
//判断根节点是否为其父节点
if(root->lchild == child || root->rchild == child)
{
//此时满足条件说明根节点就是我们需要查找的
return root;
}
//递归的以根节点的左右子树调用该函数
TreeNode *lresult = Parent(root->lchild,child);
TreeNode *rresult = Parent(root->rchild,child);
//判断哪一个符合要求,如果lresult不是我们要找的就直接返回rresult,
//即便rresult也为空不是我们要找的值,也直接返回。
//此时返回的就是一个空指针,说明没有找到我们要找的值
return lresult != NULL ? lresult : rresult;
}
//求一个节点的左孩子
TreeNode *LChild(TreeNode *node)
{
if(node == NULL)
{
return NULL;
}
return node->lchild;
}
//求一个节点的右孩子
TreeNode *RChild(TreeNode *node)
{
if(node == NULL)
{
return NULL;
}
return node->rchild;
}
以下为上面所有函数的测试函数:
void TestNodeNumAndHeight()
{
Test_Header;
//创建一棵树
TreeDataType arr[] = "abd**eg***c*f**";
TreeNode *root = _CreateTree(arr,sizeof(arr)/sizeof(arr[0]),'*');
printf("树的节点个数函数测试:");
int ret0 = TreeSize(root);
printf("expected ret0 = 7,actual ret0 = %d\n",ret0);
printf("树的叶子节点个数函数测试:");
int ret1 = TreeLeafSize(root);
printf("expected ret1 = 3,actual ret1 = %d\n",ret1);
printf("树的第k层节点个数函数测试:");
int ret2 = TreeKLevelSize(root,3);
printf("expected ret2 = 3,actual ret2 = %d\n",ret2);
printf("树的高度函数测试:");
int ret3 = TreeHeight(root);
printf("expected ret3 = 4,actual ret3 = %d\n",ret3);
}
//查找一个值,返回其指针的函数测试
void TestFind()
{
Test_Header;
//创建一棵树
TreeDataType arr[] = "abd**eg***c*f**";
TreeNode *root = _CreateTree(arr,sizeof(arr)/sizeof(arr[0]),'*');
TreeDataType to_find1 = 'b';
TreeDataType to_find2 = 'x';
//查找b(二叉树中有b)
TreeNode *R1 = TreeFind(root,to_find1);
printf("rexpected R1 = %p.actual R1 = %p\n",root->lchild,R1);
//查找x(二叉树中没有x)
TreeNode *R2 = TreeFind(root,to_find2);
printf("rexpected R2 = NULL,actual R2 = %p\n",R2);
}
void TestParentAndLRchild()
{
Test_Header;
TreeNode *a = CreateNode('a');
TreeNode *b = CreateNode('b');
TreeNode *c = CreateNode('c');
TreeNode *d = CreateNode('d');
TreeNode *e = CreateNode('e');
TreeNode *f = CreateNode('f');
TreeNode *g = CreateNode('g');
a->lchild = b;
a->rchild = c;
c->rchild = f;
b->lchild = d;
b->rchild = e;
e->lchild = g;
TreeNode *R1 = Parent(a,e);
printf("rexpected R1 = %p,actual R1 = %p\n",b,R1);
TreeNode *q = CreateNode('q');
TreeNode *R2 = Parent(a,q);
printf("expected R2 = NULL,actual R2 = %p\n",R2);
printf("找到节点的左右孩子函数测试:\n");
TreeNode *R3 = LChild(c);
printf("expected R3 = NULL,actual R3 = %p\n",R3);
TreeNode *R4 = RChild(c);
printf("expected R4 = %p,actual R4 = %p\n",f,R4);
}
测试结果如下图: