浅谈BST

前言

最近不顺心的事情有点多,再加上赶ptaL2 的题单,很久没做知识总结了 ,现在pta的题目告一段落,参考了某大佬 (某卷王) 总结的知识点,鸣谢大佬!总结一下BST问题的知识点,供以后参考。
封面:

站在巨人 (卷王) 的肩上,才能看 (卷) 的更远

二叉搜索树的性质

一棵二叉搜索树可被递归地定义为具有下列性质的二叉树:对于任一结点

  • 其左子树中所有结点的键值小于该结点的键值;
  • 其右子树中所有结点的键值大于等于该结点的键值;
  • 其左右子树都是二叉搜索树。

乍一看,其实感觉和二叉堆很像,不过二叉堆左右儿子之间没有可比性,因为二叉堆是根据与父亲节点大小关系建堆的,兄弟节点似乎无法比较,所以同一个序列,以不同顺序输入的生成的二叉堆序列也自然不同。
二叉搜索树也有类似的性质,但是二叉搜索树输入的节点不会发生位置交替,这和二叉堆边插入边排序不同,所以,同一组数字不同顺序输入二叉搜索树也会导致二叉搜索树结构不同。假如输入的数字过于玄学,会导致树的左右子树不平衡,如果将两个子树平衡,就变成了平衡树(Treap)

二叉搜索树的操作

必要的初始化
#define maxn 100000
#define INF -1
int BST[maxn];
int main()
{ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);for (int i = 0; i < maxn; i++)BST[i] = INF;
}
建树
void build(int root, int x)
{if (BST[root] == INF){BST[root] = x;return;}if (BST[root] >= x)     //说明该节点应该在其左边build(root * 2, x); //左儿子比父亲小,右儿子更大elsebuild(root * 2 + 1, x); //右儿子比父亲大,往右边放
}
前序遍历
void pre_order(int root)
{if (BST[root] == INF)return;cout << BST[root] << " ";pre_order(root * 2);pre_order(root * 2 + 1);
}
中序遍历

中序遍历其实就是序列从小到大排序

void in_order(int root)
{if (BST[root] == INF)return;in_order(root * 2);cout << BST[root] << " ";in_order(root * 2 + 1);
}
后序遍历
void post_order(int root)
{if (BST[root] == INF)return;post_order(root * 2);post_order(root * 2 + 1);cout << BST[root] << " ";
}
找最大
int get_max(int root) //一直往右走
{if (BST[root * 2 + 1] == INF)return BST[root];elsereturn get_max(root * 2 + 1);
}
找最小
int get_min(int root) //一直往左走
{if (BST[root * 2] == INF)return BST[root];elsereturn get_min(root * 2);
}
删除节点
void modify(int root, int x) //删除操作
{if (x > BST[root]) //往右找modify(root * 2 + 1, x);else if (x < BST[root]) //往左找modify(root * 2, x);else //找到了,开始修改{if (BST[2 * root] == INF && BST[root * 2 + 1] == INF){BST[root] = INF; //没有儿子,直接封杀}else if (BST[2 * root] == INF && BST[root * 2 + 1] != INF) //左子树存在,右子树无{BST[root] = BST[root * 2 + 1];modify(root * 2 + 1, BST[root * 2 + 1]);}else if (BST[2 * root] != INF && BST[root * 2 + 1] == INF) //左子树空,右子树存在{BST[root] = BST[root * 2];modify(root * 2, BST[root * 2]);}else if (BST[root * 2] != INF && BST[root * 2 + 1] != INF){//有两种修改方式!//第一种是修改用后驱节点(右子树最小节点更换)//第二种是用前驱节点修改(左子树最大节点更换)//这里演示前者int post_point = get_min(root * 2 + 1);BST[root] = post_point;modify(root * 2 + 1, post_point);}}
}

汇总代码,实弹演习

