bst
二叉搜索树(Binary Search Tree)可以用来解决数据的查找问题.
链表,队列等线性数据结构可以存储数据 但在数据的查找,排序方面效率不高
二叉搜索树则兼具了数据的存储和查找,能用来解决涉及数据查找的问题
二叉树的原理和实现:
http://blog.csdn.net/qq_21358401/article/details/79329523
二叉搜索树
和之前描述过的二叉树一样:二叉搜索树的左节点的键值小于根节点的键值
右节点的键值大于根节点的键值
二叉搜索树应该具有这几个特性: 1. 插入节点
2. 搜索/删除节点
上一文中描述的二叉树原型已经比较接近二叉搜索树 仅缺少搜索/删除节点的能力.
二叉搜索树的节点:
增加parent节点指向节点的根节点 这是为了删除节点时更改节点的连接关系准备的.
struct tree {
struct tree *parent;
struct tree *left;
struct tree *right;
int index;
};
插入节点:
和普通二叉树类似 大于根节点键值则向右插入 小于根节点键值则向左插入
static inline void sort_tree_insert(struct tree **node,
struct tree *parent, int val) {
if (!(*node)) {
*node = malloc(sizeof(struct tree));
assert((*node) != NULL);
(*node)->parent = parent; // 根节点和子节点建立连接
(*node)->left = NULL;
(*node)->right = NULL;
(*node)->index = val;
return;
}
if (val < (*node)->index) {
sort_tree_insert(&((*node)->left), (*node), val); // 向左插入
} else {
sort_tree_insert(&((*node)->right), (*node), val); // 向右插入
}
return;
}
搜索节点:
返回节点的指针
static inline struct tree* sort_tree_search(struct tree *root, int val) {
if (!root) {
return NULL;
}
if (root->index == val) {
return root;
}
if (val < root->index) {
return sort_tree_search(root->left, val);
} else if (val >= root->index){
return sort_tree_search(root->right, val);
}
}
删除节点
删除节点要考虑多种情况 所以比较复杂 单独列举出来
有这么几种情况:
1. 删除根节点
2. 删除普通节点
删除根节点其实和删除普通节点要考虑的情况一样
但因为删除根节点需要替换根节点 而不是简单的更改连接关系 所以要区别开来处理
删除根节点
1. 根节点没有左右节点
直接返回根节点
2. 根节点只存在左节点
让左节点成为根节点 返回原先的根节点
3. 根节点只存在右节点
让右节点成为根节点 返回原先的根节点
4. 根节点存在左右节点
bst的特性是左节点键值 < 根节点 < 有节点
如果要删除根节点 就要从剩下的节点中选出一个 调整到根节点的位置上来
可以明确的是:一定从左边的节点(包含可能存在的子节点)选取这个调整节点
因为只有这样 才能保持bst的特性
所以左边的节点中的键值最大的节点是寻找的目标
1. 左节点没有右节点
2 像这样 2是根节点 1就是左节点 因为1没有右节点 所以1是左边的节点中最大的
/ \ 将2删除 1翻转到2的位置就形成了新的二叉树
1 4 1
/ / \
0 0 4
2. 左节点存在有节点
3 3是根节点 1就是左节点 1存在右节点 左边节点中最大的明显是2节点
/ \ 将3删除 2翻转到3的位置
1 4 2
/ \ / \
0 2 1 4
/
0
可以看出 这样操作删除后 bst的特性没有被破坏
关于寻找左边子树的最大键值
1. 如果左节点没有右子节点 直接返回左节点
2. 左节点存在右子节点 则递归向右寻找 知道找到叶子节点(根据bst的特性 一定是最大值)
static inline struct tree* sort_tree_find_max_right(struct tree *node) {
if (!node->right)
return node;
sort_tree_find_max_right(node->right);
}
删除普通节点
删除普通节点也要考虑四种情况:
1. 节点没有左右子节点
直接返回这个节点
2. 节点有左节点
把左节点连接到要删除节点的父节点上替代自己的位置
3. 节点有右节点
把右节点连接到要删除节点的父节点上替代自己的位置
4. 节点有左右子节点
和删除根节点时考虑的情况一样 寻找左边方向的最大键值调整替换要删除的节点
参考blog
http://blog.csdn.net/feixiaoxing/article/details/6867460
示例代码
git repo:
https://github.com/sliver-chen/codingutil/tree/master/data_struct/bst