经过对代码的更深入的跟踪理解,发现了superobject采用的是平衡二叉树的方式保存数据的。
首先看看保存数据的类
TSuperAvlEntry = class
private
FGt, FLt: TSuperAvlEntry;
FGt和FLt分别是保存通过比较(比较hash或者比较key的asc)大的保存在Gt,小的保存在Lt,是一个二叉树链表。
先上图
假如有如下Json
"assign": {
"FAreaKey": "FKey",
"FAreaName": "FName",
"FAreaCode": "FCode",
}
按照sosmASC排序模式
1.首先插入的是FAreaKey节点,
2.然后插入的是FAreaName时跟Root就是FAreaKey进行比较那他会插入到FAreaKey对应的节点的Gt下图形A1表示
3.然后插入的是FAreaCode跟FAreakey比较时为较小的插入到LT下面如图A2表示
4.A2图已经为平衡二叉树。
再看看按sosmAdd排序模式
按照sosmAdd的模式的话都是排在后面也就是都放在GT位置
1.首先插入的是FAreaKey节点,
2.然后插入的是FAreaName时跟Root就是FAreaKey进行比较那他会插入到FAreaKey对应的节点的Gt下图形A1表示
3.然后插入的是FAreaCode跟FAreakey比较时因为GT位置已经有了FAreaName,此时再跟FAreaName比较也是为大的插入FAreaName的GT下面如图B1表示
4.如图B1表示经过平衡二叉树后变成了B2样式。
这样查找的话,因为sosmAdd的查询时都是查找GT位置,不会查找LT分支,所以查询FAreaKey时会查询不到。
所以简单的办法就是如果安装sosmAdd方式存储是不进行平衡二叉数,这样所有的数据都保存在GT位置。这样就成为了一个链表的方式,这样可以从头查到尾。必然可以查到。
*****深入研究后发现查询时之前的不区分Key的大小写的修改其实很容易做到。
最终的Insert代码为
function TSuperAvlTree.Insert(h: TSuperAvlEntry): TSuperAvlEntry; var unbal, parentunbal, hh, parent: TSuperAvlEntry; depth, unbaldepth: longint; cmp: integer; unbalbf: integer; branch: TSuperAvlBitArray; p: Pointer; begin inc(FCount); h.FLt := nil; h.FGt := nil; h.FBf := 0; branch := []; if (FRoot = nil) then FRoot := h else begin unbal := nil; parentunbal := nil; depth := 0; unbaldepth := 0; hh := FRoot; parent := nil; repeat if (hh.FBf <> 0) then begin unbal := hh; parentunbal := parent; unbaldepth := depth; end; if hh.FHash <> h.FHash then begin if nowSortMode = sosmDefault then begin //original code if hh.FHash < h.FHash then cmp := -1 else if hh.FHash > h.FHash then cmp := 1 else cmp := 0; end else begin // modify by mofen cmp := CompareForSortModeString(h.Name, hh.Name); end; end else cmp := CompareNodeNode(h, hh); if (cmp = 0) then begin Result := hh; //exchange data p := hh.Ptr; hh.FPtr := h.Ptr; h.FPtr := p; doDeleteEntry(h, false); dec(FCount); exit; end; parent := hh; if (cmp > 0) then begin hh := hh.FGt; include(branch, depth); end else begin hh := hh.FLt; exclude(branch, depth); end; inc(depth); until (hh = nil); if (cmp < 0) then parent.FLt := h else parent.FGt := h; depth := unbaldepth; if (unbal = nil) then hh := FRoot else begin if depth in branch then cmp := 1 else cmp := -1; inc(depth); unbalbf := unbal.FBf; if (cmp < 0) then dec(unbalbf) else inc(unbalbf); if cmp < 0 then hh := unbal.FLt else hh := unbal.FGt; if ((unbalbf <> -2) and (unbalbf <> 2)) then begin unbal.FBf := unbalbf; unbal := nil; end; end; if (hh <> nil) then while (h <> hh) do begin if depth in branch then cmp := 1 else cmp := -1; inc(depth); if (cmp < 0) then begin hh.FBf := -1; hh := hh.FLt; end else (* cmp > 0 *) begin hh.FBf := 1; hh := hh.FGt; end; end; // original code // if (unbal <> nil) then if (unbal <> nil) and (nowSortMode <> sosmAdd) then //modify by mofen begin unbal := balance(unbal); if (parentunbal = nil) then FRoot := unbal else begin depth := unbaldepth - 1; if depth in branch then cmp := 1 else cmp := -1; if (cmp < 0) then parentunbal.FLt := unbal else parentunbal.FGt := unbal; end; end; end; result := h; end;