二叉查找树的原理及实现
前言
学习了一些数据结构之后,你是不是已经有些小得意了,以为数据结构就这点东西嘛,不就用好栈、队列什么什么的就好,呵呵,那些只是皮毛。接下来的东西才会让你真正认识到数据结构的博大精深,当你看到接下来那些酷炫狂赛的操作时,你会惊叹于数据结构的神奇。在学习那些酷炫的AVL树,红黑树之前,我们先入个门,学习最简单的动态查找表——二叉查找树。
二叉查找树
二叉查找树有被称为二叉排序树,它要么是个空树,要么就满足下列条件:
- 若左子树不空,则左子树中所有元素的值比根节点小
- 若右子树不空,则左子树中所有元素的值比根节点大
- 二叉查找树的左右子树都是二叉查找树(疯狂暗示递归实现)
如图,便是一个二叉查找树
基本实现
存储实现:
二叉查找树就使用链表实现,这样能够很好的理解,每个节点有一个元素存储值,两个指针分别指向它的左子树和右子树。
template<class elemType>
class binarySearchTree
{
private:struct node{elemType data;node *left;node *right;node(const elemType &d, node *ln = NULL, node *rn = NULL):data(d), left(ln), right(rn){}};node *root;
}
find函数实现:
查找操作从根节点开始,一个一个节点递归查找。对于一个特定节点,就四个步骤:
- 如果该节点是NULL,那么说明已经查找完了整个树,还没有找到。
- 若该节点的值与要找的值吻合,那么找到,退出
- 若要找的值大于该节点的值,查找它的右子树节点
- 若要找的值小于该节点的值,查找它的左子树节点
elemType *find(const elemType &x){return find(x, root);}elemType *find(const elemType &x, node *t){if(t == NULL){cout << "Can not find" << endl;return 0;}if(t -> data == x){return &(t -> data);}if(x < t -> data){return find(x, t -> left);}else{return find(x, t -> right);}}
midOrder操作:
中序遍历输出整个树的值,细心的人其实已经从二叉查找树做小右大的性质想到了,二叉查找树中序遍历的结果必然是一个从小到大序列啊。
void midOrder(){midOrder(root);}void midOrder(node *p){if(p == NULL){return;}midOrder(p -> left);cout << p -> data << ' ';midOrder(p -> right);}
insert操作:
insert操作插入的一定是叶节点
记住这一点,插入的时候一个一个比较就好,从根节点开始,大就向右,小就向左,直到最后的NULL,在NULL处插入节点就好。
void insert(const elemType &x){insert(x, root);}void insert(const elemType &x, node *&t){if(t == NULL){t = new node(x, NULL, NULL);}else{if(x < t -> data){insert(x, t -> left);}else{if(x == t -> data){cout << "The node has existed" << endl;return;}else{insert(x, t -> right);}}}}
remove操作:
remove操作是二叉查找树中最难的,但你也不要害怕,毕竟你都已经看到这儿了对吧,不看完怎么行。
想想remove其实就分三种情况:
- remove的节点是叶节点,那么二话不说直接删了就好
- remove的节点有一个左子树或者有一个右子树,那么直接把这个节点删去,它的子树补上来就好
- remove的节点有左子树右子树都有,这就比较麻烦了,是不是已经蒙圈了,不知道怎么补了,不要慌,且待我慢慢给你讲解:删除了这个节点,这个位置又不能空着,所以我们按正常人的思维就找了个替身来填补这个位置,那么怎样选择这个替身才能保证树仍保持有序呢?静下心来想想,要想保持有序,那必须补上来左子树的最大值或是右子树的最小值啊,其实就是中序遍历的该值的相邻两个值是吧。
找左子树的最大值,其实就是从左子树的根节点开始,一直往右找,直到末端,那末端的值必然是左子树的最大值了,同理,找右子树的最小值,其实就是从右子树的根节点开始,一直往左找,直到末端,那末端的值必然是右子树的最小值了。(代码以找右子树的最小值为例写的)
找到了替身,使要删节点的值改为替身的值,然后删掉替身就好(有没有一种恩将仇报的赶脚),这里的删掉替身的操作一定是满足前两种操作的。
void remove(const elemType &x){remove(x, root);}void remove(const elemType &x, node *&t){//注意这里是指针的引用,不是复制构造,因为要满 //足补上来子树与上面的节点能够接上if(t == NULL){return;}if(x < t -> data){remove(x, t -> left);}else{if(x > t -> data){remove(x, t -> right);}else{ //==if(t -> left != NULL && t -> right != NULL){node *tmp = t -> right;while(tmp -> left != NULL){tmp = tmp -> left;}t -> data = tmp -> data;remove(t -> data, t -> right);}else{node *old = t;if(t -> left == NULL && t -> right == NULL){delete old;}else{if(t -> left!= NULL){t = t -> left;}else{t = t -> right;}delete old;}}}}}
完整代码:
#include <iostream>using namespace std;template<class elemType>
class binarySearchTree
{
private:struct node{elemType data;node *left;node *right;node(const elemType &d, node *ln = NULL, node *rn = NULL):data(d), left(ln), right(rn){}};node *root;public:binarySearchTree(){root = NULL;}~binarySearchTree(){clear(root);}void clear(node *t){if(t == NULL){return;}clear(t -> left);clear(t -> right);delete t;}elemType *find(const elemType &x){return find(x, root);}elemType *find(const elemType &x, node *t){if(t == NULL){cout << "Can not find" << endl;return 0;}if(t -> data == x){cout << "haha" << endl;return &(t -> data);}if(x < t -> data){return find(x, t -> left);}else{return find(x, t -> right);}}void insert(const elemType &x){insert(x, root);}void insert(const elemType &x, node *&t){if(t == NULL){t = new node(x, NULL, NULL);}else{if(x < t -> data){insert(x, t -> left);}else{if(x == t -> data){cout << "The node has existed" << endl;return;}else{insert(x, t -> right);}}}}void remove(const elemType &x){remove(x, root);}void remove(const elemType &x, node *&t){if(t == NULL){return;}if(x < t -> data){remove(x, t -> left);}else{if(x > t -> data){remove(x, t -> right);}else{ //==if(t -> left != NULL && t -> right != NULL){node *tmp = t -> right;while(tmp -> left != NULL){tmp = tmp -> left;}t -> data = tmp -> data;remove(t -> data, t -> right);}else{node *old = t;if(t -> left == NULL && t -> right == NULL){delete old;}else{if(t -> left!= NULL){t = t -> left;}else{t = t -> right;}delete old;}}}}}void midOrder(){midOrder(root);}void midOrder(node *p){if(p == NULL){return;}midOrder(p -> left);cout << p -> data << ' ';midOrder(p -> right);}};
总结
二叉查找树性能与结构有很大关系,如果构建的好,也就是二叉查找树接近于一棵完全二叉树,那么其所有操作都是O(logn)的,但如果数据很变态,刚好形成了一条链,那就是线性O(n)了。
不过总归是有办法解决的,那就是传说中的AVL树和红黑树,之后会慢慢讲到。
二叉查找树的原理及实现相关推荐
- 数据结构与算法--二叉查找树实现原理
二叉查找树 二叉树的一个重要应用就是他在查询中的使用,假设书中每个节点存储一项数据.在我们的案例中,任意复杂的项在java中都容易处理,但为了简单还是假设都是整数.还假设他们都是不重复的整数,使二叉树 ...
- 5.什么是二叉查找树?原理
二叉查找树:又叫二叉搜索树.二叉排序树.它或是一颗空树,如果不是空树,它的左子树不为空,它的左子树上的任何节点都小于根节点.它的右子树不为空,则它的右子树所有的节点均大于根节点.并且左子树和右子树均为 ...
- 数据结构与算法--二叉查找树转顺序排列双向链表
二叉查找树转顺序排列双向链表 题目:输入一颗二叉查找树,将二叉查找树转成一个排序的双向链表,要求不能创建任何新节点,只调整树节点中指针的指向.例如下图所示: 本次二叉查找树节点定义使用之前文章 数据结 ...
- 数据结构与算法--面试必问AVL树原理及实现
数据结构与算法–AVL树原理及实现 AVL(Adelson-Velskii 和landis)树是带有平衡条件的二叉查找树,这个平衡条件必须容易实现,并且保证树的深度必须是O(logN).因此我们让一棵 ...
- 3分钟火速手写一个二叉查找树,搞快点。
文章目录 定义 实现 完整代码 测试 问题 因为二叉查找树的原理和实现比较简单,所以我们简单了解一下最基本的概念,就直接开始写代码. 定义 二叉查找树(Binary Search Tree,BST), ...
- 数据结构与算法--死磕二叉树
死磕二叉树 近一年都比较关注算法相关的知识,也刷了不少题,之前的文章中大多也是算法相关的文章,但是感觉每次遇到树相关的题型都不能应对自如,因此还是有必要在相关知识上下功夫,因此有此次总结,以下是所有树 ...
- 数据结构与算法--力扣109题将有序双向链表转换为二叉搜索树
将有序数组转换为二叉搜索树 近一年都比较关注算法相关的知识,也刷了不少题,之前的文章中大多也是算法相关的文章,但是感觉每次遇到树相关的题型都不能应对自如,因此还是有必要在相关知识上下功夫,因此有此次总 ...
- 数据结构与算法--力扣108题将有序数组转换为二叉搜索树
力扣108提将有序数组转换为二叉搜索树 近一年都比较关注算法相关的知识,也刷了不少题,之前的文章中大多也是算法相关的文章,但是感觉每次遇到树相关的题型都不能应对自如,因此还是有必要在相关知识上下功夫, ...
- 数据结构与算法--求1~n能组成的所有二叉搜索树的排列
给定一个整数n,生成并返回所有N个节点组成并且节点值从1到n互不相同的不同二叉树,可以按照任意顺序 二叉树文章列表: 数据结构与算法–面试必问AVL树原理及实现 数据结构与算法–二叉树的深度问题 数据 ...
最新文章
- 深入理解 Java 虚拟机(第二弹) - 常用 vm 参数分析
- MQCache 秒开缓存快速入门指南 - 旁路(使用镜像交换机)
- ural 1014. Product of Digits
- UA MATH565C 随机微分方程VI 扩散过程简介
- linux添加怎么退出,linux – 是否可以设置’expect’的退出代码
- R中统计假设检验总结(一)
- hadoop版本升级到2.4.1
- Qt4_用QPainter绘图
- w7电脑蓝屏怎么解决_电脑蓝屏Win32k.sys怎么办
- BZOJ4003 [JLOI2015]城池攻占 左偏树 可并堆
- SQL Sever — 建表语句,设置种子数量与增量以及设置主键 代码
- struts2拦截器
- CacheCloud-资源归档
- 2019莆田学院c语言试卷,莆田学院C语言程序设计模拟试卷_文库吧
- Emacs footnote 自动排序
- 那些中了500万的人过上想要的生活了吗
- 计算机内存不足黑屏怎么办,win10内存不足会黑屏吗_win10电脑内存不足黑屏了怎么办...
- 网络协议 -- IP地址
- 学习笔记 JavaScript 动画 加速
- 网络视频无法快进无法选中进度条