如何用C++实现一个简易数据库(十)

本文是《如何用C++实现一个简易数据库》的第十个单元

源码位于tutorial10-实现递归搜索

1. 如何实现递归搜索B-Tree

按照惯例,先看一下假设我们修复错误后应该如何正常打印我们的B-Tree

  it "allows printing out the structure of a 3-leaf-node btree" doscript = (1..14).map do |i|"insert #{i} user#{i} person#{i}@example.com"endscript << ".btree"script << "insert 15 user15 person15@example.com"script << ".btree"script << ".exit"result = run_script(script)expect(result[14...(result.length)]).to match_array(["db > Tree:","- internal (size 1)","  - leaf (size 7)","    - 1","    - 2","    - 3","    - 4","    - 5","    - 6","    - 7","  - key 7","  - leaf (size 7)","    - 8","    - 9","    - 10","    - 11","    - 12","    - 13","    - 14","db > Executed.","db > Tree:","- internal (size 1)","  - leaf (size 7)","    - 1","    - 2","    - 3","    - 4","    - 5","    - 6","    - 7","  - key 7","  - leaf (size 8)","    - 8","    - 9","    - 10","    - 11","    - 12","    - 13","    - 14","    - 15","db > Bye!",])end

我们此时应该是能够很好的工作了,同时我们针对我们的测试run_script方法进行了一些改进。

  def run_script(commands)raw_output = nilIO.popen("./db test.db", "r+") do |pipe|commands.each do |command|beginpipe.puts commandrescue Errno::EPIPEbreakendendpipe.close_write# Read entire outputraw_output = pipe.gets(nil)endraw_output.split("\n")end

此外,现在我们的限制应该是如何更新我们的父亲结点,这个将会在之后一一实现,我们现在仅需要修改对应的报错提示。

  it "prints error message when table is full" doscript = (1..1400).map do |i|"insert #{i} user#{i} person#{i}@example.com"endscript << ".exit"result = run_script(script)expect(result.last(2)).to match_array(["db > Executed.","db > Need to implement updating parent after split",])end

2. 如何实现搜索InternalNode?

既然是搜索,那么我们首先来看搜索的最顶层接口Table::table_find,我们现在需要支持搜索InternalNode

Cursor *Table::table_find(uint32_t key)
{Node root_node = pager.get_page(root_page_num);if (root_node.get_node_type() == NODE_LEAF){return new Cursor(this, root_page_num, key);}else{return internal_node_find(root_page_num, key);}
}

我们需要在internal_node_find中实现搜索InternalNode的逻辑。

Cursor *Table::internal_node_find(uint32_t page_num, uint32_t key)
{InternalNode node = pager.get_page(page_num);uint32_t num_keys = *node.internal_node_num_keys();/* Binary search to find index of child to search */uint32_t min_index = 0;uint32_t max_index = num_keys; /* there is one more child than key */while (max_index != min_index){uint32_t index = (min_index + max_index) / 2;uint32_t key_to_right = *node.internal_node_key(index);if (key_to_right >= key){max_index = index;}else{min_index = index + 1;}}uint32_t child_num = *node.internal_node_child(min_index);Node child = pager.get_page(child_num);switch (child.get_node_type()){case NODE_INTERNAL:return internal_node_find(child_num, key);case NODE_LEAF: default:return new Cursor(this, child_num, key);}
}

核心仍旧是使用二分搜索+递归。我们知道内部结点中所储存的孩子结点的指针的右侧储存的是该孩子指针所包含的最大的key值,所以我们只需要将被搜索的key不断与key_to_right进行比较,直到找到key的位置。

此外,当我们找到了对应的孩子结点时,要注意判断其类型仍旧为InternalNode,我们需要递归调用internal_node_find。亦或是我们找到了LeafNode,我们仅需要返回一个相应指向该结点的Cursor对象即可。

运行一下我们的测试

...........Finished in 0.04058 seconds (files took 0.0803 seconds to load)
11 examples, 0 failures

我们可以看到我们的搜索逻辑已经很好的工作了。

3. 总结

我们已经基本实现了搜索逻辑,但我们的Cursor其实在多层路径下还存在着一些问题。在下一章我们会通过更新Cursor类中的方法来解决这些问题。

