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

wordpress判断首页怎么优化一个网站

wordpress判断首页,怎么优化一个网站,推荐几个的网站,信阳专业做网站公司文章目录 搜索二叉树的概念1.1 主要功能:查找1.2 功能:排序1.3 时间复杂度 二、搜索二叉树的各种实现2.1 基本框架2.2 插入2.3 查找2.3.1 中序遍历递归:2.3.2 查找 2.4 删除(记得将删除的结点进行销毁) 三、key的搜索场…

文章目录

  • 搜索二叉树的概念
    • 1.1 主要功能:查找
    • 1.2 功能:排序
    • 1.3 时间复杂度
  • 二、搜索二叉树的各种实现
    • 2.1 基本框架
    • 2.2 插入
    • 2.3 查找
      • 2.3.1 中序遍历
      • 递归:
      • 2.3.2 查找
    • 2.4 删除(记得将删除的结点进行销毁)
  • 三、key的搜索场景
  • 四、key/value搜索场景

搜索二叉树的概念

二叉搜索树又称之为二叉排序树,它或是一个空树,或是一个具备以下特点的二叉树:

简单来说:就是左比根的值小,右比根的值大。一直这样延续下去。

1.若它的左子树不为空,那么它的左子树上所有的值都是小于等于根节点的值

2.若它的右子树不为空,那么它的右子树上所有的值都是大于等于根节点的值

3.它的左右子树也是一个二叉搜索树;

