一、引言
二叉树一般可以用两种结构存储,一种是顺序表,另一种是链表,一般来说,如果是完全二叉树可以采用顺序表储存的方式,但如果不是完全二叉树,就会造成空间的浪费。
因此,我们采用二叉树的链式储存结构。这里介绍二叉链。
二、具体实现
(1)二叉树的结构
typedef int BTDataType;
// 二叉链
typedef struct BinaryTreeNode
{
struct BinTreeNode* left; // 指向当前结点左孩子
struct BinTreeNode* right; // 指向当前结点右孩子
BTDataType data; // 当前结点值域
}BTNode;
这一段程序定义了节点左右孩子的指向和当前节点存储的值,并重命名为BTNode便于后续操作。
(2)二叉树的前序遍历
二叉树的前序遍历代表我们按照“根、左子树、右子树”的顺序进行访问,代码如下:
void BTPrevOrder(BTNode* root)
{
if (root == NULL)
{
printf("N ");
return;
}
printf("%d ", root->data);
BTPrevOrder(root->left);
BTPrevOrder(root->right);
}
我们以一棵二叉树为例,看看是如何进行前序访问的:
(3)二叉树的中序遍历
与前序遍历整体上相差无几,只需要将打印的语句移到中间即可
void BTInOrder(BTNode* root)
{
if (root == NULL)
{
printf("N ");
return;
}
BTInOrder(root->left);
printf("%d ", root->data);
BTInOrder(root->right);
}
(4)二叉树的后序遍历
后序遍历也是如此,将打印语句移到最后即可
void BTPostOrder(BTNode* root)
{
if (root == NULL)
{
printf("N ");
return;
}
BTPostOrder(root->left);
BTPostOrder(root->right);
printf("%d ", root->data);
}
(5)二叉树的创建(前序遍历来创建)
了解了前序遍历后,我们就可以利用这些遍历方法来创建二叉树。我们在键盘中键入字符串例如“1 2 # 8 # # 4 9 # # #”代表我们需要创建的二叉树,其中1 2 4……代表节点的值域,#代表NULL,代码如下:
BTNode* BTCreate(BTDataType* a, int* pi)//二叉树创建
{
if (a[(*pi)] == '#')
{
(*pi)++;
return NULL;
}
BTNode* root = (BTNode*)malloc(sizeof(BTNode));
root->data = a[(*pi)++];
root->left = CreateTree(a, pi);
root->right = CreateTree(a, pi);
return root;
}
(6)二叉树的销毁
在销毁二叉树时,我们一般采用后序销毁的办法,即先销毁左右子树,最后销毁根几点
void BTDestroy(BTNode* root)
{
if (root == NULL)
return;
BTDestroy(root->left);
BTDestroy(root->right);
free(root);
root = NULL;
}
(7)二叉树的叶子个数
在二叉树中,我们想找到二叉树的所有叶子节点,采用递归遍历的方式
int TreeLeaveSize(BTNode* root)
{
if(root == NULL)
return 0;
else if(root->left == NULL && root->right == NULL)
return 1;
return TreeLeaveSize(root->left) + TreeLeaveSize(root->right);
}
(8)二叉树总节点个数
如果该节点不为0,就返回1并继续递归遍历该节点的左子树和右子树
int BTSize(BTNode* root)
{
return root == NULL ? 0 : BTSize(root->left) + BTSize(root->right) + 1;
}
(9)二叉树第k层节点个数
这段程序本质上依旧采用递归的思想,我们都知道,当k为1时,不管何种二叉树(只要不是空二叉树),在这一层永远只有1个根节点,因此通过这种思想,我们在从根节点向下遍历k层时,每经过一层,k就减1,当k=1的时候,返回1。
int BTLevelKSize(BTNode* root, int k)
{
if (root == NULL)
return 0;
else if (k == 1)
return 1;
else
return BTLevelKSize(root->left, k - 1) + BTLevelKSize(root->right, k - 1);
}
(10)二叉树高度
二叉树的高度是取左右子树中高的那一个的高度再加一,同样采用递归的方法
if (root == NULL)
return 0;
int high1 = BTHeight(root->left);
int high2 = BTHeight(root->right);
return (high1 > high2) ? high1 + 1 : high2 + 1;
需要注意的是,在这段程序中我们引入high1,high2变量来储存我们计算的值,否则每次递归时程序都将重新计算上一层的高度,会导致运算量成倍增长
(11)查找值为x的节点
BTNode* BTFind(BTNode* root, BTDataType x)
{
if (root->data = x)
return root;
if (root == NULL)
return NULL;
BTNode* left = BTFind(root->left, x);
if (left)
{
return left;
}
return BTFind(root->right, x);
}
这段程序中,我们先查找左子树,如果没有,再继续查找右子树,直到全部为空,进行返回。