B树、B-树、B+树、B*树 wrong wrong

B树家族详解
本文详细介绍了B树家族的各种类型,包括B树、B-树、B+树和B*树的特点与区别。每种树都有详细的定义说明及图例展示,帮助读者理解不同树结构的应用场景。

B

       即二叉搜索树:

       1.所有非叶子结点至多拥有两个儿子(LeftRight);

       2.所有结点存储一个关键字;

       3.非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树;

       如:

       

       B树的搜索,从根结点开始,如果查询的关键字与结点的关键字相等,那么就命中;

否则,如果查询关键字比结点关键字小,就进入左儿子;如果比结点关键字大,就进入

右儿子;如果左儿子或右儿子的指针为空,则报告找不到相应的关键字;

       如果B树的所有非叶子结点的左右子树的结点数目均保持差不多(平衡),那么B

的搜索性能逼近二分查找;但它比连续内存空间的二分查找的优点是,改变B树结构

(插入与删除结点)不需要移动大段的内存数据,甚至通常是常数开销;

       如:

      

   但B树在经过多次插入与删除后,有可能导致不同的结构:

   右边也是一个B树,但它的搜索性能已经是线性的了;同样的关键字集合有可能导致不同的

树结构索引;所以,使用B树还要考虑尽可能让B树保持左图的结构,和避免右图的结构,也就

是所谓的“平衡”问题;      

       实际使用的B树都是在原B树的基础上加上平衡算法,即“平衡二叉树”;如何保持B

结点分布均匀的平衡算法是平衡二叉树的关键;平衡算法是一种在B树中插入和删除结点的

策略;

 

 

B-

       是一种多路搜索树(并不是二叉的):

       1.定义任意非叶子结点最多只有M个儿子;且M>2

       2.根结点的儿子数为[2, M]

       3.除根结点以外的非叶子结点的儿子数为[M/2, M]

       4.每个结点存放至少M/2-1(取上整)和至多M-1个关键字;(至少2个关键字)

       5.非叶子结点的关键字个数=指向儿子的指针个数-1

       6.非叶子结点的关键字:K[1], K[2], …, K[M-1];且K[i] < K[i+1]

       7.非叶子结点的指针:P[1], P[2], …, P[M];其中P[1]指向关键字小于K[1]

