摘选自百度百科的解释:
在计算机科学中,二叉树是每个结点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用于实现二叉查找树和二叉堆。
个人理解:
二叉树算是相对较难的一个槛,一般的实现方式为,当前节点 大于左子树的节点,小于右子树的节点。由于其特性,在查找的时候有则较快的效率。
我尽量在代码中进行了大量的注释,自己画图理解会更快一点。
代码实现,以 int 整型为元素进行 示例
#include<stdio.h>
#include<stdlib.h>
/*
\ brief 二叉树节点声明
*/
typedef struct TreeNode
{
int element; // 元素
struct TreeNode* leftChild; // 左子树
struct TreeNode* rightChild; // 右子树
}TreeNode,* TreeNodePtr;
/*
\ brief 清空整颗二叉树
\ param 节点指针
*/
void makeEmpty(const TreeNodePtr node)
{
// 如果节点为NULL
if (!node)
{
return;
}
// 删除当前节点的左子树
makeEmpty(node->leftChild);
// 删除当前节点的右子树
makeEmpty(node->rightChild);
// 释放当前节点
free(node);
}
/*
\ brief 通过值查找指定节点
\ param value 要找的值
\ param node 节点指针
\ return 成功返回节点,失败返回NULL
*/
TreeNodePtr findNode(const int value, TreeNodePtr node)
{
// 如果当前节点为NULL
if (!node)
{
return NULL;
}
// 如果要查找的值 小于 当前节点
if (value < node->element)
{
// 尾递归 查找左子树
return findNode(value, node->leftChild);
}
// 如果要查找的值 大于 当前节点
if (value > node->element)
{
// 尾递归 查找右子树
return findNode(value, node->rightChild);
}
// 等于当前节点,返回当前节点
return node;
}
/*
\ brief 查找二叉树最小节点
\ param 节点指针
\ return 返回二叉树中最小节点
*/
TreeNodePtr findMin(TreeNodePtr node)
{
// 如果当前节点为NULL
if (!node)
{
return NULL;
}
// 如果当前节点的左子树为NULL,说明这个已经是最小节点
if (!node->leftChild)
{
// 返回当前节点
return node;
}
// 尾递归 左子树
return findMin(node->leftChild);
}
/*
\ brief 查找二叉树最大节点
\ param 节点指针
\ return 返回二叉树最大节点
*/
TreeNodePtr findMax(TreeNodePtr node)
{
// 如果当前节点为NULL
if (!node)
{
return NULL;
}
// 如果当前节点的右子树为NULL,说明这个已经是最大节点
if (!node->rightChild)
{
return node;
}
// 尾递归右子树
return findMax(node->rightChild);
}
/*
\ brief 插入节点
\ param element 要插入的元素
\ param node 节点指针
\ return 返回节点指针
*/
TreeNodePtr insert(const int element, TreeNodePtr node)
{
// 如果当前节点为NULL
if (!node)
{
// 分配内存
node = (TreeNodePtr)malloc(sizeof(TreeNode));
// 将值赋值给 新节点
node->element = element;
// 将新节点的左子树 和 右子树 置空
node->leftChild = NULL;
node->rightChild = NULL;
}
// 如果要插入的元素 比当前节点的元素要小
else if (element < node->element)
{
// 往左边插入,当前节点的左子树可能会更新 ps : 这里有点绕,不好解释,只能意会一下。
node->leftChild = insert(element, node->leftChild);
}
// 如果要插入的元素 比当前节点的元素要大
else if (element > node->element)
{
// 往右边插入,当前节点的左子树可能会更新 ps : 这里有点绕,不好解释,只能意会一下。
node->rightChild = insert(element, node->rightChild);
}
// 既然不大于也不小于,节点元素已存在,返回当前节点即可,不需要做更新。
return node;
}
/*
\ brief 擦除一个节点
\ param element 要擦除的元素
\ param node 节点指针
\ return 返回节点指针
*/
TreeNodePtr eraseNode(const int element, TreeNodePtr node)
{
// 分配一个临时节点
TreeNodePtr tempNode;
// 如果当前节点为NULL
if (!node)
{
// 返回NULL
return NULL;
}
// 如果要擦除的元素比当前元素要小
if (element < node->element)
{
// 递归左子树进行擦除
node->leftChild = eraseNode(element, node->leftChild);
}
// 如果要擦除的元素比当前元素要大
else if (element > node->element)
{
// 递归右子树进行擦除
node->rightChild = eraseNode(element, node->rightChild);
}
// 如果要擦除的元素就是当前元素,那么判断 当前节点的左子树 和 右子树 是否都不为NULL
else if (node->leftChild && node->rightChild)
{
// ps : 左右 子树都不为NULL的时候,一般从 右子树中寻找最小的节点,与 当前节点交换值,
// 然后在删除右子树中最小的节点。
// 获取 当前节点的 右子树最小的元素节点
tempNode = findMin(node->rightChild);
// 将右子树最小的元素的值 赋值给当前节点
node->element = tempNode->element;
// 擦除 右子树中最小的元素
node->rightChild = eraseNode(tempNode->element, node->rightChild);
}
else
{
// ps : 执行到这里 那么说明 要删除的节点就是当前节点,而且左子树或者右子树
// 必定有一个是为NULL,或者两个都为NULL
// 保存当前节点到临时节点变量中
tempNode = node;
// 如果左子不为空
if (node->leftChild)
{
//当前节点 赋值为 左子树节点
node = node->leftChild;
}
else
{
// 否则当前节点赋值为右子树节点
node = node->rightChild;
}
// 释放当前节点
free(tempNode);
}
// 返回新的当前节点
return node;
}
/*
\ brief 求树高
\ param 节点指针
*/
size_t treeHight(TreeNodePtr node)
{
// 如果当前节点为NULL
if (!node)
{
// 返回当前节点的树高为 0
return 0;
}
// 求出 左子树的树高
size_t leftHight = treeHight(node->leftChild);
// 求出右子树的树高
size_t rightHight = treeHight(node->rightChild);
// 返回当前节点的高度
return (leftHight > rightHight ? leftHight: rightHight) + 1;
}
/*
\ brief 中序遍历二叉树
\ param 节点指针
*/
void forEach(TreeNodePtr node)
{
if (!node)
{
return NULL;
}
forEach(node->leftChild);
printf("%d\n", node->element);
forEach(node->rightChild);
}
int main(int argc, char* argv[])
{
TreeNodePtr tree = insert(6, NULL);
insert(78, tree);
insert(45, tree);
insert(26, tree);
insert(10, tree);
insert(166, tree);
forEach(tree);
printf(" hight = %u", treeHight(tree));
makeEmpty(tree);
return 0;
}
文章时间 2019年12月4日11:00:26