您的位置:首页 > 其它

BST-二叉查找树

2016-08-25 17:17 260 查看
二叉查找树相比AVL和红黑树简单多了,在删除时无需旋转,但树高不平衡,有可能出现树高 = 结点树的情况,本文介绍其C/C++代码实现。

定义

实现
结点

插入

查找

删除

更新

遍历

测试

定义

直接上维基百科,要么是空树要么是符合以下性质的二叉树

任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;

任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;

任意节点的左、右子树也分别为二叉查找树;

没有键值相等的节点。

样例如图



特点是它的插入删除查找的平均复杂度都是O(log n),当节点有序的时候退化成链表O(n)复杂度(树的全部结点都只有左/右子树)

实现

结点

struct node
{
int val;
node *left, *right;
};


插入

插入很简单,根据树的大小关系去左/右定位即可,插入的点一定是新结点/没有子树的。

注意需要返回插入后新树的根节点,不能返回插入点的指针。

// 插入:值不可重复,返回插入后的根节点
node* insert(node *root, int val) {
if (!root) {
root = new node();
root->val = val;
} else if (root->val < val) {
root->right = insert(root->right, val);
} else if (root->val > val) {
root->left = insert(root->left, val);
}
return root;
}


查找

非递归写法会明显快于递归写法,不需要压/弹系统栈,若不存在返回NULL即可。

// 查找:返回具有该值的结点指针
node* find(node *root, int val) {
while (root) {
if (root->val < val) {
root = root->right;
} else if (root->val > val) {
root = root->left;
} else {
return root;
}
}
return NULL;
}


删除

删除分三种情况:

删除点没有儿子(也就是叶子),直接删之。

删除点有一个儿子,若有左儿子则把 将删除点的父结点跟左儿子连起来,右儿子同理。

删除点有左右儿子,我们选一个比删除点次大的点来顶替就行,次大可以是:左子树里的最大(左子树里的最右) 或者 右子树里的最小(右子树里的最左)。

如下图,图中的第三种情况是取右子树里的最小替换删除点,下面代码是取左子树里的最大。图片原地址戳这



实现中我们需要让删除点的父亲指向删除点的儿子,但我们没有父节点指针怎破?可以用递归实现,
root->right = del(root->right, val);
del() 返回删除点的儿子,然后通过上一层去修改指针。

为了更好理解,请戳这个数据结构动态演示链接:

http://www.cs.usfca.edu/~galles/visualization/BST.html

// 删除 返回删除后的根节点
// 情况1:同时有左右儿子,找到左儿子里的最大值,替换上来
// 情况2:有0或1个儿子,有左儿子就让左儿子替换当前节点,有右则右替换,都没有就直接删除
node* del(node *root, int val) {
if (!root) return NULL;

if (root->val < val) {
root->right = del(root->right, val);
} else if (root->val > val) {
root->left = del(root->left, val);
} else {
node *son;
if (root->left && root->right) {  //左右都有,返回左子树里的最右,指针修改由上一层递归处理
son = root->left;
while (son->right) son = son->right;
son->right = root->right;     //避免丢了删除点的右子树
}
else {  //只有一个子树,返回存在的那个子树即可
if (root->left) son = root->left;
else if (root->right) son = root->right;
else son = NULL;    //叶子结点没有子树,返回NULL给一层
}
delete root;        //删除点
return son;
}
return root;
}


更新

由于BST没有像其他树那样的调整操作,所以只能先删后增。

// 更新值:返回新树根节点
node* update(node *root, int oldVal,int newVal) {
root = del(root,oldVal);
root = insert(root,newVal);
return root;
}


遍历

// 中序遍历:得出递增结果
void inOrder(node *root) {
if (!root) return;
inOrder(root->left);
printf("%d ", root->val);
inOrder(root->right);
}


测试

int main() {

node *rt = NULL;
rt = insert(rt, 3);
rt = insert(rt, 5);
rt = insert(rt, 6); rt = insert(rt, 6);
rt = insert(rt, 8);
rt = insert(rt, 4);
rt = insert(rt, 10);

inOrder(rt); printf("\n");

rt = del(rt, 6);
inOrder(rt); printf("\n");

rt = del(rt,3);
inOrder(rt); printf("\n");

rt = update(rt,5,88);
inOrder(rt); printf("\n");

return 0;
}


参考

https://www.topcoder.com/community/data-science/data-science-tutorials/an-introduction-to-binary-search-and-red-black-trees/

http://www.cppblog.com/cxiaojia/archive/2016/02/27/186752.html

推荐两个数据结构演示 地址1 地址2
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: