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

哈尔滨百度网站快速优化沈阳网站模板

哈尔滨百度网站快速优化,沈阳网站模板,什么是网络营销产生的基础,上海网站推广网络公司目录 一、B树的由来 二、B树的优势 三、B树的插入过程分析 四、B树插入和查找的实现 一、B树的由来 我们之前已经学习过了很多的搜索树,比如红黑树或者AVL树。他们都是属于二叉搜索树的范畴,在内存中的查找效率已经足够优秀了,为lo…

目录

一、B树的由来   

二、B树的优势

三、B树的插入过程分析

四、B树插入和查找的实现


一、B树的由来   

        我们之前已经学习过了很多的搜索树,比如红黑树或者AVL树。他们都是属于二叉搜索树的范畴,在内存中的查找效率已经足够优秀了,为logN次(即树的高度次)。但是正是由于他们是二叉搜索树,这就注定导致其高度在数据量很大的时候同样不小。

        由于二叉树树节点在磁盘中的存储的位置是不确定的,所以可能导致的结果就是:每一次往下走一层,磁盘就要重新定位,重新读数据。这就使得磁盘浪费在定位方面的时长较大,而真正取数据却只取到了一点点。(因为磁盘为了摊低定位的时间,是一次读一大片数据到缓存,如果你的数据比较连续存储的话,下一次就不用进行磁盘IO,而是在缓存中直接拿了)

二、B树的优势

        举个例子,如果你的二叉树高度是30层,那么你想要找到一个数据的时间就是30次磁盘IO。由于早期的磁盘技术不够发达,会使得查找的效率极度降低。当时的工程师们为了解决这个问题而研究出了B树。

B树的优势在于:

(1)B树能够显著的降低树的高度,因为他不再局限于二叉搜索树,而是变多叉搜索树。

(2)且一个节点中不再仅仅存放一个数据,而是存放大量的数据,人为的让数据在一个节点中就能让他们在磁盘中连续存放。

一棵m阶(m>2)的B树,是一棵平衡的M路平衡搜索树,可以是空树或者满足一下性质:

1. 根节点至少有两个孩子
2. 每个分支节点都包含k-1个关键字和k个孩子,其中 ceil(m/2) ≤ k ≤ m  ceil是向上取整函数

3. 每个叶子节点都包含k-1个关键字,其中 ceil(m/2) ≤ k ≤ m
4. 所有的叶子节点都在同一层
5. 每个节点中的关键字从小到大排列,节点当中k-1个元素正好是k个孩子包含的元素的值域划分
6. 每个结点的结构为:(n,A0,K1,A1,K2,A2,… ,Kn,An)其中,Ki(1≤i≤n)为关键字,且Ki<Ki+1(1≤i≤n-1)。Ai(0≤i≤n)为指向子树根结点的指针。且Ai所指子树所有结点中的关键字均小于Ki+1。n为结点中关键字的个数,满足ceil(m/2)-1≤n≤m-1。

三、B树的插入过程分析

        为了简单起见,假设M = 3. 即三叉树,每个节点中存储两个数据(关键字),两个数据可以将区间分割成三个部分,因此节点应该有三个孩子,为了后续实现简单期间,节点的结构如下:

注意:孩子永远比数据多一个。
用序列{53, 139, 75, 49, 145, 36, 101}构建B树的过程如下:

第一步:

第二步:分裂

第三步:仍然直接插入

第四步:分裂

最后一步:第一层满了,再向上开辟一层,进行分裂

可以分析出:

(1)新的关键字只能在叶子节点插入(最后一层的节点),然后通过调整向上生长或者向右生长,维护树的相对关系。

(2)B树是天然的平衡树,因为他不存在向下生长,只会向右/向上生长。

(3)上一层一定要维护下一层的连接所以有了孩子节点,这是毋庸置疑的。但是要注意,因为存在向上生长的情况,所以孩子节点一定也要能直接连接到父亲节点,在设计BTreeNode的时候要注意。

四、B树插入和查找的实现

#pragma once
#include <utility>template<class K,size_t M=3>
struct BTreeNode
{size_t _n = 0;						//当前节点的关键字数量K _keys[M];							//关键字数组BTreeNode<K, M>* _childs[M+1];		//孩子数组BTreeNode<K, M>* _parent=nullptr;	//当前节点的父亲指针BTreeNode(){//构造函数把孩子数组和关键字数组置为空for (size_t i=0;i<M;i++){_keys[i] = K();_childs[i] = nullptr;}//以为我们故意多存了一个孩子节点,也处理一下_childs[M] = nullptr;}
};template<class K,size_t M>
class BTree
{
public:typedef BTreeNode<K, M> Node;private:Node* _root;public://1.查找key值是否在树中存在,存在返回该节点的指针,以及元素下标;不存在返回空,下标不可信std::pair<Node*, int> Find(const K& key);//2.向树中插入一个值bool Insert(const K& key);//3.向树的node节点,插入key值,和child子树void InsertKeyAndChild(Node* node, const K& key, Node* child);//4.中序遍历void InOrder(){_InOrder(_root);}void _InOrder(Node* root){if (root == nullptr){return;}//每一个节点都要走中序for (size_t i = 0;i < root->_n;i++){_InOrder(root->_childs[i]);			//左cout << root->_keys[i] << " ";		//根}_InOrder(root->_childs[root->_n]);		//右}
};//这里使用typename是告诉编译器Node*是一个类型,而非BTree类中的一个成员(因为使用::符号编译器默认是成员)
template<class K, size_t M>
std::pair<typename BTree<K, M>::Node*, int> BTree<K, M>::Find(const K& key)
{Node* parent = nullptr;Node* cur = _root;int pos = -1;//当cur没有走到叶子节点的孩子,就一直往下走while(cur!=nullptr){size_t i = 0;//遍历一个节点while (i<cur->_n){//1.如果key<cur->_keys[i],说明要去左孩子找,退出当前节点的循环if (key < cur->_keys[i]){parent = cur;cur = cur->_childs[i];break;}//2.如果key>cur->_keys[i],说明这个节点的i位置不对,让i++,当i+到cur->_n的时候,就超出了这个节点,说明该节点没有,去右孩子找else if (key > cur->_keys[i]){i++;break;}//3.如果key==cur->_keys[i],说明找到了,直接退出循环返回else{std::pair<Node*, int> ret = std::make_pair(cur,i);return ret;}}//当i == cur->_n的时候,说明该节点找完了,但是却没有找到,说明要去右子树找if (i == cur->_n){parent = cur;cur = cur->_childs[i];}}//当cur走到nullptr,说明整棵树都找完了,没有找到,则返回最后一次查找的叶子节点和-1.(方便以后插入)std::pair<Node*, int> ret = std::make_pair(parent,-1);return ret;
}template<class K, size_t M>
void BTree<K, M>::InsertKeyAndChild(Node* node, const K& key, Node* child)
{//1.插入排序,使得插入后仍然保持有序//end是最后一个关键字数量-1,即最后一个关键字的下标int end = node->_n - 1;while (end>=0){//从后往前插入,如果比key大就一个个往后挪动if (key<node->_keys[end]){//为什么这里不用担心end+1会越界呢?因为他肯定不满,只要满了一定在上一次插入的时候就分裂了node->_keys[end + 1] = node->_keys[end];//还要把他的孩子往后挪动一格node->_childs[end+2] = node->_childs[end + 1];end--;}else{break;}}//走到这里说明key到了合适的位置,直接插入到end+1的位置node->_keys[end + 1] = key;node->_n++;//把自己的兄弟变成自己的右孩子node->_childs[end + 2] = child;//最后把孩子连接到父亲if (child!=nullptr){child->_parent = node;}
}template<class K, size_t M>
bool BTree<K, M>::Insert(const K& key)
{//1.如果是空树,直接插入到root的第一个位置if (_root==nullptr){_root = new BTreeNode<K,M>();_root->_n++;_root->_keys[0] = key;return true;}//2.如果不是空树,只能插入到叶子节点,然后进行调整//先要找到在哪里插入std::pair<Node*, int> ret = Find(key);Node* cur = ret.first;int pos = ret.second;//如果pos!=-1,说明在树中能够找到,则返回错误插入失败if (pos!=-1){return false;}//如果pos==-1,说明不存在,可以插入//而cur就是要插入的节点的指针,要插入的值就是key//相当于插入一个key值和一个空树//为什么要设置一个newkey呢?因为我们的参数是const的,无法修改,而真正的插入过程可能涉及插入后导致往上层插入,需要变换key值K newkey = key;Node* child = nullptr;while (1){InsertKeyAndChild(cur,newkey,child);//判断此节点有没有满,如果满了则分裂,拷贝,往上插入if (cur->_n<M){return true;}else{size_t mid = M / 2;//1.构造一个兄弟,把右半边拷贝给兄弟Node* brother = new Node();int j = 0;for (int i=mid+1;i<=M-1;i++){//拷贝关键字brother->_keys[j] = cur->_keys[i];//挪动孩子到兄弟brother->_childs[j] = cur->_childs[i];				//左孩子//修改孩子的父亲if (cur->_childs[i]!=nullptr){cur->_childs[i]->_parent = brother;}//对cur节点的右半区清空,防止下一次查找的时候错误找到了cur->_keys[i] = K();cur->_childs[i] = nullptr;j++;}//右孩子一直没拷贝,最后再来拷贝最右的孩子(如果在循环中拷贝了,就会同一个位置覆盖拷贝的问题)brother->_childs[j] = cur->_childs[M];		//右孩子if (cur->_childs[M]!=nullptr){cur->_childs[M]->_parent = brother;}//拷贝走了就清空原来节点对应位置的值,防止下一次查找错误cur->_childs[M] = nullptr;brother->_n = j;cur->_n -= j;//2.mid往上一层插入K midKey = cur->_keys[mid];cur->_keys[mid] = K();//如果上一层不存在,则创建if (cur->_parent=nullptr){_root = new Node();_root->_keys[0] = midKey;_root->_childs[0] = cur;_root->_childs[1] = brother;_root->_n = 1;cur->_parent = _root;brother->_parent = _root;break;}//如果上一层存在,则插入到上一层的最后(仍然是执行这个逻辑,只需要更新一下cur,child,newkey即可),再进行调整//变成了要在parent节点插入midKey和brother(因为上一层既然存在的话,左边就已经连接好了,只需要管右边)else{newkey = midKey;child = brother;cur = cur->_parent;}}}return true;
}

        B树虽然足够优秀了,但是却有着更强大的数据结构来代替他,即B+树和B*树。所以我们在数据库中使用的却不是他,而是B+树,但是B+树是由B树升级而来的,基础结构还是B树。


