CnDockHashTable.pas 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. {******************************************************************************}
  2. { CnPack For Delphi/C++Builder }
  3. { 中国人自己的开放源码第三方开发包 }
  4. { (C)Copyright 2001-2018 CnPack 开发组 }
  5. { ------------------------------------ }
  6. { }
  7. { 本开发包是开源的自由软件,您可以遵照 CnPack 的发布协议来修 }
  8. { 改和重新发布这一程序。 }
  9. { }
  10. { 发布这一开发包的目的是希望它有用,但没有任何担保。甚至没有 }
  11. { 适合特定目的而隐含的担保。更详细的情况请参阅 CnPack 发布协议。 }
  12. { }
  13. { 您应该已经和开发包一起收到一份 CnPack 发布协议的副本。如果 }
  14. { 还没有,可访问我们的网站: }
  15. { }
  16. { 网站地址:http://www.cnpack.org }
  17. { 电子邮件:master@cnpack.org }
  18. { }
  19. {******************************************************************************}
  20. unit CnDockHashTable;
  21. {* |<PRE>
  22. ================================================================================
  23. * 软件名称:不可视工具组件包停靠单元
  24. * 单元名称:用于停靠的HashTable单元
  25. * 单元作者:CnPack开发组 周益波(鲁小班)
  26. * 备 注:本单元由原作者授权CnPack开发组移植,已保留原作者版权信息
  27. * 开发平台:
  28. * 兼容测试:PWin9X/2000/XP + Delphi 5/6/7
  29. * 本 地 化:该单元中的字符串均符合本地化处理方式
  30. * 单元标识:$Id$
  31. * 修改记录:2007.07.13 V1.0
  32. * 移植单元
  33. ================================================================================
  34. |</PRE>}
  35. interface
  36. {$I CnPack.inc}
  37. uses
  38. Classes, Controls;
  39. const DefaultHashSize = 20;
  40. type
  41. { 散列的节点类 }
  42. TCnDockClientHashNode = class
  43. private
  44. FKeyName: string; //名字项
  45. FKeyData: Pointer; //数据
  46. FPrevNode, //上一个指针
  47. FNextNode: TCnDockClientHashNode; //下一个指针
  48. FListIndex: Integer; //属于哪个桶
  49. public
  50. property KeyName: string read FKeyName write FKeyName;
  51. property KeyData: Pointer read FKeyData write FKeyData;
  52. property PrevNode: TCnDockClientHashNode
  53. read FPrevNode write FPrevNode;
  54. property NextNode: TCnDockClientHashNode
  55. read FNextNode write FNextNode;
  56. property ListIndex: Integer read FListIndex write FListIndex;
  57. end;
  58. { 散列类 }
  59. TCnDockControlHashTable = class
  60. private
  61. FCurrentSize, //当前桶数
  62. FTableSize: Integer; //最大桶数
  63. FEntryList: TList; //桶队列
  64. FRiseException: Boolean; //当查找到相同的名字时是否触发异常
  65. procedure SetTableSize(const Value: Integer); //为散列表分配空间
  66. protected
  67. function HashProc(Name: string): Integer; virtual;//散列函数,计算Name的初始桶号
  68. procedure DeleteListIndex(Index: Integer); //删除索引为Index的桶
  69. function CreateKeyNode(KeyName: string; KeyData: Pointer;
  70. ListIndex: Integer): TCnDockClientHashNode; //创建散列节点
  71. function CompareKey(Key1, Key2: string): Integer; //比较两个节点
  72. public
  73. constructor Create(Size: Integer = DefaultHashSize; RiseExcept: Boolean = True); virtual;
  74. destructor Destroy; override;
  75. procedure CreateDictionary(Size: Integer); virtual;//创建字典
  76. function IsIn(Name: string): Boolean; virtual; //判断Name是否在字典中
  77. function FindNode(Name: string): TCnDockClientHashNode; virtual;//查找节点
  78. function Find(Name: string): Pointer; virtual; //查找
  79. function Insert(Name: string; Data: Pointer): Integer; virtual;//插入
  80. procedure Remove(Name: string); virtual; //删除
  81. procedure MakeEmpty; //置散列表为空
  82. property CurrentSize: Integer read FCurrentSize;
  83. property TableSize: Integer read FTableSize write SetTableSize;
  84. end;
  85. implementation
  86. uses
  87. CnDockGlobal, SysUtils;
  88. { TCnDockControlHashTable }
  89. function TCnDockControlHashTable.CompareKey(Key1, Key2: string): Integer;
  90. begin
  91. Result := AnsiStrComp(PChar(Key1), PChar(Key2));
  92. end;
  93. constructor TCnDockControlHashTable.Create(Size: Integer; RiseExcept: Boolean);
  94. begin
  95. { 首先创建桶 }
  96. CreateDictionary(Size);
  97. FRiseException := RiseExcept;
  98. end;
  99. procedure TCnDockControlHashTable.CreateDictionary(Size: Integer);
  100. begin
  101. FEntryList := TList.Create;
  102. FEntryList.Count := Size;
  103. FTableSize := Size;
  104. end;
  105. function TCnDockControlHashTable.CreateKeyNode(KeyName: string;
  106. KeyData: Pointer; ListIndex: Integer): TCnDockClientHashNode;
  107. begin
  108. Result := TCnDockClientHashNode.Create;
  109. Result.KeyName := KeyName;
  110. Result.KeyData := KeyData;
  111. Result.ListIndex := ListIndex;
  112. end;
  113. procedure TCnDockControlHashTable.DeleteListIndex(Index: Integer);
  114. var Node, NextNode: TCnDockClientHashNode;
  115. begin
  116. Node := FEntryList[Index];
  117. while Node <> nil do
  118. begin
  119. NextNode := Node.NextNode;
  120. Node.Free;
  121. Node := NextNode;
  122. end;
  123. FEntryList.Delete(Index);
  124. end;
  125. destructor TCnDockControlHashTable.Destroy;
  126. begin
  127. MakeEmpty;
  128. FEntryList.Free;
  129. inherited;
  130. end;
  131. function TCnDockControlHashTable.Find(Name: string): Pointer;
  132. var Node: TCnDockClientHashNode;
  133. begin
  134. Node := FindNode(Name);
  135. if Node <> nil then
  136. Result := Node.KeyData
  137. else Result := nil;
  138. end;
  139. function TCnDockControlHashTable.FindNode(
  140. Name: string): TCnDockClientHashNode;
  141. var Value: Integer;
  142. ListIndex: Integer;
  143. begin
  144. ListIndex := HashProc(Name);
  145. Assert((ListIndex >= 0) and (ListIndex < FTableSize), gs_CnTableIndexError);
  146. Result := FEntryList[ListIndex];
  147. if Result = nil then Exit;
  148. repeat
  149. Value := CompareKey(Name, Result.FKeyName);
  150. if Value = 0 then Exit;
  151. Result := Result.FNextNode;
  152. until Result = nil;
  153. end;
  154. function TCnDockControlHashTable.HashProc(Name: string): Integer;
  155. var i: Integer;
  156. begin
  157. Result := 0;
  158. for i := 1 to Length(Name) do
  159. Inc(Result, Ord(Name[i]));
  160. Result := Result mod FTableSize;
  161. end;
  162. function TCnDockControlHashTable.Insert(Name: string;
  163. Data: Pointer): Integer;
  164. var Index: Integer;
  165. Value: Integer;
  166. Node, ParentNode: TCnDockClientHashNode;
  167. begin
  168. Result := -1;
  169. Index := HashProc(Name);
  170. Assert((Index >= 0) and (Index < FTableSize), gs_CnTableIndexError);
  171. { 首先查找在桶里面是否有数据 }
  172. if FEntryList[Index] = nil then
  173. FEntryList[Index] := CreateKeyNode(Name, Data, Index)
  174. else
  175. begin
  176. Node := FEntryList[Index];
  177. repeat
  178. { 判断在散列里面是否有相同的键值 }
  179. Value := CompareKey(Name, Node.FKeyName);
  180. { 触发异常 }
  181. if FRiseException then
  182. Assert(Value <> 0, gs_CnNodeExistedError)
  183. else if Value = 0 then
  184. Exit;
  185. ParentNode := Node;
  186. Node := Node.FNextNode;
  187. until Node = nil;
  188. { 创建节点 }
  189. Node := CreateKeyNode(Name, Data, Index);
  190. Node.FPrevNode := ParentNode;
  191. ParentNode.NextNode := Node;
  192. end;
  193. Result := Index;
  194. end;
  195. function TCnDockControlHashTable.IsIn(Name: string): Boolean;
  196. begin
  197. Result := FindNode(Name) <> nil;
  198. end;
  199. procedure TCnDockControlHashTable.MakeEmpty;
  200. var i: Integer;
  201. begin
  202. for i := FEntryList.Count - 1 downto 0 do
  203. DeleteListIndex(i);
  204. end;
  205. procedure TCnDockControlHashTable.Remove(Name: string);
  206. var Node: TCnDockClientHashNode;
  207. begin
  208. Node := FindNode(Name);
  209. if Node <> nil then
  210. begin
  211. if Node.FPrevNode <> nil then
  212. Node.FPrevNode.FNextNode := Node.FNextNode
  213. else FEntryList[Node.ListIndex] := Node.FNextNode;
  214. if Node.FNextNode <> nil then
  215. Node.FNextNode.FPrevNode := Node.FPrevNode;
  216. Node.Free;
  217. end;
  218. end;
  219. procedure TCnDockControlHashTable.SetTableSize(const Value: Integer);
  220. begin
  221. FEntryList.Count := Value;
  222. end;
  223. end.