SuperObject(Delphi最好的JSON简析类) 扩展功能----排序(4)最终揭秘 解决sosmAdd模式不能查找的问题

经过对代码的更深入的跟踪理解,发现了superobject采用的是平衡二叉树的方式保存数据的。

 

首先看看保存数据的类

TSuperAvlEntry = class
  private
    FGt, FLt: TSuperAvlEntry;

FGt和FLt分别是保存通过比较(比较hash或者比较key的asc)大的保存在Gt,小的保存在Lt,是一个二叉树链表。

 

先上图

2x

假如有如下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;
posted @ 2011-02-26 09:26  D10.天地弦  阅读(3688)  评论(8编辑  收藏  举报