样例
7
8 10 11 8 6 7 5
#include <bits/stdc++.h>
using namespace std;
#define maxn 100000
#define INF -1int BST[maxn];
void build(int root, int x)
{if (BST[root] == INF){BST[root] = x;return;}if (BST[root] >= x)     //说明该节点应该在其左边build(root * 2, x); //左儿子比父亲小,右儿子更大elsebuild(root * 2 + 1, x); //右儿子比父亲大,往右边放
}
void pre_order(int root)
{if (BST[root] == INF)return;cout << BST[root] << " ";pre_order(root * 2);pre_order(root * 2 + 1);
}
void in_order(int root)
{if (BST[root] == INF)return;in_order(root * 2);cout << BST[root] << " ";in_order(root * 2 + 1);
}
void post_order(int root)
{if (BST[root] == INF)return;post_order(root * 2);post_order(root * 2 + 1);cout << BST[root] << " ";
}
void floor_order(int root)
{queue<int> q;q.push(root);while (q.empty() == false){int fa = q.front();cout << BST[fa] << " ";q.pop();if (BST[fa * 2] != INF)q.push(fa * 2);if (BST[fa * 2 + 1] != INF)q.push(fa * 2 + 1);}
}
int get_min(int root) //一直往左走
{if (BST[root * 2] == INF)return BST[root];elsereturn get_min(root * 2);
}
int get_max(int root) //一直往右走
{if (BST[root * 2 + 1] == INF)return BST[root];elsereturn get_max(root * 2 + 1);
}
int search(int now, int x) //查找某一个特殊的元素
{if (x > BST[now])return search(now * 2 + 1, x);else if (x < BST[now])return search(now * 2, x);elsereturn now;
}
void modify(int root, int x) //删除操作
{if (x > BST[root]) //往右找modify(root * 2 + 1, x);else if (x < BST[root]) //往左找modify(root * 2, x);else //找到了,开始修改{if (BST[2 * root] == INF && BST[root * 2 + 1] == INF){BST[root] = INF; //没有儿子,直接封杀}else if (BST[2 * root] == INF && BST[root * 2 + 1] != INF) //左子树存在,右子树无{BST[root] = BST[root * 2 + 1];modify(root * 2 + 1, BST[root * 2 + 1]);}else if (BST[2 * root] != INF && BST[root * 2 + 1] == INF) //左子树空,右子树存在{BST[root] = BST[root * 2];modify(root * 2, BST[root * 2]);}else if (BST[root * 2] != INF && BST[root * 2 + 1] != INF){//有两种修改方式!//第一种是修改用后驱节点(右子树最小节点更换)//第二种是用前驱节点修改(左子树最大节点更换)//这里演示前者int post_point = get_min(root * 2 + 1);BST[root] = post_point;modify(root * 2 + 1, post_point);}}
}
int main()
{ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);for (int i = 0; i < maxn; i++)BST[i] = -1;int n;cin >> n;for (int i = 1; i <= n; i++){int remp;cin >> remp;build(1, remp);}pre_order(1);cout << endl;post_order(1);cout << endl;in_order(1);cout << endl;cout << get_max(1) << endl;cout << get_min(1) << endl;modify(1, 8);in_order(1);cout << endl;return 0;
}

运行结果

插一道题


这道题我是参考LP大佬的解法,鸣谢大佬!解法很巧妙,我们看题,它题目告诉我们它输入的序列有可能是正常的二叉搜索树,也可能是镜像的,那咋办捏?
判断两遍就可以了!先用当正常的遍历一下,试试水,如果成了就直接pass,不成了的话就用镜像的方式遍历一次
那么,我们怎么判断一个遍历是不是一个二叉搜索树捏?
以正常的为例子!
看图!


字有点丑不好意思我的锅
它生成的前序遍历应该是:

你会发现:对一段前序遍历,第一个元素是根节点,蓝色箭头之前到根节点都是小于根节点的!而绿色箭头都是大于根节点的!
而这两个箭头指的也是根节点的左右子树!
所以直接按这个规律进行判断!判断成功,就判断它的子树是否满足!

AC代码

#include <bits/stdc++.h>
using namespace std;
#define maxn 100000
vector<int> ans;
int pre[maxn];
void judge1(int start, int end) //判断是否是正序
{                               // start是根节点if (start > end)return;int node1 = start + 1;int node2 = end;while (node1 <= end && pre[node1] < pre[start])node1++; //从前往后寻找比根节点小的最后一个值while (node2 > start && pre[node2] >= pre[start])node2--; //从后往前寻找比根节点大的最后一个值node1--; //多加了node2++; //多减了// cout<<node1<<" "<<node2<<endl;if (node2 != node1 + 1) //只有两个指针中间只差一个(根节点)return;judge1(start + 1, node1);  //验证左子树judge1(node2, end);         //查右子树ans.push_back(pre[start]); //后序遍历,最后放入
}
void judge2(int start, int end) //判断是否是镜像
{if (start > end)return;int node1 = start + 1;int node2 = end;while (node1 <= end && pre[node1] >= pre[start])node1++;while (node2 >= start && pre[node2] < pre[start])node2--;node1--;node2++;if (node2 != node1 + 1)return;judge2(start + 1, node1);judge2(node2, end);ans.push_back(pre[start]);
}
int main()
{int num;scanf("%d", &num);for (int i = 1; i <= num; i++){scanf("%d", &pre[i]);}judge1(1, num);         //先正序构造一下,试一下水if (ans.size() != num) //试水失败,说明可能是镜像,再试一次水{ans.clear();judge2(1, num);}if (ans.size() == num){printf("YES\n");for (int i = 0; i < num; i++){printf("%d", ans[i]);if (i != num - 1)printf(" ");}}else{printf("NO\n");}return 0;
}