如何用C++实现一个简易数据库(十)相关推荐

  1. 如何用C++实现一个简易数据库(九)

    如何用C++实现一个简易数据库(九) 本文是<如何用C++实现一个简易数据库>的第九个单元 源码位于tutorial09-实现拆分叶结点 1. 如何分裂叶子结点? 按照惯例,我们先增加一个 ...

  2. 如何用C++实现一个简易数据库(十一)

    如何用C++实现一个简易数据库(十一) 本文是<如何用C++实现一个简易数据库>的第十一个单元 源码位于tutorial11-实现扫描多层树 1. Cursor存在什么问题? 我们在上一章 ...

  3. 如何用 Python 写一个简易的抽奖程序

    不知道有多少人是被这个头图骗进来的:) 事情的起因是这样的,上周有同学问小编,看着小编的示例代码敲代码,感觉自己也会写了,如果不看的话,七七八八可能也写的出来,但是一旦自己独立写一段程序,感觉到无从下 ...

  4. 怎么用python制作简单的程序-如何用 Python 写一个简易的抽奖程序

    不知道有多少人是被这个头图骗进来的:) 事情的起因是这样的,上周有同学问小编,看着小编的示例代码敲代码,感觉自己也会写了,如果不看的话,七七八八可能也写的出来,但是一旦自己独立写一段程序,感觉到无从下 ...

  5. 【Unity3D 教程系列第 12 篇】如何用Unity写一个简易的计时器工具?

    这是[Unity3D 教程系列第 12 篇],如果觉得有用的话,欢迎关注专栏. 平常关于延时的处理很多人都喜欢用携程去处理,但是在 Unity 里,并不建议大家用过多的携程,因为会出现一些莫名其妙的 ...

  6. 如何用idea做一个简易的网页登录界面

    在上一节课的内容基础上做一个简易的网页登录界面--18级软工1班03 打开idea后打开上一节课的工程文件(一般在打开idea软件的同时,idea会默认打开上一次的文件)并在左边列表的main文件夹下 ...

  7. 如何用Java制作一个简易日历

    简易日历制作 记录一下Java实现的一个日历小程序,效果图如下: 实现以上的效果,我们需要用到两个类:SimpleDateFormat和Calendar. 首先看看这两个类的用法: 类 SimpleD ...

  8. python alpha_如何用Python打造一个简易版的Alpha GO?

    原文来自于Github:brilee/MuGo 这是 AlphaGo 基本组成部分的一个纯 Python 实现. AlphaGo 逻辑/控制流(logic/control flow)其实并不非常复杂, ...

  9. js计算器代码加减乘除_如何用jQuery做一个简易版计算器

    经过几个小时地敲敲打打,终于把这一部分的代码完成了. 这类问题的难点不在于布局,而是如何恰当地使用jQuery达成计算.交互的目的,比如储存.显示数值,数据类型的转换等. 在听老师讲课之前的我,思路是 ...

最新文章

  1. 快速索引 (对View的自定义)
  2. proc下kcore是什么文件
  3. 案例:服务器输出字符数据到浏览器 || 乱码问题|| 案例:服务器输出字节数据到浏览器
  4. 测试小白入门必知必会的8个测试工具
  5. CountDownLacth详解
  6. 摄像头夜间拍摄画面有拖影_让客厅秒变健身房,OPPO智能电视R1+摄像头上手体验...
  7. 学mysql需要学python吗_python 学习 第六篇 mysql
  8. 关于2014年上半年全国计算机等级考试有关事宜的通知,关于2014年上半年全国计算机等级考试报名的通知...
  9. mysql查询前100个_mysql查询前100条数据
  10. C++入门经典 Ivor Horton 第3版
  11. python常用的开发环境包括_Python 全栈:Python 四种常用开发环境总结
  12. 什么是v-model语法糖
  13. 计算机网络ospf流程图,计算机网络7-OSPF祥解.ppt
  14. Java使用aopse实现word转换pdf
  15. IBM DB2 Alphablox 8.3 build 149 安装过程 部署 WebSphere Application Server 6.0.1上
  16. C++多线程:thread_local
  17. 贸然用string比较的后果
  18. 条形码标签软件Bartender怎么样?三大版本该选择哪个?
  19. MB10F-ASEMI整流桥MB10F
  20. 简单易懂的小学除法思维导图

热门文章

  1. java 设置dns_通过代码直接设置Java的DNS - Java Dns Cache Manipulator
  2. 项目设计 盲人导航系统
  3. python使用mechanize
  4. 「可信计算」论文初步解读
  5. 数据采集与管理【12】
  6. 腾讯|前端开发实习生 | 深圳 | 2021 一二+HR面面经
  7. Xilinx 7系列FPGA架构 SelectIO 常见电平标准和阻抗匹配(精华)
  8. 协程爬虫(python)
  9. 卡特兰(Catalan)数入门详解
  10. 转:变革:站在十字路口的领导力