树的定义
BST的实现
通用头文件 fatal.h
#include <stdio.h>
#include <stdlib.h>
#define Error( Str ) FatalError( Str )
#define FatalError( Str ) fprintf( stderr, "%s\n", Str ), exit( 1 )
声明头文件 tree.h
typedef int ElementType;
#ifndef _Tree_H
#define _Tree_H
struct TreeNode;
typedef struct TreeNode *Position;
typedef struct TreeNode *SearchTree;
SearchTree MakeEmpty(SearchTree);
Position Find(ElementType X, SearchTree T);
Position FindMin(SearchTree T);
Position FindMax(SearchTree T);
SearchTree Insert(ElementType X, SearchTree T);
SearchTree Delete(ElementType X, SearchTree T);
ElementType Retrieve(Position P);
#endif
实现头文件 tree.c
#include "tree.h"
#include <stdlib.h>
#include "fatal.h"
struct TreeNode
{
ElementType Element;
SearchTree Left;
SearchTree Right;
};
SearchTree
MakeEmpty(SearchTree T)
{
if (T != NULL)
{
MakeEmpty(T->Left);
MakeEmpty(T->Right);
free(T);
}
return NULL;
}
Position
Find(ElementType X, SearchTree T)
{
if (T == NULL)
return NULL;
if (X < T->Element)
return Find(X, T->Left);
else if (X > T->Element)
return Find(X, T->Right);
else
return T;
}
Position
FindMin(SearchTree T)
{
if (T == NULL)
return NULL;
else if (T->Left == NULL)
return T;
else
return FindMin(T->Left);
}
Position
FindMax(SearchTree T)
{
if (T != NULL)
while (T->Right != NULL)
T = T->Right;
return T;
}
SearchTree
Insert(ElementType X, SearchTree T)
{
// 插入新的节点
if (T == NULL)
{
T = malloc(sizeof(struct TreeNode));
if (T == NULL)
FatalError("Out of space!!!");
else
{
T->Element = X;
T->Left = T->Right = NULL;
}
}
else if (X < T->Element)
{
T->Left = Insert(X, T->Left);
}
else if (X > T->Element)
{
T->Right = Insert(X, T->Right);
}
// 需要返回当前节点 因为是递归调用的
return T;
}
SearchTree
Delete(ElementType X, SearchTree T)
{
Position TmpCell;
if (T == NULL)
Error("Element not found");
else if (X < T->Element)
T->Left = Delete(X, T->Left);
else if (X > T->Element)
T->Right = Delete(X, T->Right);
else if (T->Left && T->Right)
{
// 左右子节点都有的情况复杂一些 我们需要先找到原先准备删除的节点的右子节点的最小子节点,然后把它的元素值赋值给这个节点,然后去这个递归调用Delete去删除这个右节点的最小子节点,而这个子节点是不满足同时有左右子节点条件的,这样子就进入了下面的else情况,就通过递归调用解决了
TmpCell = FindMin(T->Right);
T->Element = TmpCell->Element;
T->Right = Delete(T->Element, T->Right);
}
else
{
// 删除一个只有左节点或者只有右子节点的情况 比较简单 用对应的右节点/左节点替代即可 保持全树的整体有序性
TmpCell = T;
if (T->Left == NULL)
T = T->Right;
else if (T->Right == NULL)
T = T->Left;
free(TmpCell);
}
return T;
}
ElementType
Retrieve(Position P)
{
return P->Element;
}
测试代码 testtree.c
#include "tree.h"
#include <stdio.h>
main()
{
SearchTree T;
Position P;
int i;
int j = 0;
T = MakeEmpty(NULL);
for (i = 0; i < 50; i++, j = (j + 7) % 50)
{
T = Insert(j, T);
}
for (i = 0; i < 50; i++)
if ((P = Find(i, T)) == NULL || Retrieve(P) != i)
printf("Error at %d\n", i);
for (i = 0; i < 50; i += 2)
T = Delete(i, T);
for (i = 1; i < 50; i += 2)
if ((P = Find(i, T)) == NULL || Retrieve(P) != i)
printf("Error at %d\n", i);
for (i = 0; i < 50; i += 2)
if ((P = Find(i, T)) != NULL)
printf("Error at %d\n", i);
printf("Min is %d, Max is %d\n", Retrieve(FindMin(T)),
Retrieve(FindMax(T)));
return 0;
}
测试输出
Min is 1, Max is 49
BST实战
leetcode 1373题 给你一棵以 root 为根的 二叉树 ,请你返回 任意 二叉搜索子树的最大键值和。
二叉搜索树的定义如下:
任意节点的左子树中的键值都 小于 此节点的键值。 任意节点的右子树中的键值都 大于 此节点的键值。 任意节点的左子树和右子树都是二叉搜索树。
示例 1:
输入:root = [1,4,3,2,4,2,5,null,null,null,null,null,null,4,6] 输出:20
解释:键值为 3 的子树是和最大的二叉搜索树。
示例 2:
输入:root = [4,3,null,1,2]
输出:2
解释:键值为 2 的单节点子树是和最大的二叉搜索树。
示例 3:
输入:root = [-4,-2,-5]
输出:0
解释:所有节点键值都为负数,和最大的二叉搜索树为空。
示例 4:
输入:root = [2,1,3]
输出:6
示例 5:
输入:root = [5,4,8,3,null,6,3]
输出:7
提示:
每棵树最多有 40000 个节点。 每个节点的键值在 [-4 * 10^4 , 4 * 10^4] 之间。
代码:
int max_val = 0;
int is_valid_tree(struct TreeNode* root, int *val)
{
/* 0:sum, 1:max_val, 2:min_val */
int l_value[3] = {0, INT_MIN, INT_MAX};
int r_value[3] = {0, INT_MIN, INT_MAX};
int ret_l, ret_r;
if (!root) {
return 1;
}
ret_l = is_valid_tree(root->left, l_value);
ret_r = is_valid_tree(root->right, r_value);
// 左右子树都是二叉搜索树 且当前节点满足 大于左边最大节点 小于右边最小节点
if (!ret_l || !ret_r || root->val <= l_value[1] || root->val >= r_value[2])
return 0;
// 答案只出现在叶子节点 以及所有的子二叉搜索树中
val[0] += root->val + l_value[0] + r_value[0];
val[1] = root->right ? r_value[1] : root->val;
val[2] = root->left ? l_value[2] : root->val;
if (max_val < val[0])
max_val = val[0];
return 1;
}
int maxSumBST(struct TreeNode* root){
int val[3] = {0, INT_MIN, INT_MAX};
max_val = 0;
is_valid_tree(root, val);
return max_val;
}
参考资料 《数据结构与算法分析: C语言描述》