• Delphi的HashMap


    使用过Java的朋友,应该知道它有个超好用的HashMap容器类,面试必问的,在Delphi10中有TDictionary类,但Delphi7没得用,所以自己动手,使用数组 + 链表写个类似Java的HashMap类,提供给所有坚守Delphi的朋友们,性能还是相当不错的。

      1 {*******************************************************}
      2 {                                                       }
      3 {       Delphi HashMap                                  }
      4 {                                                       }
      5 {       版权所有 (C) 2018 hsoft                          }
      6 {                                                       }
      7 {                                                       }
      8 { Author: MarkWu    Email: 77910086@qq.com              }
      9 { Date:   2018-01-02 14:17:00                           }
     10 { Desc:   HashMap                                       }
     11 {*******************************************************}
     12 
     13 unit uHashMap;
     14 
     15 interface
     16 
     17 uses
     18   Windows, SysUtils, StrUtils, Classes, uHashEntry, Variants;
     19 
     20 type
     21   // 实体数组类型
     22   TEntrySet = array of THashEntry;
     23   
     24   // 排序类型
     25   TSortType = (
     26         stKey,      // 按Key排序
     27         stValue,    // 按Value排序
     28         stKeyValue  // Key=Value排序
     29   );
     30 
     31   THashMap = class
     32   private
     33     // 临界值
     34     FThreshold: Integer;
     35 
     36     // 元素个数
     37     FCount: Integer;
     38 
     39     // 扩容次数
     40     FResize: Integer;
     41 
     42     FTable: TEntrySet;
     43 
     44     procedure InitTable();
     45 
     46     // 计算AKey的HashCode
     47     function HashCode(AKey: string): Integer;
     48     function IndexOf(AKey: string; iLen: Integer = 0): Integer;
     49     
     50     procedure Put(AIndex: Integer; AKey: string; AValue: Variant; AIsObj: Boolean = False);
     51     // 加入Key为空
     52     procedure PutNullKey(AValue: Variant);
     53 
     54     procedure Resize(capacity: Integer);
     55 
     56     function ToList: TList;
     57 
     58     //扩容时重新计算各元素的index
     59     procedure Transfer(ANewTable: TEntrySet);
     60     function GetItems(Index: Integer): THashEntry;
     61 
     62   public
     63     constructor Create();
     64     destructor Destroy; override;
     65     // 添加一个元素
     66     procedure Add(AKey: string; AValue: Variant; AIsObj: Boolean = False); overload;
     67     procedure Add(AMap: THashMap); overload;
     68     procedure AddObject(AKey: string; AValue: TObject);
     69 
     70     function Get(AKey: string): Variant;
     71     function GetObject(AKey: string): TObject;
     72     function GetNullKey: Variant;
     73     function GetEntry(AKey: string): THashEntry;
     74     procedure Remove(AKey: string);
     75     function ContainsKey(AKey: string): Boolean;
     76     procedure Clear;
     77 
     78     function GetEntrySet: TEntrySet;
     79 
     80     function ToString: string;
     81 
     82     // 排序
     83     function Sort(ASortType: TSortType = stKeyValue): TEntrySet;
     84 
     85     property Count: Integer read FCount;
     86     property Items[Index: Integer]: THashEntry read GetItems; default;
     87   end;
     88 
     89 implementation
     90 
     91 
     92 const
     93   //默认初始化大小 16, 数组长度一定是2的次幂
     94   DEFAULT_INITIAL_CAPACITY = 16;
     95 
     96   //默认负载因子 0.75
     97   DEFAULT_LOAD_FACTOR = 0.75;
     98 
     99   MAX_SIZE = 1000000;
    100 
    101 { THashMap }
    102 
    103 constructor THashMap.Create;
    104 begin
    105   InitTable;
    106 end;
    107 
    108 destructor THashMap.Destroy;
    109 begin
    110   Clear;
    111 
    112   SetLength(FTable, 0);
    113   FCount := 0;
    114   inherited;
    115 end;
    116 
    117 
    118 procedure THashMap.InitTable;
    119 begin
    120   SetLength(FTable, DEFAULT_INITIAL_CAPACITY);
    121   FThreshold := Trunc(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
    122   FCount := 0;
    123 end;
    124 
    125 // 计算AKey的HashCode
    126 function THashMap.HashCode(AKey: string): Integer;
    127 var
    128   I: Integer;
    129 begin                                       
    130   Result := 0;
    131   if (Result = 0) and (Length(AKey) > 0) then
    132   begin
    133     for I := 1 to Length(AKey) do
    134     begin
    135       Result := 31 * Result + Ord(AKey[I]);
    136     end;
    137   end;
    138 end;
    139 
    140 function THashMap.IndexOf(AKey: string; iLen: Integer): Integer;
    141 begin
    142   if iLen = 0 then iLen := Length(FTable);
    143   // 根据key的hashcode和table长度取模计算key在table中的位置
    144   Result := HashCode(AKey) and (iLen - 1);
    145 end;
    146 
    147 procedure THashMap.Add(AKey: string; AValue: Variant; AIsObj: Boolean);
    148 var
    149   index: Integer;
    150   entry: THashEntry;
    151 begin
    152   // key为''时,需要特殊处理
    153   if AKey = '' then
    154   begin
    155     PutNullKey(AValue);
    156     Exit;
    157   end;
    158 
    159   if Length(FTable) = 0 then
    160     InitTable;
    161 
    162   index := IndexOf(AKey);
    163   // 遍历index位置的Entry, 若找到重复key,则更新对应entry的值,再返回
    164   entry := FTable[index];
    165   while entry <> nil do
    166   begin
    167     if (HashCode(entry.Key) = HashCode(AKey)) and (SameText(entry.Key, AKey)) then
    168     begin
    169       //entry.Value := Unassigned;
    170       entry.Value := AValue;
    171       Exit;
    172     end;
    173     entry := entry.Next;
    174   end;
    175   // 如果index位置没有找到或者未找到重复的Key, 则将新Key添加到table的index位置
    176   Put(index, AKey, AValue, AIsObj);
    177 end;
    178 
    179 procedure THashMap.PutNullKey(AValue: Variant);
    180 var
    181   entry: THashEntry;
    182 begin
    183   entry := FTable[0];
    184   while entry <> nil do
    185   begin
    186     // 如果找到Key为空的对象时,则覆盖它
    187     if entry.Key = '' then
    188     begin
    189       entry.Value := AValue;
    190       Exit;
    191     end;
    192 
    193     entry := entry.Next;
    194   end;
    195   Put(0, '', AValue);
    196 end;
    197 
    198 procedure THashMap.Put(AIndex: Integer; AKey: string; AValue: Variant; AIsObj: Boolean = False);
    199 var
    200   entry: THashEntry;
    201 begin
    202   // 将新的entry放到table的index位置第一个, 如果原来有值则以链表存放
    203   entry := THashEntry.Create(AKey, AValue, FTable[AIndex], AIsObj);
    204   FTable[AIndex] := entry;
    205   // 若达到临界值, 则进行扩容,将table的capacity翻倍
    206   Inc(FCount);
    207 
    208   if FThreshold >= MAX_SIZE then
    209   begin
    210     FThreshold := MAX_SIZE;
    211     Exit;
    212   end;
    213 
    214   if FCount >= FThreshold then
    215   begin
    216     Resize(Length(FTable) * 2);
    217   end;
    218 end;
    219 
    220 procedure THashMap.Resize(capacity: Integer);
    221 var
    222   I, index: Integer;
    223   newTable: TEntrySet;
    224 begin
    225   if capacity <= Length(FTable) then Exit;
    226 
    227 
    228   SetLength(newTable, capacity);
    229 
    230   Transfer(newTable);
    231   FTable := nil;
    232   FTable := newTable;
    233 
    234   //修改临界值
    235   FThreshold := Trunc(Length(FTable) * DEFAULT_LOAD_FACTOR);
    236   Inc(FResize);
    237 end;
    238 
    239 //重新计算index
    240 procedure THashMap.Transfer(ANewTable: TEntrySet);
    241 var
    242   I, newIndex: Integer;
    243   iNewCapacity: Integer;
    244   e, tmpNext: THashEntry;
    245 begin
    246   iNewCapacity := Length(ANewTable);
    247   // 循环Table,重新计算各元素索引位置, 再把旧数组数据Copy到新数组中
    248   for I := Low(FTable) to High(FTable) do
    249   begin
    250     e := FTable[I];
    251     while e <> nil do
    252     begin
    253       tmpNext := e.Next;
    254       // 计算出新的索引
    255       newIndex := IndexOf(e.Key, iNewCapacity);
    256       // 把当前旧entry.next链指向新的索引位置,ANewTable[newIndex]可能为nil, 也可能是entry链,
    257       // 如果是entry链,就直接在链表头插入
    258       e.Next := ANewTable[newIndex];
    259       ANewTable[newIndex] := e;
    260 
    261       e := tmpNext;
    262     end;
    263   end;
    264 end;
    265 
    266 function THashMap.Get(AKey: string): Variant;
    267 var
    268   entry: THashEntry;
    269 begin
    270   Result := NULL;
    271   if (AKey = '') then
    272   begin
    273     Result := GetNullKey;
    274     Exit;
    275   end;
    276 
    277   entry := GetEntry(AKey);
    278   if entry = nil then
    279     Result := NULL
    280   else
    281     Result := entry.Value;
    282 end;
    283 
    284 function THashMap.GetNullKey: Variant;
    285 var
    286   e: THashEntry;
    287 begin
    288   if FCount = 0 then
    289   begin
    290     Result := Null;
    291     Exit;
    292   end;
    293 
    294   //在FTable[0]的链表上查找key为''的键值对,因为''默认是存在FTable[0]的桶里
    295   e := FTable[0];
    296   while e <> nil do
    297   begin
    298     if e.Key = '' then
    299     begin
    300       Result := e.Value;
    301       Break;
    302     end;
    303     e := e.Next;
    304   end;
    305 end;
    306 
    307 
    308 function THashMap.GetEntry(AKey: string): THashEntry;
    309 var
    310   entry: THashEntry;
    311 begin
    312   entry := FTable[IndexOf(AKey)];
    313   try
    314     while (entry <> nil) do
    315     begin
    316       if (HashCode(entry.Key) = HashCode(AKey)) and SameText(entry.Key, AKey) then
    317       begin
    318         Result := entry;
    319         Exit;
    320       end;
    321       entry := entry.Next;
    322     end;
    323     Result := entry;
    324   except
    325     Result := nil;
    326   end;
    327 end;
    328 
    329 procedure THashMap.Remove(AKey: string);
    330 var
    331   index: Integer;
    332   pre, entry: THashEntry;
    333 begin
    334   if AKey = '' then Exit;
    335 
    336   index := IndexOf(AKey);
    337   pre := nil;
    338   entry := FTable[index];
    339   while entry <> nil do
    340   begin
    341     if (HashCode(entry.Key) = HashCode(AKey)) and SameText(entry.Key, AKey) then
    342     begin
    343       if pre = nil then
    344         FTable[index] := entry.Next
    345       else
    346         pre.Next := entry.Next;
    347 
    348       Dec(FCount);
    349       Exit;
    350     end;
    351     pre := entry;
    352     entry := entry.Next;
    353   end;
    354 end;
    355 
    356 
    357 function THashMap.ContainsKey(AKey: string): Boolean;
    358 begin
    359   Result := False;
    360   if AKey = '' then Exit;
    361   Result := GetEntry(aKey) <> nil;
    362 end;
    363 
    364 procedure THashMap.Clear;
    365 var
    366   I: Integer;
    367   firstEntry, pre, Entry: THashEntry;
    368 begin
    369   for I := 0 to Length(FTable) - 1 do
    370   begin
    371     firstEntry := FTable[I];
    372     if firstEntry <> nil then
    373     begin
    374       // 有链表
    375       pre := nil;
    376       entry := firstEntry.Next;
    377       while entry <> nil do
    378       begin
    379         pre := Entry;
    380         Entry := pre.Next;
    381         pre.Next := nil;
    382         FreeAndNil(pre);
    383       end;
    384       FreeAndNil(firstEntry);
    385       FTable[I] := nil;
    386     end;
    387   end;
    388 
    389   SetLength(FTable, 0);
    390   FCount := 0;
    391 end;
    392 
    393 function THashMap.ToString(): string;
    394 var
    395   I, iPadLeft: Integer;
    396   entry: THashEntry;
    397   sValue: string;
    398 begin                     
    399   if not Assigned(FTable) then Exit;
    400   Result := Format('Size: %d, capacity: %d, Resize: %d;'#10#13, [FCount, Length(FTable), FResize]);
    401   Result := Result + #13#10;
    402   for I := 0 to Length(FTable) - 1 do
    403   begin
    404     entry := FTable[I];
    405     if entry = nil then
    406       Result := Result + Format('a[%d] = nil'#13#10, [I])
    407     else
    408       Result := Result + Format('a[%d]  ', [I]);
    409 
    410     iPadLeft := Length(Format('a[%d]  ', [I])) + 1;
    411     while entry <> nil do
    412     begin
    413       case TVarData(entry.Value).VType of
    414         varString: sValue := '''' + entry.Value + '''';
    415       else
    416         sValue := VarToStrDef(entry.Value, '');
    417       end;
    418 
    419 
    420       if entry <> FTable[I] then
    421         Result := Result + DupeString(' ', iPadLeft) + ' -> ' + entry.Key + ' = ' +  sValue
    422       else
    423         Result := Result + entry.Key + ' = ' + sValue;
    424 
    425       entry := entry.Next;
    426       Result := Result + #13#10;
    427     end;
    428   end;
    429 end;
    430 
    431 function THashMap.ToList: TList;
    432 var
    433   I: Integer;
    434   e: THashEntry;
    435 begin
    436   Result := nil;
    437   if Length(FTable) = 0 then
    438   begin
    439     Exit;
    440   end;
    441 
    442   Result := TList.Create;
    443   for I := Low(FTable) to High(FTable) do
    444   begin
    445     e := FTable[I];
    446     while e <> nil do
    447     begin
    448       Result.Add(e);
    449       e := e.Next;
    450     end;
    451   end;
    452 end;
    453 
    454 function THashMap.GetEntrySet: TEntrySet;
    455 var
    456   I: Integer;
    457   e: THashEntry;
    458   aList: TList;
    459 begin
    460   Result := nil;
    461   if Length(FTable) = 0 then
    462   begin
    463     Exit;
    464   end;
    465 
    466   try
    467     // 1、先获取到数组和链表中所有Entry对象
    468     aList := ToList;
    469     // 2、把得到的Entry对象加入到TEntrySet中
    470     SetLength(Result, aList.Count);
    471     for I := 0 to aList.Count - 1 do
    472     begin
    473       Result[I] := aList[I];
    474     end;
    475   finally
    476     FreeAndNil(aList);
    477   end;
    478 end;
    479 
    480 procedure THashMap.Add(AMap: THashMap);
    481 var
    482   I: Integer;
    483   e: THashEntry;
    484   aSet: TEntrySet;
    485 begin
    486   aSet := AMap.GetEntrySet;
    487   for I := 0 to Length(aSet) - 1 do
    488   begin
    489     Add(aSet[I].Key, aSet[I].Value);
    490   end;
    491 end;
    492 
    493 // 插入对象
    494 procedure THashMap.AddObject(AKey: string; AValue: TObject);
    495 begin
    496   Add(AKey, Integer(AValue), True);
    497 end;
    498 
    499 function THashMap.GetObject(AKey: string): TObject;
    500 begin
    501   Result := TObject(Integer(Get(AKey)));
    502 end;
    503 
    504 
    505 // key排序
    506 function SortCompareByKey(Item1, Item2: Pointer): Integer;
    507 begin
    508   Result := AnsiCompareStr(THashEntry(item1).Key, THashEntry(Item2).Key);
    509 end;
    510 
    511 // Value排序
    512 function SortCompareByValue(Item1, Item2: Pointer): Integer;
    513 begin
    514   Result := AnsiCompareStr(THashEntry(item1).Value, THashEntry(Item2).Value);
    515 end;
    516 
    517 // KeyValue排序
    518 function SortCompareByKeyValue(Item1, Item2: Pointer): Integer;
    519 begin
    520   Result := AnsiCompareStr(THashEntry(item1).Key + VarToStrDef(THashEntry(item1).Value, '')
    521     , THashEntry(item2).Key + VarToStrDef(THashEntry(Item2).Value, ''));
    522 end;
    523 
    524 function THashMap.Sort(ASortType: TSortType): TEntrySet;
    525 var
    526   I: Integer;
    527   aSortCompare: TListSortCompare;
    528   aList: TList;
    529 begin
    530   aList := ToList;
    531   try
    532     case ASortType of
    533       stKey:
    534         aSortCompare := SortCompareByKey;
    535       stValue:
    536         aSortCompare := SortCompareByValue;
    537     else
    538       aSortCompare := SortCompareByKeyValue;
    539     end;
    540     aList.Sort(aSortCompare);
    541 
    542     SetLength(Result, aList.Count);
    543     for I := 0 to aList.Count - 1 do
    544     begin
    545       Result[I] := aList[I];
    546     end;
    547   finally
    548     FreeAndNil(aList);
    549   end;
    550 end;
    551 
    552 
    553 
    554 function THashMap.GetItems(Index: Integer): THashEntry;
    555 begin
    556   if (Index < 0) or (Index >= FCount) then
    557   begin
    558     Result := nil;
    559     Exit;
    560   end;
    561   Result := FTable[Index];  
    562 end;
    563 
    564 end.
     1 {*******************************************************}
     2 {                                                       }
     3 {       Delphi HashMap                                  }
     4 {                                                       }
     5 {       版权所有 (C) 2018 hsoft                          }
     6 {                                                       }
     7 {                                                       }
     8 { Author: MarkWu    Email: 77910086@qq.com              }
     9 { Date:   2018-01-02 14:17:00                           }
    10 { Desc:   HashMap                                       }
    11 {*******************************************************}
    12 
    13 unit uHashEntry;
    14 
    15 interface
    16 
    17 uses
    18   Variants;
    19 
    20 type
    21   THashEntry = class
    22   private
    23     FKey: string;
    24     FValue: Variant;
    25     FNext: THashEntry;
    26     FIsObj: Boolean;
    27     procedure SetValue(const Value: Variant);
    28     function GetValue: Variant;
    29   public
    30     constructor Create(AKey: string; AValue: Variant; ANext: THashEntry; AIsObj: Boolean = False);
    31 
    32     function ToString(): string;
    33     function HashCode: Integer;
    34 
    35     property Key: string read FKey write FKey;
    36     property Value: Variant read GetValue write SetValue;
    37     property Next: THashEntry read FNext write FNext;
    38     property IsObj: Boolean read FIsObj;
    39   end;
    40 
    41 implementation
    42 
    43 { THashEntry }
    44 
    45 constructor THashEntry.Create(AKey: string; AValue: Variant; ANext: THashEntry; AIsObj: Boolean);
    46 begin
    47   FKey := AKey;
    48   FValue := AValue;
    49   FIsObj := AIsObj;
    50   FNext  := ANext;
    51 end;
    52 
    53 function THashEntry.HashCode: Integer;
    54 begin
    55   Result := Integer(Self);
    56 end;
    57 
    58 function THashEntry.GetValue: Variant;
    59 begin
    60   Result := FValue;
    61 end;
    62 
    63 procedure THashEntry.SetValue(const Value: Variant);
    64 begin
    65   FValue := Value;
    66 end;
    67 
    68 function THashEntry.ToString: string;
    69 begin
    70   Result := FKey + '=' + VarToStrDef(FValue, '');
    71 end;
    72 
    73 end.

    测试效果图

     

     HashMap, StringList, HashedStringList的性能比较, HashMap的性能比较稳定,保持O(1), 而HashedStringList第1次查找时很慢,后面就稳定了,不知啥原因,没有去跟踪它代码。

    测试程序源码:

    object Form1: TForm1
      Left = 263
      Top = 169
      Width = 787
      Height = 518
      Caption = 'HashMap Demo -- Author: MarkWu  QQ:77910086'
      Color = clBtnFace
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -11
      Font.Name = 'MS Sans Serif'
      Font.Style = []
      OldCreateOrder = False
      OnCreate = FormCreate
      PixelsPerInch = 96
      TextHeight = 13
      object Label1: TLabel
        Left = 237
        Top = 90
        Width = 18
        Height = 13
        Caption = 'Key'
      end
      object Label2: TLabel
        Left = 237
        Top = 119
        Width = 27
        Height = 13
        Caption = 'Value'
      end
      object Label3: TLabel
        Left = 231
        Top = 168
        Width = 34
        Height = 13
        Caption = 'Serach'
      end
      object Label4: TLabel
        Left = 240
        Top = 348
        Width = 14
        Height = 13
        Caption = 'N: '
      end
      object Label5: TLabel
        Left = 365
        Top = 347
        Width = 17
        Height = 13
        Caption = 'Get'
      end
      object Button1: TButton
        Left = 257
        Top = 11
        Width = 75
        Height = 25
        Caption = #21021#22987#21270'Map'
        TabOrder = 2
        OnClick = Button1Click
      end
      object Memo1: TMemo
        Left = 0
        Top = 0
        Width = 225
        Height = 480
        Align = alLeft
        ScrollBars = ssVertical
        TabOrder = 0
      end
      object Button2: TButton
        Left = 364
        Top = 163
        Width = 75
        Height = 25
        Caption = 'Get'
        TabOrder = 8
        OnClick = Button2Click
      end
      object Edit1: TEdit
        Left = 268
        Top = 164
        Width = 85
        Height = 21
        TabOrder = 9
      end
      object Button3: TButton
        Left = 364
        Top = 97
        Width = 75
        Height = 25
        Caption = 'Put'
        TabOrder = 6
        OnClick = Button3Click
      end
      object edt_key: TEdit
        Left = 268
        Top = 85
        Width = 85
        Height = 21
        TabOrder = 5
      end
      object edt_value: TEdit
        Left = 268
        Top = 117
        Width = 85
        Height = 21
        TabOrder = 7
      end
      object Button4: TButton
        Left = 364
        Top = 11
        Width = 75
        Height = 25
        Caption = 'Destory Map'
        TabOrder = 3
        OnClick = Button4Click
      end
      object btnSortKey: TButton
        Left = 241
        Top = 236
        Width = 97
        Height = 25
        Caption = 'Sort Key'
        TabOrder = 12
        OnClick = btnSortKeyClick
      end
      object PutMap: TButton
        Left = 241
        Top = 203
        Width = 97
        Height = 25
        Caption = 'PutMap'
        TabOrder = 10
        OnClick = PutMapClick
      end
      object Button5: TButton
        Left = 257
        Top = 51
        Width = 184
        Height = 25
        Caption = #25171#21360'Map'#20869#23481
        TabOrder = 4
        OnClick = Button5Click
      end
      object btnSortValue: TButton
        Left = 241
        Top = 270
        Width = 97
        Height = 25
        Caption = 'Sort Value'
        TabOrder = 13
        OnClick = btnSortValueClick
      end
      object btnSortKeyValue: TButton
        Left = 241
        Top = 303
        Width = 97
        Height = 25
        Caption = 'Sort KeyValue'
        TabOrder = 14
        OnClick = btnSortKeyValueClick
      end
      object btnHashMap10000: TButton
        Left = 241
        Top = 379
        Width = 122
        Height = 25
        Caption = 'HashMap '#22686#21152'N'#26465
        TabOrder = 17
        OnClick = btnHashMap10000Click
      end
      object btnStringList10000: TButton
        Left = 241
        Top = 408
        Width = 122
        Height = 25
        Caption = 'StringList '#22686#21152'N'#26465
        TabOrder = 19
        OnClick = btnStringList10000Click
      end
      object edt_N: TEdit
        Left = 259
        Top = 345
        Width = 104
        Height = 21
        TabOrder = 15
        Text = '10000'
      end
      object btn_hashMap_get: TButton
        Left = 373
        Top = 379
        Width = 100
        Height = 25
        Caption = 'hashMap_get'
        TabOrder = 18
        OnClick = btn_hashMap_getClick
      end
      object btn_stringList_get: TButton
        Left = 373
        Top = 408
        Width = 100
        Height = 25
        Caption = 'stringList_get'
        TabOrder = 20
        OnClick = btn_stringList_getClick
      end
      object edt_Get: TEdit
        Left = 387
        Top = 345
        Width = 104
        Height = 21
        TabOrder = 16
      end
      object Button6: TButton
        Left = 364
        Top = 203
        Width = 75
        Height = 25
        Caption = 'AddObject'
        TabOrder = 11
        OnClick = Button6Click
      end
      object Panel1: TPanel
        Left = 504
        Top = 0
        Width = 267
        Height = 480
        Align = alRight
        BevelOuter = bvNone
        TabOrder = 1
        object Label6: TLabel
          Left = 0
          Top = 0
          Width = 267
          Height = 16
          Align = alTop
          Caption = 'HashMap'#20869#23384#20998#24067
        end
        object Memo2: TMemo
          Left = 0
          Top = 16
          Width = 267
          Height = 464
          Align = alClient
          ScrollBars = ssVertical
          TabOrder = 0
        end
      end
      object btn_HashStringList1000: TButton
        Left = 241
        Top = 439
        Width = 122
        Height = 25
        Caption = 'HashStringList '#22686#21152'N'#26465
        TabOrder = 21
        OnClick = btn_HashStringList1000Click
      end
      object btn_HashStringList_get: TButton
        Left = 373
        Top = 439
        Width = 100
        Height = 25
        Caption = 'HashStringList_Get'
        TabOrder = 22
        OnClick = btn_HashStringList_getClick
      end
    end
    {*******************************************************}
    {                                                       }
    {       Delphi HashMap test                             }
    {                                                       }
    {       版权所有 (C) 2018 hsoft                        }
    {                                                        }
    {                                                       }
    { Author: MarkWu    Email: 77910086@qq.com                }
    { Date:   2018-01-02 14:17:00                           }
    { Desc:   HashMap                                       }
    {*******************************************************}
    
    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, uHashMap, StdCtrls, StrUtils, ExtCtrls, IniFiles;
    
    type
      TForm1 = class(TForm)
        Button1: TButton;
        Memo1: TMemo;
        Button2: TButton;
        Edit1: TEdit;
        Button3: TButton;
        edt_key: TEdit;
        edt_value: TEdit;
        Label1: TLabel;
        Label2: TLabel;
        Label3: TLabel;
        Button4: TButton;
        btnSortKey: TButton;
        PutMap: TButton;
        Button5: TButton;
        btnSortValue: TButton;
        btnSortKeyValue: TButton;
        btnHashMap10000: TButton;
        btnStringList10000: TButton;
        Label4: TLabel;
        edt_N: TEdit;
        btn_hashMap_get: TButton;
        btn_stringList_get: TButton;
        Label5: TLabel;
        edt_Get: TEdit;
        Button6: TButton;
        Panel1: TPanel;
        Label6: TLabel;
        Memo2: TMemo;
        btn_HashStringList1000: TButton;
        btn_HashStringList_get: TButton;
        procedure Button1Click(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure Button2Click(Sender: TObject);
        procedure Button3Click(Sender: TObject);
        procedure Button4Click(Sender: TObject);
        procedure btnSortKeyClick(Sender: TObject);
        procedure PutMapClick(Sender: TObject);
        procedure Button5Click(Sender: TObject);
        procedure btnSortValueClick(Sender: TObject);
        procedure btnSortKeyValueClick(Sender: TObject);
        procedure btnHashMap10000Click(Sender: TObject);
        procedure btnStringList10000Click(Sender: TObject);
        procedure btn_hashMap_getClick(Sender: TObject);
        procedure btn_stringList_getClick(Sender: TObject);
        procedure Button6Click(Sender: TObject);
        procedure btn_HashStringList1000Click(Sender: TObject);
        procedure btn_HashStringList_getClick(Sender: TObject);
    
      private
        { Private declarations }
        aHashMap: THashMap;
    
        FMap: THashMap;
        FList: TStringList;
        FHashList: THashedStringList;
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    uses uHashEntry;
    
    {$R *.dfm}
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      aHashMap := THashMap.Create;
    
      FMap := THashMap.Create;
      FList := TStringList.Create;
      FHashList := THashedStringList.Create;
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      //caption :=  IntToStr(aHashMap.HashCode('123'));
      //caption :=  IntToStr(5 mod 3);
      aHashMap.Add('中国', '中华人民共和国');
      aHashMap.Add('中國', '中華人民共和國');
      aHashMap.Add('吴wu', 'MarkWu');
      aHashMap.Add('b', 2);
      aHashMap.Add('c', 3);
      aHashMap.Add('d', 'dd');
      aHashMap.Add('e', 'ee');
      aHashMap.Add('f', 'ff');
      aHashMap.Add('g', 'ggg');
      aHashMap.Add('h', 11.1);
      aHashMap.Add('i', 22.2);
      aHashMap.Add('j', 33.3);
      aHashMap.Add('k', 44.4);
      aHashMap.Add('l', True);
    
      aHashMap.Add('aa', 'a1');
      aHashMap.Add('ca', 'c2');
    
      aHashMap.Add('', '0000000000');
      aHashMap.Add('', '1111111111');
     // aHashMap.Put('m', VarArrayOf([1, 2, 'a', 'b']));
    
      Memo1.Lines.Add(aHashMap.ToString);
    end;
    
    procedure TForm1.Button2Click(Sender: TObject);
    var
      I: Integer;
      aMap: THashMap;
      aSet: TEntrySet;
    begin
    {  aMap := THashMap.Create;
      aMap.Put('h1', 'h1');
      aMap.Put('h2', 2);
      aMap.Put('h3', 33);
      aMap.Put('中1', 81);
      aMap.Put('中2', 82);
      aMap.Put('中2', 83);
    
      aMap.Put(aHashMap);
    }
      //Memo2.Lines.Add(aMap.ToString);
      Memo2.Lines.Add('---------------Get-----------------');
      Memo2.Lines.Add(VarToStrDef( aHashMap.Get(Edit1.Text), ''));
    
      //aMap.Free;
    end;
    
    procedure TForm1.Button3Click(Sender: TObject);
    begin
      aHashMap.Add(edt_key.Text, edt_value.Text);
    end;
    
    procedure TForm1.Button4Click(Sender: TObject);
    begin
      FreeAndNil(aHashMap);
    end;
    
    procedure TForm1.btnSortKeyClick(Sender: TObject);
    var
      I: Integer;
      aSet: TEntrySet;
    begin
      Memo2.Lines.Add('---------------Sort Key-----------------');
      aSet := aHashMap.Sort(stKey);
      for I := 0 to Length(aSet) - 1 do
      begin
        Memo2.Lines.Add(aSet[I].Key + '=' + VarToStrDef(aSet[I].Value, 'NULL') );
      end;
    end;
    
    procedure TForm1.btnSortValueClick(Sender: TObject);
    var
      I: Integer;
      aSet: TEntrySet;
    begin
      Memo2.Lines.Add('---------------Sort Value-----------------');
      aSet := aHashMap.Sort(stValue);
      for I := 0 to Length(aSet) - 1 do
      begin
        Memo2.Lines.Add(aSet[I].Key + '=' + VarToStrDef(aSet[I].Value, 'NULL') );
      end;
    end;
    
    procedure TForm1.btnSortKeyValueClick(Sender: TObject);
    var
      I: Integer;
      aSet: TEntrySet;
    begin
      Memo2.Lines.Add('---------------Sort KeyValue-----------------');
      aSet := aHashMap.Sort(stKeyValue);
      for I := 0 to Length(aSet) - 1 do
      begin
        Memo2.Lines.Add(aSet[I].Key + '=' + VarToStrDef(aSet[I].Value, 'NULL') );
      end;
    end;
    
    
    procedure TForm1.PutMapClick(Sender: TObject);
    var
      I: Integer;
      aMap: THashMap;
      aSet: TEntrySet;
    begin
      aMap := THashMap.Create;
      aMap.Add('h1', 'h1');
      aMap.Add('h2', 2);
      aMap.Add('h3', 33);
      aMap.Add('中1', 81);
      aMap.Add('中2', 82);
      aMap.Add('中2', 83);
      //aMap.Put(aHashMap);
      aHashMap.Add(aMap);
    
      //Memo2.Lines.Add(aMap.ToString);
    
       Memo2.Lines.Add('-------------------PutMap-------------------');
      aSet := aHashMap.GetEntrySet;
      for I := 0 to Length(aSet) - 1 do
      begin
        Memo2.Lines.Add(aSet[I].Key + '=' + VarToStrDef(aSet[I].Value, '') );
      end;
      aMap.Free;
    end;
    
    procedure TForm1.Button5Click(Sender: TObject);
    begin
      Memo2.Lines.Add('------------------ToString----------------------');
      Memo2.Lines.Add(aHashMap.ToString);
    end;
    
    
    
    procedure TForm1.btnHashMap10000Click(Sender: TObject);
    var
      I: Integer;
      iBegin, iEnd: Cardinal;
      map: THashMap;
    begin
      FMap.Clear;
      iBegin := GetTickCount;
      map := FMap;
      for I := 0 to StrToInt(edt_N.Text) - 1 do
      begin
        map.Add( IntToStr(I), I);   //'m' +
      end;
      iEnd := (GetTickCount - iBegin);
    
      Memo2.Lines.Add(Format('-------------------- %s ToString--------------------', [btnHashMap10000.Caption]));
      Memo2.Lines.Add(Format('HashMap 增加%d条, 总共花了%d ms', [StrToIntDef(edt_N.Text, 1), iEnd]));
      //Memo2.Lines.Add(map.ToString);
    end;
    
    procedure TForm1.btnStringList10000Click(Sender: TObject);
    var
      I: Integer;
      iBegin, iEnd: Cardinal;
      str: string;
      aList: TStringList;
    begin
      FList.Clear;
      iBegin := GetTickCount;
      aList := FList; //TStringList.Create;
      for I := 0 to StrToInt(edt_N.Text) -1 do
      begin
        aList.Add( IntToStr(I) + '=' + IntToStr(I));
      end;
      iEnd := GetTickCount - iBegin;
    
      Memo2.Lines.Add(Format('-------------------- %s ToString--------------------', [btnStringList10000.Caption]));
      //Memo2.Lines.Add(btnStringList10000.Caption + ' 总共花了' + Inttostr(iEnd));
      Memo2.Lines.Add(Format('StringList 增加%d条, 总共花了%d ms', [StrToIntDef(edt_N.Text, 1), iEnd]));
    
      {
      str := '';
      for I := 0 to aList.Count - 1 do
      begin
        str := str + #13#10 + aList[I];
      end;
      Memo2.Lines.Add(str);
      }
    end;
    
    procedure TForm1.btn_hashMap_getClick(Sender: TObject);
    var
      iBegin, iEnd: Cardinal;
      sValue: string;
    begin
      try
        if Trim(edt_Get.Text) = '' then
        begin
          if edt_Get.CanFocus then edt_Get.SetFocus;
          ShowMessage('请输入要查询的key');
          Abort;
        end;
        iBegin := GetTickCount;
        sValue := FMap.Get(edt_Get.Text);
        iEnd := GetTickCount - iBegin;
        Memo2.Lines.Add('------------------hashMap Get-----------------');
        Memo2.Lines.Add(sValue + '--->' + IntToStr(iEnd) + 'ms');
      except
    
      end;
    end;
    
    procedure TForm1.btn_stringList_getClick(Sender: TObject);
    var
      iBegin, iEnd: Cardinal;
      sValue: string;
    begin
      try
        if Trim(edt_Get.Text) = '' then
        begin
          if edt_Get.CanFocus then edt_Get.SetFocus;
          ShowMessage('请输入要查询的key');
          Abort;
        end;
        iBegin := GetTickCount;
        sValue := FList.Values[edt_Get.Text]; //FList.ValueFromIndex(Flist.);
        iEnd := GetTickCount - iBegin;
        Memo2.Lines.Add('------------------StringList Get-----------------');
        Memo2.Lines.Add(sValue + '--->' + IntToStr(iEnd) + 'ms');
      except
    
      end;
    end;
    
    procedure TForm1.Button6Click(Sender: TObject);
    var
      v: Variant;
      map: THashMap;
    begin
      //map := THashMap.Create;
      map := aHashMap;
      try
        v := Integer(Self);
        map.AddObject('form1', Self);
        //ShowMessage(map.Get('form1').Value);
    
        ShowMessage(TForm1(map.GetObject('form1')).Caption);
      finally
        //FreeAndNil(map);
      end;
    end;
    
    procedure TForm1.btn_HashStringList1000Click(Sender: TObject);
    var
      I: Integer;
      iBegin, iEnd: Cardinal;
      str: string;
      aList: THashedStringList;
    begin
      FHashList.Clear;
      iBegin := GetTickCount;
      aList := FHashList; //TStringList.Create;
      for I := 0 to StrToInt(edt_N.Text) -1 do
      begin
        aList.Add(IntToStr(I) + '=' + IntToStr(I));
      end;
      iEnd := GetTickCount - iBegin;
    
      Memo2.Lines.Add(Format('-------------------- %s ToString--------------------', [btn_HashStringList1000.Caption]));
      //Memo2.Lines.Add(btnStringList10000.Caption + ' 总共花了' + Inttostr(iEnd));
      Memo2.Lines.Add(Format('HashStringList 增加%d条, 总共花了%d ms', [StrToIntDef(edt_N.Text, 1), iEnd]));
    
      {
      str := '';
      for I := 0 to aList.Count - 1 do
      begin
        str := str + #13#10 + aList[I];
      end;
      Memo2.Lines.Add(str);
      }
    end;
    
    procedure TForm1.btn_HashStringList_getClick(Sender: TObject);
    var
      iBegin, iEnd: Cardinal;
      sValue: string;
    begin
      try
        if Trim(edt_Get.Text) = '' then
        begin
          if edt_Get.CanFocus then edt_Get.SetFocus;
          ShowMessage('请输入要查询的key');
          Abort;
        end;
        iBegin := GetTickCount;
        sValue := FHashList.Values[edt_Get.Text];
        //sValue := FHashList.ValueFromIndex[ FHashList.IndexOfName(edt_Get.Text) ];
        iEnd := GetTickCount - iBegin;
        Memo2.Lines.Add('------------------HashedStringList Get-----------------');
        Memo2.Lines.Add(sValue + '--->' + IntToStr(iEnd) + 'ms');
      except
    
      end;
    end;
    
    end.
  • 相关阅读:
    ABP(现代ASP.NET样板开发框架)系列之4、ABP模块系统
    ABP(现代ASP.NET样板开发框架)系列之3、ABP分层架构
    ABP(现代ASP.NET样板开发框架)系列之2、ABP入门教程
    ABP(现代ASP.NET样板开发框架)系列之1、ABP总体介绍
    基于DDD的现代ASP.NET开发框架--ABP系列文章总目录
    参加博客园DDD交流会的情况和感想
    新思想、新技术、新架构——更好更快的开发现代ASP.NET应用程序(续1)
    【python】使用openpyxl解析json并写入excel(xlsx)
    [leetcode]multiply-strings java代码
    线性回归,感知机,逻辑回归(GD,SGD)
  • 原文地址:https://www.cnblogs.com/markwu/p/13601095.html
Copyright © 2020-2023  润新知