子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树;

       8.所有叶子结点位于同一层;

       如:(M=3

       B-树的搜索,从根结点开始,对结点内的关键字(有序)序列进行二分查找,如果

命中则结束,否则进入查询关键字所属范围的儿子结点;重复,直到所对应的儿子指针为

空,或已经是叶子结点;

B-树的特性:

       1.关键字集合分布在整颗树中;

       2.任何一个关键字出现且只出现在一个结点中;

       3.搜索有可能在非叶子结点结束;

       4.其搜索性能等价于在关键字全集内做一次二分查找;

       5.自动层次控制;

       由于限制了除根结点以外的非叶子结点,至少含有M/2个儿子,确保了结点的至少

利用率,其最底搜索性能为:

    

       其中,M为设定的非叶子结点最多子树个数,N为关键字总数;

       所以B-树的性能总是等价于二分查找(与M值无关),也就没有B树平衡的问题;

       由于M/2的限制,在插入结点时,如果结点已满,需要将结点分裂为两个各占

M/2的结点;删除结点时,需将两个不足M/2的兄弟结点合并;

 

 

B+

       B+树是B-树的变体,也是一种多路搜索树:

       1.其定义基本与B-树同,除了:

       2.非叶子结点的子树指针与关键字个数相同;

       3.非叶子结点的子树指针P[i],指向关键字值属于[K[i], K[i+1])的子树

B-树是开区间);

       5.为所有叶子结点增加一个链指针;

       6.所有关键字都在叶子结点出现;

       如:(M=3

   B+的搜索与B-树也基本相同,区别是B+树只有达到叶子结点才命中(B-树可以在

非叶子结点命中),其性能也等价于在关键字全集做一次二分查找;

       B+的特性:

       1.所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好

是有序的;

       2.不可能在非叶子结点命中;

       3.非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储

(关键字)数据的数据层;

       4.更适合文件索引系统;

  

B*

       B+树的变体,在B+树的非根和非叶子结点再增加指向兄弟的指针;

   B*树定义了非叶子结点关键字个数至少为(2/3)*M,即块的最低使用率为2/3

(代替B+树的1/2);

       B+树的分裂:当一个结点满时,分配一个新的结点,并将原结点中1/2的数据

复制到新结点,最后在父结点中增加新结点的指针;B+树的分裂只影响原结点和父

结点,而不会影响兄弟结点,所以它不需要指向兄弟的指针;

       B*树的分裂:当一个结点满时,如果它的下一个兄弟结点未满,那么将一部分

数据移到兄弟结点中,再在原结点插入关键字,最后修改父结点中兄弟结点的关键字

(因为兄弟结点的关键字范围改变了);如果兄弟也满了,则在原结点与兄弟结点之

间增加新结点,并各复制1/3的数据到新结点,最后在父结点增加新结点的指针;

       所以,B*树分配新结点的概率比B+树要低,空间使用率更高;

  

小结

       B树:二叉树,每个结点只存储一个关键字,等于则命中,小于走左结点,大于

走右结点;

       B-树:多路搜索树,每个结点存储M/2M个关键字,非叶子结点存储指向关键

字范围的子结点;

       所有关键字在整颗树中出现,且只出现一次,非叶子结点可以命中;

       B+树:在B-树基础上,为叶子结点增加链表指针,所有关键字都在叶子结点

中出现,非叶子结点作为叶子结点的索引;B+树总是到叶子结点才命中;

       B*树:在B+树基础上,为非叶子结点也增加链表指针,将结点的最低利用率

1/2提高到2/3

 

 原文地址 http://blog.youkuaiyun.com/manesking/archive/2007/02/09/1505979.aspx

WebSocket 握手失败并返回状态码 `404 Not Found` 通常表示客户端尝试连接的 WebSocket 服务器端点不存在或无法访问。握手失败的原因可能有多种,以下是一些常见的原因及相应的解决办法: ### 1. **WebSocket 服务器未正确配置** - **原因**:服务器端未正确配置 WebSocket 服务,导致请求的路径不存在或未正确映射。 - **解决办法**:检查服务器端的 WebSocket 路由配置,确保客户端请求的 URL 服务器端配置的路径一致。例如,在 Node.js 中使用 `ws` 模块时,确保 WebSocket 服务器监听的路径客户端请求的路径匹配。 ```javascript const WebSocket = require('ws'); const wss = new WebSocket.Server({ port: 8080, path: '/websocket' }); ``` - 客户端应使用相同的路径进行连接: ```javascript const socket = new WebSocket('ws://localhost:8080/websocket'); ``` ### 2. **服务器未运行或端口未开放** - **原因**:WebSocket 服务器未启动,或者防火墙、安全组规则阻止了对 WebSocket 端口的访问。 - **解决办法**:确保 WebSocket 服务器正在运行,并且服务器的防火墙或安全组允许客户端访问相应的端口(例如 8080)。可以通过 `telnet` 或 `nc` 命令测试端口是否开放: ```bash telnet localhost 8080 ``` ### 3. **URL 路径错误** - **原因**:客户端请求的 WebSocket URL 错误,导致服务器返回 404。 - **解决办法**:检查客户端使用的 WebSocket URL 是否正确,包括协议(`ws://` 或 `wss://`)、主机名、端口和路径。例如,确保没有拼写错误或遗漏路径部分: ```javascript // 错误示例 const socket = new WebSocket('ws://localhost:8080/wrongpath'); // 正确示例 const socket = new WebSocket('ws://localhost:8080/websocket'); ``` ### 4. **服务器端返回 HTML 内容** - **原因**:当 WebSocket 握手失败时,服务器可能返回 HTML 内容作为错误页面(如 404 页面),导致客户端接收到 `Content-Type: text/html` 的响应。 - **解决办法**:检查服务器日志以确认 WebSocket 握手失败的具体原因。如果服务器配置了默认的错误页面(如 404 页面),可以调整服务器配置,使其在 WebSocket 握手失败时返回适当的错误消息而不是 HTML 页面。 ### 5. **代理或负载均衡器配置问题** - **原因**:如果使用了反向代理(如 Nginx)或负载均衡器,可能未正确配置以支持 WebSocket 协议。 - **解决办法**:确保反向代理或负载均衡器正确配置了 WebSocket 支持。例如,在 Nginx 中需要设置以下头部以支持 WebSocket: ```nginx location /websocket/ { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } ``` ### 6. **SSL/TLS 配置问题** - **原因**:如果使用 `wss://` 协议(WebSocket over SSL/TLS),可能由于 SSL/TLS 配置不正确导致握手失败。 - **解决办法**:检查服务器的 SSL/TLS 配置,确保证书有效且配置正确。例如,在 Node.js 中启用 SSL 支持: ```javascript const fs = require('fs'); const https = require('https'); const WebSocket = require('ws'); const server = https.createServer({ cert: fs.readFileSync('/path/to/cert.pem'), key: fs.readFileSync('/path/to/key.pem') }); const wss = new WebSocket.Server({ server }); server.listen(8080); ``` ### 7. **跨域请求问题** - **原因**:如果客户端服务器不在同一域,可能会受到跨域限制,导致握手失败。 - **解决办法**:在服务器端设置适当的 CORS(跨域资源共享)头,允许客户端的域进行 WebSocket 连接。例如,在 Node.js 中设置: ```javascript const WebSocket = require('ws'); const wss = new WebSocket.Server({ port: 8080 }, () => { console.log('WebSocket server is running on ws://localhost:8080'); }); wss.on('connection', (ws, req) => { // 设置 CORS 头 ws.upgradeReq.headers.origin = req.headers.origin; }); ``` ### 8. **客户端代码错误** - **原因**:客户端代码中可能存在错误,导致 WebSocket 握手失败。 - **解决办法**:检查客户端代码,确保没有语法错误或逻辑错误。可以使用浏览器的开发者工具(如 Chrome DevTools)查看网络请求的详细信息,确认 WebSocket 请求的 URL、头部等是否正确。 ### 9. **服务器端限制连接数** - **原因**:服务器端可能设置了连接数限制,导致新的 WebSocket 连接被拒绝。 - **解决办法**:检查服务器端的连接数限制配置,适当调整限制或优化资源使用,确保服务器能够处理更多的连接。 ### 10. **WebSocket 协议版本不兼容** - **原因**:客户端和服务器端使用的 WebSocket 协议版本不兼容,导致握手失败。 - **解决办法**:确保客户端和服务器端都使用标准的 WebSocket 协议版本(如 RFC 6455)。大多数现代浏览器和 WebSocket 库都支持标准协议,因此通常不需要手动调整版本。 ### 总结 WebSocket 握手失败并返回 `404 Not Found` 的原因可能有多种,常见的包括服务器未正确配置、URL 路径错误、服务器未运行或端口未开放等。通过检查服务器配置、客户端代码、网络连接等方面,通常可以找到并解决该问题。[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值