//LinkBinTree.h
#ifndef _LINKBINTREE_H_
#define _LINKBINTREE_H_
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
//此处不能使用typedef去"定义"数据的类型,提供一个typedef会传递此数据结构支持多种类型的信息,而创建二叉树节点的函数,却明确指定以固定%x的方式去
//格式化存储输入,这种声明与实现的不一致可能会带来不必要的烦恼
//typedef char Element; 禁止!!!
//二叉树节点类型结构
typedef struct _BinTreeNode
{
char data;
struct _BinTreeNode *leftChild; //左孩子
struct _BinTreeNode *rightChild; //右孩子
}BinTreeNode;
//二叉树管理结构,flag参数用于标记空节点,当数据等于flag的值时,节点为空
typedef struct _BinTree
{
BinTreeNode *root;
char flag;
}BinTree;
//初始化函数,用于初始化二叉树管理变量
void InitBinTree(BinTree *tree, char flag);
//创建函数,以输入字符方式创建
void CreateBinTree_input(BinTree *tree);
//一些方法
//全部节点数
int Count(BinTree tree);
//叶子节点数
int CountOfLeaves(BinTree tree);
//度为2的节点个数
int CountOfN2(BinTree tree);
//第k层节点数,整个树根为第0层(与二叉树性质的公式保持一致)
int CountOfKLevel(BinTree tree, int k);
//树高度
int Height(BinTree tree);
//查找e
BinTreeNode *Search(BinTree tree, char e);
//p的双亲
BinTreeNode *Parent(BinTree tree, BinTreeNode *p);
//树为空
bool BinTreeEmpty(BinTree tree);
//树比较
bool BinTreeCmp(BinTree tree1, BinTree tree2);
//将树tree1拷贝到tree2
void BinTreeCopy(BinTree *tree1, BinTree *tree2);
//摧毁
void BinTreeDestroy(BinTree *tree);
#endif // _LINKBINTREE_H_
//LinkBinTree.c
#include "LinkBinTree.h"
void InitBinTree(BinTree *tree, char flag)
{
tree->root = NULL;
tree->flag = flag;
}
static void Create_1(BinTree *tree, BinTreeNode **node) //创建方式的先序的
{
char item;
if( 1 != scanf("%c", &item) || item == tree->flag ) //如果输入字符与空节点标记值相等,则将节点置NULL并立即返回
{
*node = NULL;
return ;
}
//输入值不为标记,创建节点并创建左右孩子
*node = (BinTreeNode *)malloc(sizeof(BinTreeNode));
if( NULL == *node )
{
*node = NULL;
return ;
}
(*node)->data = item;
Create_1(tree, &(*node)->leftChild);
Create_1(tree, &(*node)->rightChild);
}
static BinTreeNode *Create_2(BinTree *tree)
{
char item;
if( 1 != scanf("%c", &item) || item == tree->flag )
return NULL;
BinTreeNode * p = (BinTreeNode *)malloc(sizeof(BinTreeNode));
if( NULL == p )
return NULL;
p->data = item;
p->leftChild = Create_2(tree);
p->rightChild = Create_2(tree);
return p;
}
void CreateBinTree_input(BinTree *tree)
{
printf("请输入各节点元素,#表示该节点为空节点\n");
Create_1(tree, &(tree->root));
//tree->root = Create_2(tree);
}
//利用递归将问题分解,一个二叉树由一个个子二叉树组成
static int Count_(BinTreeNode *node)
{
if( NULL == node ) //树为空节点数为0
return 0;
return Count_(node->leftChild) + Count_(node->rightChild) + 1; //不为空则是根节点数加上左子树与右子树的节点个数
}
int Count(BinTree tree)
{
return Count_(tree.root);
}
static int CountOfLeaves_(BinTreeNode *node)
{
if( NULL == node )
return 0;
if( NULL == node->leftChild && NULL == node->rightChild ) //根节点为叶子节点
return 1;
return CountOfLeaves_(node->leftChild) + CountOfLeaves_(node->rightChild); //不是叶子节点则叶子节点数为其左右子树叶子结点之和
}
int CountOfLeaves(BinTree tree)
{
return CountOfLeaves_(tree.root);
}
static int CountOfN2_(BinTreeNode *node)
{
if( NULL == node )
return 0;
if( NULL != node->leftChild && NULL != node->rightChild ) //度为2的节点下还可能有度为2的节点,继续查找
return 1 + CountOfN2_(node->leftChild) + CountOfN2_(node->leftChild);
return CountOfN2_(node->leftChild) + CountOfN2_(node->leftChild); //只要有一个以上的子树就可能在其子树存在度为2的节点,继续查找
}
int CountOfN2(BinTree tree)
{
return CountOfN2_(tree.root);
}
/*这个比起其他的递归稍微难理解一些,我是这样理解的
* 从整个二叉树的根开始往下递归,设根为第0层,目标层为k层,位于第0层时,目标层与当前层差k - 0层,到了第1层时,目标层与当前层差了k - 1层,第2层,差了k - 2层
*于是,当差值为0时,即到了目标层,便可统计该层所有不为空的节点数目
*/
static int CountOfKLevel_(BinTreeNode *node, int k)
{
if( NULL == node ) //节点为空不计入数量
return 0;
if( 0 == k ) //到达目标层,且node不是空,对其计1
return 1;
return CountOfKLevel_(node->leftChild, k - 1) + CountOfKLevel_(node->rightChild, k - 1); //往目标层靠近逼近
}
int CountOfKLevel(BinTree tree, int k)
{
return k < 0 ? 0 : CountOfKLevel_(tree.root, k); //非法输入返回0
}
static int Height_(BinTreeNode *node)
{
if( NULL == node )
return 0;
int LHeight = Height_(node->leftChild);
int RHeight = Height_(node->rightChild);
return LHeight > RHeight ? (LHeight + 1) : (RHeight + 1); //二叉树的高度为左右子树中较高者加上根节点的高度
}
int Height(BinTree tree)
{
return Height_(tree.root);
}
static BinTreeNode *Search_(BinTreeNode *node, char e)
{
if( NULL == node )
return NULL;
if( node->data == e ) //找到节点,返回节点
return node;
BinTreeNode *p = Search_(node->leftChild, e); //在左子树中寻找
if( NULL != p ) //找到,无需在右子树中查找
return p;
return Search_(node->rightChild, e);
}
BinTreeNode *Search(BinTree tree, char e)
{
return Search_(tree.root, e);
}
static BinTreeNode *Parent_(BinTreeNode *node, BinTreeNode *p)
{
if( NULL == node || NULL == p )
return NULL;
if( node->leftChild == p || node->rightChild == p )
return node;
BinTreeNode *parent = Parent_(node->leftChild, p); //在左子树中寻找
if( NULL != parent ) //找到,无需在右子树中查找
return parent;
return Parent_(node->rightChild, p);
}
BinTreeNode *Parent(BinTree tree, BinTreeNode *p)
{
return Parent_(tree.root, p);
}
bool BinTreeEmpty(BinTree tree)
{
return NULL == tree.root;
}
static bool BinTreeCmp_(BinTreeNode *node1, BinTreeNode *node2)
{
if( NULL == node1 && NULL == node2 ) //同为空则相等
return true;
if( NULL != node1 && NULL != node2 && node1->data == node2->data ) //都不为空且节点数据域值相等,判断其子树是否相等
return BinTreeCmp_(node1->leftChild, node2->leftChild) && BinTreeCmp_(node1->rightChild, node2->rightChild);
return false; //其余情况不等
}
bool BinTreeCmp(BinTree tree1, BinTree tree2)
{
return BinTreeCmp_(tree1.root, tree2.root);
}
static void BinTreeCopy_(BinTreeNode *node1, BinTreeNode **node2)
{
if( NULL == node1 )
{
*node2 = NULL;
return ;
}
*node2 = (BinTreeNode *)malloc(sizeof(BinTreeNode));
if( NULL == node2 )
return ;
(*node2)->data = node1->data;
BinTreeCopy_(node1->leftChild, &(*node2)->leftChild);
BinTreeCopy_(node1->rightChild, &(*node2)->rightChild);
}
void BinTreeCopy(BinTree *tree1, BinTree *tree2)
{
BinTreeCopy_(tree1->root, &tree2->root);
}
static void BinTreeDestroy_(BinTreeNode **node)
{
if( NULL == *node )
return;
BinTreeDestroy_(&(*node)->leftChild);
BinTreeDestroy_(&(*node)->rightChild);
free(*node);
*node = NULL;
}
void BinTreeDestroy(BinTree *tree)
{
BinTreeDestroy_(&tree->root);
}
//main.c
#include <stdio.h>
#include "LinkBinTree.h"
int main(int argc, char *argv[])
{
BinTree tree;
InitBinTree(&tree, '#');
CreateBinTree_input(&tree);
printf("二叉树的节点个数为 %d\n", Count(tree));
printf("叶子节点个数为 %d\n", CountOfLeaves(tree));
printf("度为2的节点个数为 %d\n", CountOfN2(tree));
printf("第k层的节点个数为 %d\n", CountOfKLevel(tree, 1));
printf("第k层的节点个数为 %d\n", CountOfKLevel(tree, 2));
printf("树的高度为 %d\n", Height(tree));
BinTreeNode *p = Search(tree, 'G');
if( NULL != p )
printf("查找的节点的值为 %c\n", p->data);
BinTreeNode *parent = Parent(tree, p);
if( NULL != parent )
printf("父节点的值为 %c\n", parent->data);
BinTreeEmpty(tree) ? printf("树是空的\n") : printf("树不是空的\n");
BinTree tree2;
BinTreeCopy(&tree, &tree2);
BinTreeCmp(tree, tree2) ? printf("树相等\n") : printf("树不等\n");
BinTreeDestroy(&tree2);
BinTreeDestroy(&tree);
return 0;
}