当前位置: 首页 > wzjs >正文

网站建设浩森宇特百度推广开户渠道

网站建设浩森宇特,百度推广开户渠道,网站内页百度不收录,通州做网站文章目录前言1. 二叉搜索树的概念2. 二叉搜索树的操作及模拟实现2.1 查找2.2 插入2.3 删除3. 二叉搜索树的应用3.1 K模型(Key)3.2 KV模型(Key_Value)4. 二叉搜索树查找的时间复杂度分析前言 本文我们补充二叉树的知识——二叉搜索…

文章目录

    • 前言
    • 1. 二叉搜索树的概念
    • 2. 二叉搜索树的操作及模拟实现
      • 2.1 查找
      • 2.2 插入
      • 2.3 删除
    • 3. 二叉搜索树的应用
      • 3.1 K模型(Key)
      • 3.2 KV模型(Key_Value)
    • 4. 二叉搜索树查找的时间复杂度分析


前言

本文我们补充二叉树的知识——二叉搜索树。在之前学习初阶数据结构时,我们还留下了这部分知识没有讲解,具体原因是由于C语言的限制,会大大增大我们的学习成本,因此,在学会C++后学习会事半功倍。

二叉搜索树我将会分两个阶段来学习:

  • 二叉搜索树的概念和应用,以及模拟实现二叉搜索树(本文内容)
  • 二叉树OJ题(下篇内容)

1. 二叉搜索树的概念

二叉搜索树又称二叉排序树,它可以是一颗空树。
它是具有以下性质的二叉树:
如果树不为空时

  1. 非空左子树的所有节点的值小于其根节点的值。
  2. 非空左子树的所有节点的值小于其根节点的值。
  3. 左右子树都是二叉搜索树
  4. 节点的值都是唯一的,不存在相等值的两个节点

为什么又可以叫二叉排序树呢?
因为二叉搜索树的中序遍历的结果一定是一个升序序列

那么,二叉搜索树应该是链式结构还是顺序结构呢?
其实很容易想到,这棵树需要具备增删的功能,若是顺序结构,每次都得挪动数据,效率太差。
因此,二叉搜索树是链式结构


2. 二叉搜索树的操作及模拟实现

这里操作的实现可以有两种方式:递归和非递归(迭代)。这里我们两者一起实现。

2.1 查找

  1. 从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。
  2. 最多查找高度次,走到到空,还没找到,这个值不存在。

非递归:

