1
0
mirror of https://github.com/chai2010/advanced-go-programming-book.git synced 2025-05-23 20:02:22 +00:00

fix router section

This commit is contained in:
Xargin 2018-12-19 14:55:50 +08:00
parent 2e22cc595b
commit 6f083a9fb9

View File

@ -109,12 +109,16 @@ httprouter和众多衍生router使用的数据结构被称为压缩字典树(Rad
![trie tree](../images/ch6-02-trie.png)
*图 6-1 字典树*
字典树常用来进行字符串检索例如用给定的字符串序列建立字典树。对于目标字符串只要从根节点开始深度优先搜索即可判断出该字符串是否曾经出现过时间复杂度为O(n)n可以认为是目标字符串的长度。为什么要这样做字符串本身不像数值类型可以进行数值比较两个字符串对比的时间复杂度取决于字符串长度。如果不用字典树来完成上述功能要对历史字符串进行排序再利用二分查找之类的算法去搜索时间复杂度只高不低。可认为字典树是一种空间换时间的典型做法。
普通的字典树有一个比较明显的缺点,就是每个字母都需要建立一个孩子节点,这样会导致字典树的层数比较深,压缩字典树相对好地平衡了字典树的优点和缺点。下图是典型的压缩字典树结构:
![radix tree](../images/ch6-02-radix.png)
*图 6-2 压缩字典树*
每个节点上不只存储一个字母了,这也是压缩字典树中“压缩”的主要含义。使用压缩字典树可以减少树的层数,同时因为每个节点上数据存储也比通常的字典树要多,所以程序的局部性较好(一个节点的path加载到 cache 即可进行多个字符的对比)从而对CPU缓存友好。
## 5.2.3 压缩字典树创建过程
@ -171,8 +175,11 @@ r.PUT("/user/installations/:installation_id/repositories/:reposit", Hello)
```
这样PUT对应的根节点就会被创建出来。把这棵PUT的树画出来
![put radix tree](../images/ch6-02-radix-put.png)
*图 6-3 插入路由之后的压缩字典树*
radix的节点类型为`*httprouter.node`,为了说明方便,我们留下了目前关心的几个字段:
```
@ -194,31 +201,40 @@ indices: 子节点索引,当子节点为非参数类型,即本节点的 wild
### 5.2.3.2 子节点插入
当插入`GET /marketplace_listing/plans`类似前面PUT的过程GET树的结构如图所示
当插入`GET /marketplace_listing/plans`类似前面PUT的过程GET树的结构如*图 6-4*
![get radix step 1](../images/ch6-02-radix-get-1.png)
*图 6-4 插入第一个节点的压缩字典树*
因为第一个路由没有参数path都被存储到根节点上了。所以只有一个节点。
然后插入 `GET /marketplace_listing/plans/:id/accounts`,新的路径与之前的路径有共同的前缀,且可以直接在之前叶子节点后进行插入,那么结果也很简单,插入后树变成了这样:
然后插入 `GET /marketplace_listing/plans/:id/accounts`,新的路径与之前的路径有共同的前缀,且可以直接在之前叶子节点后进行插入,那么结果也很简单,插入后的树结构见*图 6-5*:
![get radix step 2](../images/ch6-02-radix-get-2.png)
*图 6-5 插入第二个节点的压缩字典树*
由于`:id`这个节点只有一个字符串的普通子节点所以indices还依然不需要处理。
上面这种情况比较简单,新的路由可以直接作为原路由的子节点进行插入。实际情况不会这么美好。
### 5.2.3.3 边分裂
接下来我们插入`GET /search`,这时会导致树的边分裂。
接下来我们插入`GET /search`,这时会导致树的边分裂,见*图 6-6*
![get radix step 3](../images/ch6-02-radix-get-3.png)
*图 6-6 插入第三个节点,导致边分裂*
原有路径和新的路径在初始的`/`位置发生分裂这样需要把原有的root节点内容下移再将新路由 `search`同样作为子节点挂在root节点之下。这时候因为子节点出现多个root节点的indices提供子节点索引这时候该字段就需要派上用场了。"ms" 代表子节点的首字母分别为m(marketplace)和s(search)。
我们一口作气,把`GET /status``GET /support`也插入到树中。这时候会导致在`search`节点上再次发生分裂,来看看最终结果:
我们一口作气,把`GET /status``GET /support`也插入到树中。这时候会导致在`search`节点上再次发生分裂,最终结果见*图 6-7*
![get radix step 4](../images/ch6-02-radix-get-4.png)
*图 6-7 插入所有路由后的压缩字典树*
### 5.2.3.4 子节点冲突处理
在路由本身只有字符串的情况下不会发生任何冲突。只有当路由中含有wildcard(类似 :id)或者catchAll的情况下才可能冲突。这一点在前面已经提到了。