二叉搜索树(BST)学习笔记
BST调了一天,最后遍历参数错了,没药救了……
本文所有代码均使用数组+结构体,不使用指针!
前言——BST是啥
BST 二叉搜索树是基于二叉树的一种树,一种特殊的二叉树。
二叉搜索树要么是一颗空树,要么满足一下特点(性质)的二叉树:
- 它的左子树要么为空,要么它(左子树)的所有节点均小于它的根节点。
- 它的右子树要么为空,要么它(右子树)的所有节点均大于它的根节点。
- 它的左、右子树也分别是二叉搜索树。
直观的说,如果中序遍历一棵二叉搜索树,则会产生一个有序数列。
如:,中序遍历会产生序列:1 2 5 6 8 9
No.1——算法复杂度分析
二叉搜索树是"排过序"的二叉树,并非"用于排序"的二叉树。
它的优势在于"有序性",而且其插入和查找的时间复杂度均为\(O(h)\),一般情况下\(h=O(\log_{2}n)\),n代表节点数,h代表树的高度。堆的插入算法虽然时间复杂度为\(O(\log_{2}n)\),但并不具有有序性。
No.2——使用范围
对比上述的的分析,发现BST的特点是:
- 有序
- 插入、查找等算法高效
因此,BST使用范围是:要经常对有序数列进行"动态的"插入或查找等工作。
No.3——基本操作
BST的基本操作很多,一时半会也讲不过来,就从易到难的讲吧。
No.3-1——三种遍历方式
BST的遍历与二叉树和树一样,有三种:先序遍历、中序遍历、后续遍历。
三种遍历的方式:
- 先序遍历:根→左→右 (DLR)
- 中序遍历:左→根→右 (LDR) (结合定义,想一想,为什么中序遍历就是有序的??)
- 后续遍历:左→右→根 (LRD)
想必大家都知道了吧,上代码。
/*========遍历========*/
void bl(int how,int now)
{
if(how==1){ //先序遍历
cout<<a[now].data<<" ";
if(a[now].l!=-1)
bl(1,a[now].l);
if(a[now].r!=-1)
bl(1,a[now].r);
}
if(how==2){ //中序遍历
if(a[now].l!=-1)
bl(2,a[now].l);
cout<<a[now].data<<" ";
if(a[now].r!=-1)
bl(2,a[now].r);
}
if(how==3){ //后续遍历
if(a[now].l!=-1)
bl(3,a[now].l);
if(a[now].r!=-1)
bl(3,a[now].r);
cout<<a[now].data<<" ";
}
}
No.3-2——建树与插入
强烈建议使用父亲孩子表示法!!!
所谓建树,就是构建一颗树,建树的时候必然涉及到插入。
也没有什么好说的,根据定义走,他怎么说,你怎么做。
- 第一个为根节点
- 比根大,往右对比
- 比根小,往左对比
- 如果当前为空,插入成功。
就这四步,代码来了
/*========插入========*/
void into(int sum,int now,int tot)
{
if(sum<a[now].data)
if(a[now].l!=-1)
into(sum,a[now].l,tot);
else {
a[now].l=tot;
a[a[now].l].data=sum;
a[a[now].l].fa=now;
}
else if(sum>a[now].data)
if(a[now].r!=-1)
into(sum,a[now].r,tot);
else {
a[now].r=tot;
a[a[now].r].data=sum;
a[a[now].r].fa=now;
}
}
/*========构建========*/
void init()
{
cin>>n;
int x,tot;
for(tot=1;tot<=n;tot++){
scanf("%d",&x);
if(tot==1)
a[tot].data=x;
else
into(x,1,tot);
}
}
No.3-3——查找
查找也是二叉搜索树必不可少的一个操作,我这里find()
返回了是第几个数,方便删除。
实现很简单,只用熟练掌握二叉搜索树的性质,便可轻易打出以下代码:
/*========查找========*/
int find(int now,int sum)
{
cout<<now<<endl;
if(a[now].data==sum) return now;
if(sum<a[now].data)
if(a[now].l!=-1) return find(a[now].l,sum);
else return 0;
else if(sum>a[now].data)
if(a[now].r!=-1) return find(a[now].r,sum);
else return 0;
}
void init2()
{
cin>>n;
int i,x;
for(i=1;i<=n;i++){
cin>>x;
if(find(ROOT,x)) printf("Yes\n");
else printf("No\n");
}
}
No.3-4——求前驱后继
前驱后继就是在中序遍历时他的前一个与后一个,如图:
如图,八的前驱是六,后继是九。
这太简单了!
放到树上说,前驱就是该节点左儿子的最右节点,后继则是该节点右儿子的最左节点。
放一个前驱的代码,后继自己推!
/*========前驱========*/
int pred(int now)
{
if(a[now].r!=-1) return pred(a[now].r);
else return now;
}
No.3-5——删除
本操作有一定难度,请务必弄懂
删除要分一些情况讨论,见下:
- 没有孩子
- 只有一个孩子
3-1. 有两个孩子
3-2. 删除根
第一种情况好办,删掉就行了。
第二种情况也行,删掉后接上左/右孩子。
第三种情况有些复杂,需要用到前驱/后继(用哪个没有一定要求),用它的前驱/后继代替它,同时删除(一个递归过程,又一次调用删除函数)它的前驱/后继。
看一组图吧(有点大):
这是一颗二叉搜索树,我们要删掉3。
找到前驱。
替换。
最后变成这个样子。
最后讲一讲如何删根节点,其实与其他删除差不多,只需在开个ROOT
变量存储根是谁就行了(根默认为1)
因为一些原因,不放代码。(其实是我太懒了)
No.4——写在最后
其实个人认为二叉搜索树的实用价值不大,主要用于练手与预备知识,比方说Treap、平衡树、堆……都需要用到二叉搜索树的性质。
综合代码算了,删除你们自己打吧!
No.4-1——练习题
但,算法之路,才刚刚开始!
二叉搜索树(BST)学习笔记的更多相关文章
- 萌新笔记之二叉搜索树(BST)
前言,以前搞过线段树,二叉树觉得也就那样= =.然后数据结构的课也没怎么听过,然后下周期中考... 本来以为今天英语考完可以好好搞ACM了,然后这个数据结构期中考感觉会丢人,还是好好学习一波. 二叉搜 ...
- C++版 - 剑指offer 面试题24:二叉搜索树BST的后序遍历序列(的判断) 题解
剑指offer 面试题24:二叉搜索树的后序遍历序列(的判断) 题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则返回true.否则返回false.假设输入的数组的任意两个 ...
- 给定一个二叉搜索树(BST),找到树中第 K 小的节点
问题:给定一个二叉搜索树(BST),找到树中第 K 小的节点. 出题人:阿里巴巴出题专家:文景/阿里云 CDN 资深技术专家. 考察点: 1. 基础数据结构的理解和编码能力 2. 递归使用 参考答案 ...
- 在二叉搜索树(BST)中查找第K个大的结点之非递归实现
一个被广泛使用的面试题: 给定一个二叉搜索树,请找出其中的第K个大的结点. PS:我第一次在面试的时候被问到这个问题而且让我直接在白纸上写的时候,直接蒙圈了,因为没有刷题准备,所以就会有伤害.(面完的 ...
- 二叉搜索树 (BST) 的创建以及遍历
二叉搜索树(Binary Search Tree) : 属于二叉树,其中每个节点都含有一个可以比较的键(如需要可以在键上关联值), 且每个节点的键都大于其左子树中的任意节点而小于右子树的任意节点的键. ...
- [LeetCode] Convert BST to Greater Tree 将二叉搜索树BST转为较大树
Given a Binary Search Tree (BST), convert it to a Greater Tree such that every key of the original B ...
- 二叉搜索树(BST)
(第一段日常扯蛋,大家不要看)这几天就要回家了,osgearth暂时也不想弄了,毕竟不是几天就能弄出来的,所以打算过完年回来再弄.这几天闲着也是闲着,就掏出了之前买的算法导论看了看,把二叉搜索树实现了 ...
- hdu 3791:二叉搜索树(数据结构,二叉搜索树 BST)
二叉搜索树 Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) Total Submiss ...
- 数据结构---二叉搜索树BST实现
1. 二叉查找树 二叉查找树(Binary Search Tree),也称为二叉搜索树.有序二叉树(ordered binary tree)或排序二叉树(sorted binary tree),是指一 ...
随机推荐
- redis的LRU算法(一)
最近加班比较累,完全不想写作了.. 刚看到一篇有趣的文章,是redis的作者antirez对redis的LRU算法的回顾.LRU算法是Least Recently Used的意思,将最近最少使用的资源 ...
- D1 java概述
首先扯点别的.在学习知识的过程中非常重要的一点是沟通交流,拿自学java来说绝不是抱着一本Head First Java闷头看.感觉自学入门这一阶段相当于启蒙,绝不能向无头苍蝇一样到处乱撞.java的 ...
- pip install -r requirements.txt
生成文件 pip freeze > requirements.txt pip install --help Usage: pip install [options] <requiremen ...
- CF867E: Buy Low Sell High(贪心, STL) (hdu6438)
Description 有nn个城市,第ii个城市商品价格为aiai,从11城市出发依次经过这nn个城市到达n n城市,在每个城市可以把手头商品出售也可以至多买一个商品,问最大收益. Input 第 ...
- 搭建opencv javaweb项目
搭建opencv javaweb项目 用到的技术maven.git.ssm.opencv.javaweb 搭建opencv javaweb项目时,踩了很多坑:怀疑过spring,想过python,最后 ...
- 注意C语言 / 要想得到精确结果
#include <stdio.h> int main(){ double r; while(scanf("%lf",&r)!=EOF) { ...
- scrapy基本使用
Scrapy笔记 安装scrapy框架 安装scrapy: 通过pip install scrapy 如果是在Windows上面,还需要安装pypiwin32,如果不安装,那么以后运行scrapy项目 ...
- PTA2
一.题目:7-1 币值转换 (20 分) 输入一个整数(位数不超过9位)代表一个人民币值(单位为元),请转换成财务要求的大写中文格式.如23108元,转换后变成“贰万叁仟壹百零捌”元.为了简化输出,用 ...
- 学习笔记CB007:分词、命名实体识别、词性标注、句法分析树
中文分词把文本切分成词语,还可以反过来,把该拼一起的词再拼到一起,找到命名实体. 概率图模型条件随机场适用观测值条件下决定随机变量有有限个取值情况.给定观察序列X,某个特定标记序列Y概率,指数函数 e ...
- Python 限制线程的最大数量(Semaphore)
import threadingimport time sem = threading.Semaphore(4) # 限制线程的最大数量为4个 def gothread(): with sem: # ...