4.二叉搜索树既支持插入相同的值(允许冗余)又支持插入不同的值(不允许冗余,这根据使用的场景来决定,我们后面学习的map/multimap/set/multiset等系列容器就是以二叉搜索树为底层实现的,其中map/set是不支持插入相同的值的,multimap/multiset是支持插入相同的值的。
在这里插入图片描述

1.1 主要功能:查找

在这里插入图片描述

搜索二叉树的主要功能是:查找某个值。它搜索的比较快,只需要查找部分结构,不需要将整个都搜索。(怎么查找呢?想搜索x,从根结点开始,若x大于根结点的值,往右继续遍历;若x小于根结点的值,往左遍历…循环往复,最终找到x值/到最后一个值也没找到)

与二分查找的功能比较相似,但是比二分查找更好一点。

二分查找的缺点:1. 要求数组中的所有元素都必须是有序的(这样才可以进行二分查找)
2. 底层结构必须是数组,但这样会使得在头部/中部插入数据效率很低(需要移动数据)。(二分查找是通过下标去查找的,不断缩小区间)

1.2 功能:排序

它又叫做:二叉排序树,它还有排升序的功能。从它的结构可以看出
在这里插入图片描述
如果想排升序,那也就是小中大,也就是中序遍历了。对搜索二叉树进行中序遍历,即可得到升序的有序序列

1.3 时间复杂度

时间复杂度需要看它的最优时间复杂度以及最差时间复杂度。当二叉搜索树是类似一个完全二叉树时,在学习数据结构的时候说过,完全二叉树搜索查找某个值的时间复杂度(和层数有关)是O(log2N);当二叉搜索树是一个单支树时,我们在里面查找某个值的时间复杂度(和个数有关,因为是单只树)就是O(N)综合来看,它增删查的时间复杂度是O(N)。虽说不是特别的好,但是它也不差。
在这里插入图片描述

之后学习的AVL树和红黑树这两棵树均是由搜索二叉树变形而来的。

二、搜索二叉树的各种实现

2.1 基本框架

我们需要一点一点实现:二叉树我们使用struct结构体实现。二叉树是由一个一个的结点由指针链接起来的,我们先创建结点的结构体。再把结点使用在二叉树的结构体里面。

结点结构体:

  1. 在创建结构体的时候,基本都会使用类模板,因为我们无法确定数据的类型
  2. 在创建的时候,可以将结点的构造函数也实现,这样以后在实现二叉搜索树时,直接可以new一个树结点了(调用结点类的构造函数)
  3. 为什么需要我们自己写构造函数,却不需要自己写析构呢
    如果不显式地将 _left_right 设为 nullptr,那么这两个指针可能保留垃圾值,进而引发不可预料的行为
template<class K>
struct BSNode
{K k;BSNode<K>* _left;BSNode<K>* _right;BSNode(const K& key):k(key),_left(nullptr),_right(nullptr){}
};

搜索二叉树终究也是一个容器,我们暂时不得知元素类型,所以也是用模板

template<class K>
struct BSTree
{typedef BSNode<K> Node;
private:
//成员变量一般私有Node* _root=nullptr;//vs里面编译器默认生成的构造函数,对于指针类型并不会初始化为空,需要我们显示进行初始化
};

2.2 插入

我们将那些二叉搜索树的基本接口定义实现在其public公有成员中

  1. 如果根结点为空,代表整棵二叉树都是空的,那直接new一个新结点,赋值给根结点即可
  2. 如果不为空:则按照逻辑,值比根大,往右走,小的话往左走
  3. 在最后一步:不仅要将这个值放在合适的位置,还需要和父结点有链接(即:你是人家的左还是右,需要进行判断)

插入的原则:找到一个合适的空位置,将值放在那里

以插入5为例:
在这里插入图片描述

bool Insert(const K& key)
{if (_root == nullptr){_root = new Node(k);return true;  //返回成功(函数的类型是bool)}Node* parent = nullptr;  //总是在cur的上一级,用于最后一步的链接Node* cur = _root;while (cur)  //用循环找到合适的位置{if (key < cur->k)   {parent = cur;  //确保parent在cur的上一层,最终可以找到父结点cur = cur->_left;}else if (key > cur->k)  //说明合适位置在以cur为根的这棵树的右侧。{parent = cur;cur = cur->_right;}else {return false;}}//出循环代表着已经找到合适的位置了,只差赋值以及链接cur = new Node(key);if (key < parent->k){parent->_left = cur;}elseparent->_right = cur;return true;
}

2.3 查找

2.3.1 中序遍历

递归:

(不冗余的情况)

void _InOrder(Node* root)
{if (root == nullptr)return;_InOrder(root->_left);cout << root->k << " ";_InOrder(root->right);
}

这个是搜索二叉树的中序遍历的代码,但是这个是有问题的。我们的成员变量Node* _root是私有的,它在类里面可以随意用,但是不可以在类外面用。我们现在写的这个函数,是放在类里面的,它可以传参_root,但是在外面调用这个函数的时候,如何传参呢,_root是私有的,在外面无法传递这个参数。

解决办法:在类里面封装一个InOrder,在这个函数里调用_InOrder(在类里面调用还可以成功传参),并且在类外面使用这个函数的时候都不用传参,对使用者十分友好。
数里面写递归,一般都会封装(因为根是私有的)
(冗余的情况)
这个是,不影响中序遍历的结果(根据下面的例子自己进行中序遍历看看结果)(要保持逻辑一致性(开始就明确好,如果遇到相等的值就一直往左走或一直往右走,不要一会往左走一会往右走)。)
在这里插入图片描述

2.3.2 查找

  1. 从根开始比较,查找x,若x比根的值大,则往右边走继续查找,若x比根值小,则往左边走继续查找。

  2. 最多查找高度次,若走到空,还是没有找到的话,就说明这个值是不存在的。

  3. 如果不支持插入相等的值的话(不允许冗余),找到x即可返回

  4. 支持插入相同的值时,当插入值与当前结点的值相同时,我们可以向左走也可以向右走,找到空位置后插入新结点,但是我们要保持逻辑一致性(开始就明确好,如果遇到相等的值就一直往左走或一直往右走,不要一会往左走一会往右走)。

尽量:可以不适用递归,就不使用递归

bool Find(const K& key)
{Node* cur = _root;while (cur) //cur不为空的情况下{if (key > cur->k)cur = cur->_right;else if (key < cur->k)cur = cur->_left;else if (key == cur->k)return true;}return false;
}

2.4 删除(记得将删除的结点进行销毁)

情况比较繁多:如果直接删除的话,后续的结点怎么办?

  1. 如果删除的结点没有孩子结点,直接将其删除,将该结点的parent指向空。

  2. 如果删除的结点有一个孩子结点:将该结点删除,再将该结点的父亲指向孩子。
    可以将前两种情况合并,如果准备删除的结点的左孩子为空,那就将父亲指向删除节点的右孩子(如果是没有孩子结点的情况,那右也是nullptr,那父亲指向它即可;如果是一个结点的情况,那父亲指向右孩子即可);如果左不为空,那就有可能准备删除结点的右孩子为空,那将父亲指向左孩子即可。还有可能左右都不为空,继续往下看。是父亲的左还是右指向它们呢?取决于当时的情况
    在这里插入图片描述

  3. 如果删除的结点有两个孩子结点:(该将它指向谁呢?)这个时候不适合将它指向其中一个,因为另一个孩子没办法处理。使用替换法

从左子树/右子树中找到一个合适的值哪个值算合适呢?就是替换(即将被删除的结点的值),放在删除的位置,是符合二叉搜索树的性质的,就是左子树的每个值都小于(该子树的根结点的值),或者,右子树的每个值都小于(该子树的根结点的值)】,(用左子树的max或者右子树的min)和删除结点进行交换,使被删除的结点处于,前面两个案例的位置,便于删除。

左子树的max:位于左子树的最右边(因为大的值总是方右边)
右子树的min:位于右子树的最左边(因为小的值总是放左边)

那什么是合适的值呢?
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在考虑删除之前,需要先‘根据值’‘找到它的位置’(利用循环)

在这里插入图片描述

	bool Erase(const K& key){BSNode<int>* parent = nullptr;BSNode<int>* cur = _root;while (cur){if (key > cur->k){parent = cur;cur = cur->_right;}else if (key < cur->k){parent = cur;cur = cur->_left;}else{//进入这个循环,则说明已经找到值为x的位置if (cur->_left == nullptr) //cur的左为空,要么cur的两个孩子都为空,要么左空,右不空{if (parent->_left == cur)parent->_left = cur->_right;else if (parent->_right == cur)parent->_right = cur->_right;delete cur;}else if (cur->_right == nullptr)  //到这里说明左不为空,所以进入这个if说明左不空,右空{//到这里说明cur的左不为空,但右为空if (parent->_left == cur)parent->_left = cur->_left;elseparent->_right = cur->_left;delete cur;}else{//到这里说明cur的左右孩子都不为空(开始找替换)//用循环找到合适的值,但不能让cur进入循环,否则就找不到删除的值了,所以用新的值进入循环BSNode<int>* recur = cur; BSNode<int>* reparent = parent;//以(寻找左子树的max)为例while (recur->_right){reparent = recur;recur = recur->_right;}//将cur的值替换cur->k = recur->k;//删除recurif (reparent->_left == recur)reparent->_left = recur->_left;elsereparent->_right = recur->_left;//再将recur释放delete recur;}return true;}}return false;}

但是有一个bug,如果删除的结点是根结点,以上代码是可以完成的。但是,如果是单支树(这里假设根结点没有左子树,只有单支的右子树),我们删除根结点的话
在这里插入图片描述

进行修改:

在这里插入图片描述

bool Erase(const K& key)
{BSNode<int>* parent = nullptr;BSNode<int>* cur = _root;while (cur){if (key > cur->k){parent = cur;cur = cur->_right;}else if (key < cur->k){parent = cur;cur = cur->_left;}else{//进入这个循环,则说明已经找到值为x的位置if (cur->_left == nullptr) //cur的左为空,要么cur的两个孩子都为空,要么左空,右不空{//还需要注意:单支树(只有右)if (cur == _root){_root = cur->_right;}else{if (parent->_left == cur)parent->_left = cur->_right;else if (parent->_right == cur)parent->_right = cur->_right;}delete cur;}else if (cur->_right == nullptr)  //到这里说明左不为空,所以进入这个if说明左不空,右空{//到这里说明cur的左不为空,但右为空//同样需要注意单支树(只有左)if (cur == _root){_root = cur->_left;}else{if (parent->_left == cur)parent->_left = cur->_left;elseparent->_right = cur->_left;}delete cur;}else{//到这里说明cur的左右孩子都不为空(开始找替换)//用循环找到合适的值,但不能让cur进入循环,否则就找不到删除的值了,所以用新的值进入循环BSNode<int>* recur = cur; BSNode<int>* reparent = parent;//以(寻找左子树的max)为例while (recur->_right){reparent = recur;recur = recur->_right;}//将cur的值替换cur->k = recur->k;//删除recurif (reparent->_left == recur)reparent->_left = recur->_left;elsereparent->_right = recur->_left;//再将recur释放delete recur;}return true;}}return false;
}

三、key的搜索场景

  1. 搜索场景只需要判断key在不在。key的搜索场景实现的二叉树搜索树支持增删查,但是不支持修改,修改key破坏搜索树结构了。
  2. 检查篇英文文章单词拼写是否正确,将词库中所有单词放入二叉搜索树,读取文章中的单词,查找是否在二叉搜索树中,不在则波浪线标红提示
  3. 小区无人值守车库,小区车库买了车位的业主才能进入小区,那么业主会把买了车位的车主的车牌号录入后台系统,车辆进入时会扫描车牌在不在系统内,在则抬杆,不在的话就会提示非本小区车辆
    无法进入。

四、key/value搜索场景

一个key对应一个value

  1. 每一个关键码key,都有与之对应的值value(value可以是任意类型对象)。树的结构中(结点)除了需要存储key还要存储对应的value,增/删/查还是以key为关键字走二叉搜索树的规则进行比较,可以快速查找到key对应的value。key/value的搜索场景实现的二叉树搜索树仅支持修改val,仍然不支持修改key,修改key破坏搜索树性质了,可以修改value。在这里插入图片描述

  2. 应用场景:简单中英互译字典,树的结构中(结点)存储key(英文)和vlaue(中文),搜索时输入英文,则同时查找到了英文对应的中文

  3. 应用场景:统计一篇文章中单词出现的次数,读取一个单词,查找单词是否存在,不存在这个说明第一次出现,(单词,1),单词存在,则++单词对应的次数

  4. set --------key

  5. map ---------key/value

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

相关文章:

  • 做照明出口的网站兰州网络推广
  • 怎么用阿里云做网站公司网络推广排名定制
  • qq网站登录济南网络优化厂家
  • 济南网站建设泰观网络如何在百度上做广告
  • 蓟县网站建设seo专业论坛
  • 专业做网文的网站武汉seo网站管理
  • 厦门 网站建设闽icpit培训机构排名及学费
  • 北京建设银行网站理财产品网络优化是做啥的
  • 做网站服务器一年多少钱百度指数分析大数据
  • 如何选择一家靠谱的网站建设公司郑州seo招聘
  • 做网站的旅行社网站怎么seo关键词排名优化推广
  • 淄川政府网站建设托管电商关键词工具
  • 郑州微网站建设宁波网站优化公司电话
  • 成都网站定制开发佛山做优化的公司
  • 做网站怎么偷源码做网站企业网站建设多少钱
  • 做电商的网站二级域名注册平台
  • 深圳精品网站设计要做网络推广
  • 深圳企业网站制作公司介绍网络营销策划内容
  • 做网站开发的笔记本配置武汉大学人民医院地址
  • 互联网建站国际军事最新头条新闻
  • 做网站申请域名空间企业培训课程视频
  • 新手如何做移动端网站百度推广有效果吗
  • 网站名重复网站搜索引擎优化方法
  • 东莞网站建设怎么样app有哪些推广方式
  • 如何做vip电影解析网站2023年10月爆发新冠
  • 做的网站百度搜不到seo网站推广报价
  • 做电子商务系统网站建设怎样做好网络营销推广
  • 怎样不让网站被收录seo快排技术教程
  • 河南做外贸网站的公司简介seo超级外链工具
  • 做邮箱网站广安seo外包