C语言实现二叉树

二叉树: 任意一个节点的度都是小于等于 2 的.

节点定义

可以看到, 一个二叉树节点有三个部分:

1. 存储数据的位置

2. 指向左节点的指针

3. 指向右节点的指针 

typedef int BTDataType;
typedef struct BinaryTreeNode
{
    BTDataType data;    // 用来存储当前节点的值
    struct BinaryTreeNode* leftchild;    // 指向左孩子
    struct BinaryTreeNode* rightchild;   // 指向右孩子
}BTNode;

三种遍历

前序遍历

当前节点: 都先访问自己数据, 然后访问自己的左右子树.

void Order(BTNode* root)
{
	if(root == NULL)
    {
        printf("N ");
        return;
    }
    printf("%d ", root->data);		// 前序
    Order(root->leftchild);
    Order(root->rightchild);
}

中序遍历

当前节点: 在访问自己数据前, 要先确定自己的左子树已经先被访问了,

然后访问自己, 最后访问自己的右子树

void Order(BTNode* root)
{
	if(root == NULL)
    {
        printf("N ");
        return;
    }
    Order(root->leftchild);
    printf("%d ", root->data);	// 中序
    Order(root->rightchild);
}

后序遍历

当前节点: 在访问自己数据时, 要确保自己的左子树已经被访问了,

然后自己的右子树也被访问了, 最后访问自己的数据

void Order(BTNode* root)
{
	if(root == NULL)
    {
        printf("N ");
        return;
    }
    Order(root->leftchild);
    Order(root->rightchild);
    printf("%d ", root->data);	// 后序
}

总结

前序中序后序, 是站在根节点的角度来看的.

前序: 先访问根自己的数据, 再访问左右子树. 根的访问位于最前面

中序: 先访问自己的左子树, 然后访问自己的数据, 最后访问自己的右子树. 根的访问位于中间

后续: 先访问自己的右子树, 然后访问自己的右子树, 最后访问自己的数据. 根的访问位于最后

二叉树接口实现

创建节点

// 创建节点: 传入需要存储的值 x, 创建出节点并返回节点地址
BTNode* CreateNode(BTDataType x)
{
    BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
    assert(newnode);
    newnode->data = x;
    newnode->leftchild = newnode->rightchild = NULL;
}

计算二叉树的节点个数

int BTreeSize(BTNOde* root)
{
    if(root == NULL)
    {
        return 0;
    }
    return BTreeSize(root->left) + BTreeSize(root->right) + 1;
}

树节点个数 = 左子树的节点个数总和 + 右子树节点个数总和 + 1

这个 + 1 就是加上这个树的根

计算二叉树的叶子节点的个数

int BTreeLeafSize(BTNode* root)
{
    if(root->NULL)
    {
		return 0;
    }
    if(root->leftchild == NULL && root->rightchild == NULL)
    {
        return 1;
    }
    return BTreeLeafSize(root->leftright) + BTreeLeafSize(root->rightchild);
}

叶子节点: 左右两个子树都是空

获得二叉树的高度

int BTreeHeight(BTNode* root)
{
    if(root == NULL)
    {
        return 0;
    }
    left = BTreeHeight(root->leftchild);
    right = BTreeHeight(root->rightchild);
    return left > right ? left + 1 : right + 1;
}

return left > right ? left + 1 : right + 1;
// return BTreeHeight(root->leftchild)> BTreeHeight(root->rightchild)? BTreeHeight(root->leftchild)+ 1 : BTreeHeight(root->rightchild)+ 1;

return 语句不建议写成下面那种.

因为在执行完 BTreeHeight(root->leftchild)> BTreeHeight(root->rightchild), 之后因为没有保存结果, 就需要在执行一遍 BTreeHeight(root->leftchild) 和 BTreeHeight(root->rightchild), 这样会导致程序运行效率大大降低

获取二叉树第 k 层的节点个数

int BTreeLevelKSsize(BTNode* root, int k)
{
    assert(k > 0);
    if(root == NULL)
    {
        return 0;
    }
    if(k == 1)
    {
        return 1;
    }
    return BTreeLevelKSsize(root->leftchild, k - 1) + BTreeLevelKSsize(root->rightchild, k - 1);
}

判断二叉树中是否存在某个值

BTNode* BTreeFind(BTNode* root, BTDataType x)
{
    if(root == NULL)
    {
        return NULL;
    }
    if(root->data == x)
    {
        return root;
    }
    BTNode* left = BTreeFind(root->leftchild, x);
    if(left != NULL)    // 当左子树中已经找到了这个值, 后续的查找就不需要了
    {
        return left;
    }
    BTNode* right = BTreeFind(root->rightchild, x);
    if(right != NULL)
    {
        return right;
    }
    return NULL;
}

查找就是遍历, 通过遍历每一个节点, 并比较节点中的内容, 来判断某个值似乎否存在二叉树中

二叉树的销毁

void BTreeDestroy(BTNode* root)
{
    if (root == NULL)
	{
		return;
	}
	Destroy(root->left);
	Destroy(root->right);
	root->left = root->right = NULL;
	free(root);
}

想要删除就需要找到节点: 删除也是遍历, 通过遍历每个节点, 然后销毁这个节点.

一定要先执行两个 Destroy() 递归, 如果先执行 root->left = root->right = NULL;

那么传递给 Destroy() 的参数就是 NULL, 这样后面的节点就不会被销毁,

会照成内存泄漏.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值