BST调了一天,最后遍历参数错了,没药救了……

本文所有代码均使用数组+结构体,不使用指针!

前言——BST是啥

BST 二叉搜索树是基于二叉树的一种树,一种特殊的二叉树。

二叉搜索树要么是一颗空树,要么满足一下特点(性质)的二叉树:

  1. 它的左子树要么为空,要么它(左子树)的所有节点均小于它的根节点。
  2. 它的右子树要么为空,要么它(右子树)的所有节点均大于它的根节点。
  3. 它的左、右子树也分别是二叉搜索树。

直观的说,如果中序遍历一棵二叉搜索树,则会产生一个有序数列。

如:,中序遍历会产生序列:1 2 5 6 8 9

No.1——算法复杂度分析

二叉搜索树是"排过序"的二叉树,并非"用于排序"的二叉树。

它的优势在于"有序性",而且其插入和查找的时间复杂度均为\(O(h)\),一般情况下\(h=O(\log_{2}n)\),n代表节点数,h代表树的高度。堆的插入算法虽然时间复杂度为\(O(\log_{2}n)\),但并不具有有序性。

No.2——使用范围

对比上述的的分析,发现BST的特点是:

  1. 有序
  2. 插入、查找等算法高效

因此,BST使用范围是:要经常对有序数列进行"动态的"插入或查找等工作

No.3——基本操作

BST的基本操作很多,一时半会也讲不过来,就从易到难的讲吧。

No.3-1——三种遍历方式

BST的遍历与二叉树和树一样,有三种:先序遍历、中序遍历、后续遍历。