浅谈二叉搜索树(BST)相关推荐

  1. 【数据结构与算法】3.二叉搜索树(BST)、c++代码

    二叉搜索树(BST).c++代码 参考 https://blog.csdn.net/c_living/article/details/81021510

  2. 看动画学算法之:二叉搜索树BST

    文章目录 简介 BST的基本性质 BST的构建 BST的搜索 BST的插入 BST的删除 看动画学算法之:二叉搜索树BST 简介 树是类似于链表的数据结构,和链表的线性结构不同的是,树是具有层次结构的 ...

  3. 阿里开发者招聘节 | 面试题02-04:给定一个二叉搜索树(BST),找到树中第K小的节点

    为帮助开发者们提升面试技能.有机会入职阿里,云栖社区特别制作了这个专辑--阿里巴巴资深技术专家们结合多年的工作.面试经验总结提炼而成的面试真题这一次将陆续放出(面试题官方参考答案将在专辑结束后统一汇总 ...

  4. 二叉搜索树 (BST)

    二叉搜索树 (BST : Binary Search Tree) 又名 二叉查找树 或 二叉排序树. 二叉搜索树: 左孩子的值 一定小于或等于 父结点的值 二叉搜索树: 右孩子的值 一定大于或等于 父 ...

  5. 二叉搜索树BST的学习

    文章目录 二叉搜索树BST 什么是BST? 用BST做什么? 一.BST的特性 BST的特性是什么? 1.[230. 二叉搜索树中第K小的元素](https://leetcode.cn/problem ...

  6. 真c++ 从二叉树到红黑树(3)之二叉搜索树BST

      此文章为从二叉树到红黑树系列文章的第三节,主要介绍介绍二叉搜索树BST,为AVL和RedBlack打下基础 文章目录 一.前面文章链接~(点击右边波浪线可以返回目录) 二.二叉搜索树BST的定义~ ...

  7. 二叉搜索树(BST的理论剖析+代码实现)

    二叉搜索树(BST树) 文章目录 二叉搜索树(BST树) 1.二叉搜索树的概念 2.二叉搜索树的结构定义 2.1 二叉搜索树结点模板的定义 2.2 二叉搜索树类模板的定义 3.二叉搜索树的效率 4.二 ...

  8. 五.树,二叉树,二叉搜索树(BST)和自平衡二叉搜索树(AVL)

    1.树 树是一种数据结构 比如:目录结构 树是一种可以递归定义的数据结构 树是由n个节点组成的集合: 如果 n=0, 那这是一颗空树 如果 n>0, 那存在1个节点作为树的根节点,其他节点可以分 ...

  9. 二叉搜索树BST红黑树

    二叉搜索树基础知识 提起红黑树咱们肯定要先说说这个二叉搜索树(BST) 二叉搜索树又叫二叉查找树,二叉排序树:它具有以下特点: 如果它的左子树不为空,则左子树上结点的值都小于根结点. 如果它的右子树不 ...

最新文章

  1. Pytorch(七) --加载数据集
  2. Trade off between bias and variance
  3. java面向对象内存分析
  4. 【SQL数据库】查询语句练习题
  5. SpringAop+Mybatis 实现动态切换数据库操作
  6. OpenWrt加入iptables 支持过滤字符串
  7. 华为服务器系统启动项,服务器设置开机启动项
  8. 输入法辅助工具:自动切换输入法 for Mac
  9. (xsinx)/(1+(cosx)^2)在0到π上的定积分
  10. 2008下搭建easypanel(康乐)虚拟主机控制面板
  11. 结合Zemax浅谈几何光学和信息光学中的成像,孔径光阑,视场光阑
  12. 提示非标准语法;请使用 ““ 来创建指向成员的指针
  13. LR录制https协议报证书错误,导航已阻止
  14. 商业银行vh是哪个银行的简称_各个银行缩写是什么
  15. 用Android studio设计贺卡,功能强大的贺卡设计制作软件推荐:Hallmark Card Studio
  16. Python OpenCV 写入视频
  17. 追根溯源之最好的Spring AOP解析
  18. 即时通讯,1 天快速集成 支持单群聊、聊天室、系统通知等通信能力,安全可靠、 全球互通
  19. 【Unity3D】Unity3D 软件安装 ( 注册账号并下载 Unity Hub | 安装 Unity Hub | 获取个人版授权 | 中文环境设置 | 安装 Unity3D 编辑器 )
  20. Javad 方法,方法的重载,递归,类,类的构造方法

热门文章

  1. 欧几里得算法和扩展欧几里得算法——杨子曰数学
  2. VAO 与 VBO 的前世今生
  3. MySQL DBA的修炼与未来,看看老司机们怎么说?
  4. 关于Zoom连不了,明明别人可以连接,却提示会议号不存在
  5. 6款相见恨晚的资源网站,每个都百里挑一,送给正需要的你!
  6. A题 序号互换(进制转换)
  7. selenium - web 自动化测试
  8. 数据库常用增删改查sql语句(二)
  9. Linux--用history查看历史命令如何在history命令时,查看历史命令执行时间
  10. vim 单行删除与多行删除