记录一次用于表示全国省市区地址树的建立和处理过程.
关于地址树的处理
当前服务端返回的节点数据是这样的:
json
{ "id": "110102", "parentId": "110100", "parentIds": "110000,110100,110102", "name": "西城区", "parentName": "市辖区", "parentNames": "北京市市辖区西城区", "type": "3", "code": "110102", // 暂未使用 "sort": 2 // 暂未使用 }
可以将这个 JSON 转换为下面的这个实体:
swift
struct Node { let nodeID: String // id "110102" let parentID: String // parentId "110100" let fullPath: String // parentIds "110000,110100,110102" let name: String // "西城区" let parentName: String // "市辖区" let parentNames: String // "北京市市辖区西城区" let depth: String // "3" }
操作:
- 获取指定 ID 的节点
- 获取指定 ID 节点的所有子节点.(在指定 ID 节点获取的时候就可以直接拿到.)
比如获取根节点后, 就可以直接拿到它的所有子节点, 就是一级节点.
拿到一个一级节点, 向下拿它的孩子就是所有的二级, 依次类推. 这样就无需每次去遍历整个地址数组了!!!! 且存储空间也可以减少很多!!!
如果能够将结构重建, 则可以减少很多内存占用, 比如可以将节点简化为如下的造型:
swift
// 树节点的泛型定义: 如果 children.isEmpty == true, 则是叶子节点 class TreeNode<T> { let value: T let children: [TreeNode<T>] } extension TreeNode<T> { func isLeaf() -> Bool { return children.isEmpty } } struct Area { let nodeID: String // id "110102" let name: String // "西城区" } // 建树 // 根节点定义: 其中 children 是全部深度 1 的节点 let rootValue = Area(nodeID: "0", name: "") let rootNode = TreeNode<Area>(value: rootValue, children: ...)
ContiguousArray 曰: 居然在 swift 中早就有了…即顺序存储的线性表.
为什么要选择 class 呢? 由于不知道该树中的 Node 是否会被外部修改, 如果使用 struct, 则修改不会被同步到树上, 而是被复制到新的地方, 所以说用 class 更好.
要解决问题:
- 建树: 通过原始数据, 按老办法过滤一遍?
- 遍历: BFS, DFS.
已经将工程放到这里了, 实际解决的时候用的是蛮力建树, 直接将每个结点连接到它的父结点, 不过这里将子节点存储放到双向链表中提高加入的效率.