三种遍历的方式:

  1. 先序遍历:根→左→右 (DLR)
  2. 中序遍历:左→根→右 (LDR) (结合定义,想一想,为什么中序遍历就是有序的??)
  3. 后续遍历:左→右→根 (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——建树与插入

强烈建议使用父亲孩子表示法!!!

所谓建树,就是构建一颗树,建树的时候必然涉及到插入。

也没有什么好说的,根据定义走,他怎么说,你怎么做。

  1. 第一个为根节点
  2. 比根大,往右对比
  3. 比根小,往左对比
  4. 如果当前为空,插入成功。

就这四步,代码来了

/*========插入========*/
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——删除

本操作有一定难度,请务必弄懂

删除要分一些情况讨论,见下:

  1. 没有孩子
  2. 只有一个孩子

    3-1. 有两个孩子

    3-2. 删除根

第一种情况好办,删掉就行了。

第二种情况也行,删掉后接上左/右孩子。

第三种情况有些复杂,需要用到前驱/后继(用哪个没有一定要求),用它的前驱/后继代替它,同时删除(一个递归过程,又一次调用删除函数)它的前驱/后继。

看一组图吧(有点大):

这是一颗二叉搜索树,我们要删掉3。

找到前驱。

替换。

最后变成这个样子。

最后讲一讲如何删根节点,其实与其他删除差不多,只需在开个ROOT变量存储根是谁就行了(根默认为1)

因为一些原因,不放代码。(其实是我太懒了)

No.4——写在最后

其实个人认为二叉搜索树的实用价值不大,主要用于练手与预备知识,比方说Treap、平衡树、堆……都需要用到二叉搜索树的性质。

综合代码算了,删除你们自己打吧!

No.4-1——练习题

  1. 模板题
  2. [HNOI2002]营业额统计

但,算法之路,才刚刚开始!

二叉搜索树(BST)学习笔记的更多相关文章

  1. 萌新笔记之二叉搜索树(BST)

    前言,以前搞过线段树,二叉树觉得也就那样= =.然后数据结构的课也没怎么听过,然后下周期中考... 本来以为今天英语考完可以好好搞ACM了,然后这个数据结构期中考感觉会丢人,还是好好学习一波. 二叉搜 ...

  2. C++版 - 剑指offer 面试题24:二叉搜索树BST的后序遍历序列(的判断) 题解

    剑指offer 面试题24:二叉搜索树的后序遍历序列(的判断) 题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则返回true.否则返回false.假设输入的数组的任意两个 ...

  3. 给定一个二叉搜索树(BST),找到树中第 K 小的节点

    问题:给定一个二叉搜索树(BST),找到树中第 K 小的节点. 出题人:阿里巴巴出题专家:文景/阿里云 CDN 资深技术专家. 考察点: 1. 基础数据结构的理解和编码能力 2.  递归使用 参考答案 ...

  4. 在二叉搜索树(BST)中查找第K个大的结点之非递归实现

    一个被广泛使用的面试题: 给定一个二叉搜索树,请找出其中的第K个大的结点. PS:我第一次在面试的时候被问到这个问题而且让我直接在白纸上写的时候,直接蒙圈了,因为没有刷题准备,所以就会有伤害.(面完的 ...

  5. 二叉搜索树 (BST) 的创建以及遍历

    二叉搜索树(Binary Search Tree) : 属于二叉树,其中每个节点都含有一个可以比较的键(如需要可以在键上关联值), 且每个节点的键都大于其左子树中的任意节点而小于右子树的任意节点的键. ...

  6. [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 ...

  7. 二叉搜索树(BST)

    (第一段日常扯蛋,大家不要看)这几天就要回家了,osgearth暂时也不想弄了,毕竟不是几天就能弄出来的,所以打算过完年回来再弄.这几天闲着也是闲着,就掏出了之前买的算法导论看了看,把二叉搜索树实现了 ...

  8. hdu 3791:二叉搜索树(数据结构,二叉搜索树 BST)

    二叉搜索树 Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submiss ...

  9. 数据结构---二叉搜索树BST实现

    1. 二叉查找树 二叉查找树(Binary Search Tree),也称为二叉搜索树.有序二叉树(ordered binary tree)或排序二叉树(sorted binary tree),是指一 ...

随机推荐

  1. CSS学习笔记_day7

    目录 1.径向渐变 2. 线性渐变 3. 背景图片裁剪 4. 背景图片大小 5. 边框图片 6. 边框圆角 7. 边框阴影 8.位移 9. 倾斜 10. 旋转 11. 缩放 12. 文本换行 13. ...

  2. Fedora 系统屏幕亮度修改

    在某些笔记本电脑上,屏幕亮度卡在最大值,功能键或桌面设置似乎没有做任何事情. 有一件事要尝试通常可以解决这个问题.打开/ etc / default / grub 并找到以GRUB_CMDLINE_L ...

  3. javascript方法篇-String

    一.String 实例方法(或非静态方法) const str = "Hello World"; toLowerCase();将英文大写字母转换成小些字母.比如: const ne ...

  4. C++实验四

    // 类graph的实现 #include "graph.h" #include <iostream> using namespace std; // 带参数的构造函数 ...

  5. mysql的分表与分区的区别

    http://www.2cto.com/database/201503/380348.html

  6. jquery的相关用法

    选择器基本选择器1.id选择器$('#id1')找到id为id1 的标签2.class选择器$('.class1')找到class中有class1这个类的标签3.标签选择器$('tag') 找到tag ...

  7. js中substr、substring、slice的区别

    substr(start, length) substring(from, to) slice(from, to) 以上函数只传一个参数时,认为是起始位置,然后按照正方向截取 substring的参数 ...

  8. Python之PIL库的运用、GIF处理h

    一.PIL库简介 PIL(Python Image Library)库是Python语言的第三方库,它支持图像存储.显示和处理,它能够处理几乎所有图片格式,可以完成对图像的缩放.剪裁.折叠以及像图片添 ...

  9. Java(原码、反码、补码和计算机存储格式)

    原码:将一个整数,转换成二进制,就是其原码.如单字节的5的原码为:0000 0101:-5的原码为1000 0101. 反码:正数的反码就是其原码:负数的反码是将原码中,除符号位以外,每一位取反.如单 ...

  10. 给jumpserver双机配置glusterfs共享复制卷

    为什么要使用glusterfs呢. 本身Haproxy+Keepalived对jumpserver进行了负载均衡和反向代理.但是真实的视频只会存储在一个节点上 否则播放视频的时候会出现找不到的情况 为 ...