文章转载自:

http://5FIrYiiT.srbfp.cn
http://o91z0fhp.srbfp.cn
http://jPLGRoxD.srbfp.cn
http://y8rPcRwZ.srbfp.cn
http://kqYGBQdA.srbfp.cn
http://iSPOpNuS.srbfp.cn
http://jLDHJa8h.srbfp.cn
http://lxv7Q39X.srbfp.cn
http://ASkezufI.srbfp.cn
http://C2NWszup.srbfp.cn
http://0UopBP00.srbfp.cn
http://vwN0adAK.srbfp.cn
http://22Hzbpzx.srbfp.cn
http://cUSAg8ZX.srbfp.cn
http://REpR3YZF.srbfp.cn
http://ZHpPKUD4.srbfp.cn
http://GOxHhORE.srbfp.cn
http://ewrzBBp6.srbfp.cn
http://jd6JH1yK.srbfp.cn
http://uFcwBBSF.srbfp.cn
http://pygrazSm.srbfp.cn
http://BrYyAuNi.srbfp.cn
http://a3RdbCq5.srbfp.cn
http://MDustWb5.srbfp.cn
http://wS9wbKl9.srbfp.cn
http://auDsRC7E.srbfp.cn
http://82rt3nZB.srbfp.cn
http://aPIe8Iou.srbfp.cn
http://xQMEBxYx.srbfp.cn
http://YBDQ7Lvz.srbfp.cn
http://www.dtcms.com/wzjs/747609.html

相关文章:

  • 网站设计公司 中山广告设计公司公司vi设计
  • 西安网站建设阳建网站上线稳定后工作
  • 网站无法访问中国十大网络公司排行榜
  • 网站建设亇金手指下拉排名亅培训班报名
  • 织梦网站自动跳转手机网站电力大学临港校区建设网站
  • 微信可以做网站吗国产在线免费观看高甜电影推荐
  • 南宁个人做网站的vs做网站怎样添加图片
  • 大冶网站开发idea怎么做网站
  • 珠海营销网站建设做个网站多少钱大概
  • 网站链接优化网站统计怎么做
  • 公司电子商务网站建设策划书建筑公司企业宗旨
  • 柞水县住房和城乡建设局网站山西响应式网站设计
  • 花生壳动态域名做网站培训机构推荐
  • 如何下载网站模板网站运营建设的目标
  • 外贸双语网站源码公司网站上线流程
  • 网站建设教程浩森宇特手机网站是用什么开发的
  • pc网站自动转换wap网站襄樊网站建设襄樊
  • 上海专业网站建站品软件工作室网站模板
  • 阿里巴巴外贸网站首页注册公司北京
  • 泰国网站建设有关网站设计的文章
  • 网站建设背景分析论文wordpress取消重定向
  • 网站建设的空间选择做一个网站成本是多少合适
  • 太康做网站公司中国旅游网官网首页
  • 做网站的费用 可以抵扣吗全球搜索引擎网站
  • 建设维护网站运营方案电商营业执照怎么办
  • 各类网站国外网站服务器建设
  • whois查询 站长工具郑州酒店网站建设
  • 做网站赌钱犯法吗近期国外重大新闻事件
  • react企业网站模板网页制作模板教程
  • 青岛谁优化网站做的好教怎么做ppt的网站