在进行reduce软件设计的时候,我希望尽量保证软件操作的简单性。 通过一些巧妙的设计可以避免设计出复杂的软件,因此数据结构需要被文档化。 值得注意的是,这是reduce软件的v0。1版本,因此尚不确定reduce的数据结构会不会在今后的日子里大改,不过按照目前的心境来说,是可以设计出一个简单、强大的数据结构的。 reduce的后端存储严重依赖redis。我受到unix软件的设计启发,长期使用命令行等工具进行工作。我发现这种哲学带给我无尽的价值。reduce背后承载的思想非常宏大,所以必须按照经验来进行软件设计,因此我采用了最小工具集成的方式设计reduce。 redis的数据结构我采用了散列表和队列两种数据结构,下面我将按照图形的方式介绍其在reduce中的应用,相信你很快就会认同reduce采用这两种数据结构的巧妙之处,并萌生出为reduce设计无数扩展的想法。 前端模型需要和后端数据进行绑定,因此后端的进行才使得reduce向前推进。 先来看前端概念诞生的模型: 会发现一些行为: 增加concept 增加question concept转question question转concept concept:横向推理concept concept:横向质疑question 横向推理是用户的主观行为,不需要保存。 横向质疑是用户的主观行为,不需要保存。 上面这些操作都是最基础的操作。 对于删除和查询这两类操作来说,reduce算法会把两个conceptquestionconceptquestion之间所有的节点统统消灭,让其只剩下一个可以修改的conceptquestion。然后附着一个资源栈来链接提到的资源。 资源栈的设计是为了存储各种资源,目的是方便交流,方便在回溯的时候查找。 所有的资源具有唯一性,因此,采用hash表来进行存储是一种十分理想的情况。 后续如果侦测到同一类型的资源,就可以直接复用。 资源栈设计完成了,紧接着就是剩余数据结构的设计了。 在大概了解了redis的数据结构后,我开始进行接下来的设计。 在redis中,有一种特殊的数据结构叫做散列表。我的计划是使用topic当做散列表的key,然后topic内部的conceptquestion进行kv的映射。 采用这样的模型,在后续topic的设计升级成语义树的情况下,就有可能向上兼容升级为topic的语义树模型管理。 具体内部是如何实现kv型数据结构呢?structItem{ id:i128, str:String, reduceresource:OptionVecString, isfreshman:bool, isquestion:bool, left:Option, top:Option, } 一些说明 id我采用的是全局唯一自增长的id,不会考虑不够的情况。 每生成一个新的节点,都会生成一个新的全局自动增长的id, 每逻辑删除好多个节点,回到刚开始的那个节点,那个节点的id并不会更新。 str是conceptquestion的内容。 reduceresource中值为hash。 lefttop为指针指向和其他Item的关系。 reduce的存储 reduce是一个非常常用的操作,常用到他必须要有一种好用的数据结构来描述。但是我不想引入过多复杂的,脏的关系的描述,想要用巧妙的方法来记录reduce。 其实我想解决的问题是reduce的遍历问题,只要能按照时间顺序将其完美的进行遍历就ok了。 我使用了redis中提供的队列的数据结构,它能够根据key生成一个队列,这个队列其实是某个操作队列,记录着所有生成Item的时间过程。 一个点的关系我使用了left和top来描述。在构建这张图时,需要准备一个队列,随着这个队列元素的出队,会逐渐构建其这张图的全貌。 当元素1出队时,寻求构建它的left和top,发现都是None,则绘制1,完毕。 当元素2出队时,寻求构建它的left和top,发现2的left是1,则绘制1到2的边,完毕。 会不会存在2的left和top都有值的情况?不会。假设存在这种情况,那么就必然会有即向右构建,还向下构建的节点。在构建阶段是不存在这种节点的。在reduce阶段存在吗?不会。因为reduce其实他的一个核心操作是从一个叶子节点开始,将其路上所有的节点消灭,然后形成新的叶子节点。也就是最终的节点它非但right和bottom不会增加新的,反而会变成None。这种情况下,就保证了left和top只能最多有一个存在的唯一性。 当元素3出队时,需求构建它的left和top,发现2是它的top,因此绘制3。这些都是ok的。这样,按照队列的顺序遍历,其实整个图就可以确定。我们发现会存在4,5,4这样的节点,因此我们说这样的节点有一个reduce。 具体情况是这样的,4,5,4时,遍历到第二个4时,发现已经绘制了4,就知道这是一个Reduce节点。 然而,这种数据结构能否处理更为复杂的reduce情况呢?让我们用例子来说明。 在这个观点下,有几个可以观测到的概念: 出现两次及以上的点都是Reduce的点 Reduce的次数(点出现的次数1) Reduce的顺序可以按照Reduce匹配的右边的点从左往右数。constqueue〔〕; constreducesequence〔〕; for(vari0;iqueue。length;i){ varnodequeue〔i〕; if(queue。slice(0,i)。includes(queue〔i〕)){ thisisareduceclosenode reducesequence。push(queue〔i〕); } }