bool Find(const K& key)
{Node* cur = _root;while (cur){if (cur->_key > key)//比根小就往左走{cur = cur->_left;}else if (cur->_key < key)//比根大就往右走{cur = cur->_right;}else//与根相等就找到了{return true;}}return false;
}

递归:

bool _FindR(Node* root, const K& key)
{if (root == nullptr){return false;}if (root->_key > key)//比根小了,就在左子树上查找{_FindR(root->_left, key);}else if (root->_key < key)//比根大了,就在右子树上查找{_FindR(root->_right, key);}else{return true;}
}

2.2 插入

插入的具体过程分两种情况:
a. 树为空,则直接新增节点,赋值给root指针
b. 树不空,按二叉搜索树性质查找插入位置,插入新节点

如果有重复的节点,则插入失败,返回false。

非递归:

bool Insert(const K& key)
{Node* cur = _root;Node* parent = nullptr;if (_root == nullptr){_root = new Node(key);return true;}else{//查找插入的位置while (cur){if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{return false;}}//插入cur = new Node(key);if (parent->_key > key){parent->_left = cur;}else{parent->_right = cur;}return true;}
}

递归:

  1. 小于根节点,化子问题为在左子树插入
  2. 大于根节点,化子问题为在右子树插入

设计参数:

bool _InsertR(Node*& root, const K& key)

这里root参数巧用&引用,可以达到效果是:递归的每层root都是同一个,以达到每一层递归都是作用在一颗树上。
后面的删除也是如此。

bool _InsertR(Node*& root, const K& key)
{if (root == nullptr){root = new Node(key);return true;}if (root->_key > key){_InsertR(root->_left, key);}else if (root->_key < key){_InsertR(root->_right, key);}else{return false;}
}

2.3 删除

删除就比较复杂了,情况分为:

  1. 删除的节点没有孩子,也就是叶子节点,直接删即可。
  2. 删除的节点有一个孩子,将这个孩子交给父亲,也就是托孤。注意区分左右孩子。
  3. 删除的节点有两个孩子,替换法,将其与左子树最大的节点或右子树最小的节点进行替换,转换为一个孩子或两个孩子的节点进行删除。
    求法:
    左子树最大节点——左子树的最右节点;
    右子树最小节点——右子树的最左节点。

还有一个很容易疏忽的一个情况:LeftMax存在左孩子的情况
删除8:
在这里插入图片描述
如果替换后直接删除的话,LeftMax的左孩子就丢失了,因此这里需要托孤

if (parent->_left == LeftMax)
{parent->_left = LeftMax->_left;
}
else
{parent->_right = LeftMax->_left;
}

完整代码(非递归):

bool Erase(const K& key)
{Node* cur = _root;Node* parent = nullptr;while (cur){if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{//左为空if (cur->_left == nullptr){if (cur == _root){_root = cur->_left;}else{if (parent->_left == cur){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}}//右为空else if (cur->_right == nullptr){if (cur == _root){_root = cur->_right;}else{if (parent->_right == cur){parent->_right = cur->_right;}else{parent->_left = cur->_right;}}}//左右都不为空else{Node* LeftMax = cur->_left;parent = cur;//找最右节点while (LeftMax->_right){parent = LeftMax;LeftMax = LeftMax->_right;}swap(cur->_key, LeftMax->_key);//处理LeftMax存在左孩子的情况if (parent->_left == LeftMax){parent->_left = LeftMax->_left;}else{parent->_right = LeftMax->_left;}cur = LeftMax;}delete cur;return true;}}return false;
}

递归:

  1. 小于根节点,化子问题为在左子树删除
  2. 大于根节点,化子问题为在右子树删除
  3. 等于根节点,进行删除操作(同上)
    好处是无需控制父节点了,也避免了许多复杂的情况。
bool _EraseR(Node*& root, const K& key)
{if (root == nullptr){return false;}if (root->_key > key){return _EraseR(root->_left, key);}else if (root->_key < key){return _EraseR(root->_right, key);}else{Node* del = root;//左为空if (root->_left == nullptr){root = root->_right;}//右为空else if (root->_right == nullptr){root = root->_left;}//右两个孩子:转化为一个或没有孩子的问题else{Node* LeftMax = root->_left;while (LeftMax->_right){LeftMax = LeftMax->_right;}swap(root->_key, LeftMax->_key);return _EraseR(root->_left, key);}delete del;return true;}
}Node* _root;
};

3. 二叉搜索树的应用

3.1 K模型(Key)

K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。
应用场景案例:
给一个单词word,判断该单词是否拼写正确
具体方式如下:

  1. 以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树
  2. 在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。

3.2 KV模型(Key_Value)

每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。
这种模型在现实生活中更为常见:

  • 英汉词典就是英文与中文的对应关系
    通过英文可以快速找到与其对应的中文,英文单词与其对应的中文<word, chinese>就构成一种键值对;
  • 统计单词次数,统计成功后,给定单词就可快速找到其出现的次数
    单词与其出现次数就是<word, count>就构成一种键值对。

4. 二叉搜索树查找的时间复杂度分析

二叉搜索树的操作都用到了查找
那对于查找,它的时间复杂度是多少呢?

对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在树的深度
但二叉搜索树为完全二叉树时就是最好的情况了,查找的时间复杂度为O(logN)O(logN)O(logN)

但是,时间复杂度计算的最坏情况,并非平均。我们需要寻找极端情况。

极端情况:

在这里插入图片描述
这种趋于线性的二叉搜索树,查找的时间复杂是O(N)O(N)O(N)

那能不能将此类情况优化呢??

有的有的,后继我们将要学习的AVL树、红黑树,它们的最多查找次数就是树的高度次,敬请期待吧!

http://www.dtcms.com/wzjs/73190.html

相关文章:

  • 医院网站管理制度seo1搬到哪里去了
  • 电商网站功能模块图百度关键词排名怎么做
  • 什么网站没人做重庆百度seo
  • 中文wordpress博客模板seo广告投放是什么意思
  • wordpress编辑器换成经典模式班级优化大师简介
  • 学校网站 制作网站提交入口链接
  • 医疗门户网站模板广告推销网站
  • 免费电视剧网站大全在线观看视频号最新动作
  • 新疆网站建设电话网站关键词优化报价
  • 网站建设哪里学域名注册需要什么条件
  • 东莞四网合一网站建设合肥关键词快速排名
  • 外贸网站建设要注意什么股票发行ipo和seo是什么意思
  • 免费下载的网页模板seo推广软件
  • 广州市企业网站建设平台产品市场推广计划书
  • 专做婚礼logo的网站长沙百度快速排名
  • 凡科微传单制作官网seo排名赚app是真的吗
  • 政协网站建设功能微信软文范例大全100
  • 网站没后台怎么修改类容seo网站推广是什么意思
  • 汕尾北京网站建设武汉百度推广seo
  • 全球做的比较好的网站天津天狮网络营销课程
  • 龙华哪有做网站设计上海seo优化服务公司
  • 环保推广哪个网站好有没有免费的推广网站
  • 什么网站做的好郑州网站排名优化外包
  • 一流的网站建设seo技术分享免费咨询
  • 网站系统的运营和维护网络营销方案范文
  • 百度分享wordpress插件seo助力网站转化率提升
  • 兖州中材建设有限公司网站南京seo优化培训
  • 做设计及免费素材网站有哪些广东队对阵广州队
  • wordpress qq登陆南京seo按天计费
  • 网页设计与制作解答题整站优化系统厂家