dbf_avl.pas 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. unit dbf_avl;
  2. interface
  3. {$I dbf_common.inc}
  4. uses
  5. Dbf_Common;
  6. type
  7. TBal = -1..1;
  8. TAvlTree = class;
  9. TKeyType = Cardinal;
  10. TExtraData = Pointer;
  11. PData = ^TData;
  12. TData = record
  13. ID: TKeyType;
  14. ExtraData: TExtraData;
  15. end;
  16. PNode = ^TNode;
  17. TNode = record
  18. Data: TData;
  19. Left: PNode;
  20. Right: PNode;
  21. Bal: TBal; // balance factor: h(Right) - h(Left)
  22. end;
  23. TAvlTreeEvent = procedure(Sender: TAvlTree; Data: PData) of object;
  24. TAvlTree = class(TObject)
  25. private
  26. FRoot: PNode;
  27. FCount: Cardinal;
  28. FOnDelete: TAvlTreeEvent;
  29. FHeightChange: Boolean;
  30. procedure InternalInsert(X: PNode; var P: PNode);
  31. procedure InternalDelete(X: TKeyType; var P: PNode);
  32. procedure DeleteNode(X: PNode);
  33. procedure TreeDispose(X: PNode);
  34. public
  35. constructor Create;
  36. destructor Destroy; override;
  37. procedure Clear;
  38. function Find(Key: TKeyType): TExtraData;
  39. procedure Insert(Key: TKeyType; Extra: TExtraData);
  40. procedure Delete(Key: TKeyType);
  41. function Lowest: PData;
  42. property Count: Cardinal read FCount;
  43. property OnDelete: TAvlTreeEvent read FOnDelete write FOnDelete;
  44. end;
  45. implementation
  46. uses
  47. Math;
  48. procedure RotL(var P: PNode);
  49. var
  50. P1: PNode;
  51. begin
  52. P1 := P^.Right;
  53. P^.Right := P1^.Left;
  54. P1^.Left := P;
  55. P := P1;
  56. end;
  57. procedure RotR(var P: PNode);
  58. var
  59. P1: PNode;
  60. begin
  61. P1 := P^.Left;
  62. P^.Left := P1^.Right;
  63. P1^.Right := P;
  64. P := P1;
  65. end;
  66. function Height(X: PNode): Integer;
  67. begin
  68. if X = nil then
  69. Result := 0
  70. else
  71. Result := 1+Max(Height(X^.Left), Height(X^.Right));
  72. end;
  73. function CheckTree_T(X: PNode; var H: Integer): Boolean;
  74. var
  75. HR: Integer;
  76. begin
  77. if X = nil then
  78. begin
  79. Result := true;
  80. H := 0;
  81. end else begin
  82. Result := CheckTree_T(X^.Left, H) and CheckTree_T(X^.Right, HR) and
  83. ((X^.Left = nil) or (X^.Left^.Data.ID < X^.Data.ID)) and
  84. ((X^.Right = nil) or (X^.Right^.Data.ID > X^.Data.ID)) and
  85. // ((Height(X^.Right) - Height(X^.Left)) = X^.Bal);
  86. (HR - H = X^.Bal);
  87. H := 1 + Max(H, HR);
  88. end;
  89. end;
  90. function CheckTree(X: PNode): Boolean;
  91. var
  92. H: Integer;
  93. begin
  94. Result := CheckTree_T(X, H);
  95. end;
  96. procedure BalanceLeft(var P: PNode; var HeightChange: Boolean);
  97. var
  98. B1, B2: TBal;
  99. {HeightChange = true, left branch has become less high}
  100. begin
  101. case P^.Bal of
  102. -1: begin P^.Bal := 0 end;
  103. 0: begin P^.Bal := 1; HeightChange := false end;
  104. 1: begin {Rebalance}
  105. B1 := P^.Right^.Bal;
  106. if B1 >= 0
  107. then {single L rotation}
  108. begin
  109. RotL(P);
  110. //adjust balance factors:
  111. if B1 = 0
  112. then
  113. begin P^.Bal :=-1; P^.Left^.Bal := 1; HeightChange := false end
  114. else
  115. begin P^.Bal := 0; P^.Left^.Bal := 0 end;
  116. end
  117. else {double RL rotation}
  118. begin
  119. B2 := P^.Right^.Left^.Bal;
  120. RotR(P^.Right);
  121. RotL(P);
  122. //adjust balance factors:
  123. if B2=+1 then P^.Left^.Bal := -1 else P^.Left^.Bal := 0;
  124. if B2=-1 then P^.Right^.Bal := 1 else P^.Right^.Bal := 0;
  125. P^.Bal := 0;
  126. end;
  127. end;{1}
  128. end{case}
  129. end;{BalanceLeft}
  130. procedure BalanceRight(var P: PNode; var HeightChange: Boolean);
  131. var
  132. B1, B2: TBal;
  133. {HeightChange = true, right branch has become less high}
  134. begin
  135. case P^.Bal of
  136. 1: begin P^.Bal := 0 end;
  137. 0: begin P^.Bal := -1; HeightChange := false end;
  138. -1: begin {Rebalance}
  139. B1 := P^.Left^.Bal;
  140. if B1 <= 0
  141. then {single R rotation}
  142. begin
  143. RotR(P);
  144. //adjust balance factors}
  145. if B1 = 0
  146. then
  147. begin P^.Bal :=1; P^.Right^.Bal :=-1; HeightChange:= false end
  148. else
  149. begin P^.Bal := 0; P^.Right^.Bal := 0 end;
  150. end
  151. else {double LR rotation}
  152. begin
  153. B2 := P^.Left^.Right^.Bal;
  154. RotL(P^.Left);
  155. RotR(P);
  156. //adjust balance factors
  157. if B2=-1 then P^.Right^.Bal := 1 else P^.Right^.Bal := 0;
  158. if B2= 1 then P^.Left^.Bal := -1 else P^.Left^.Bal := 0;
  159. P^.Bal := 0;
  160. end;
  161. end;{-1}
  162. end{case}
  163. end;{BalanceRight}
  164. procedure DelRM(var R: PNode; var S: PNode; var HeightChange: Boolean);
  165. // Make S refer to rightmost element of tree with root R;
  166. // Remove that element from the tree
  167. begin
  168. if R^.Right = nil then
  169. begin S := R; R := R^.Left; HeightChange := true end
  170. else
  171. begin
  172. DelRM(R^.Right, S, HeightChange);
  173. if HeightChange then BalanceRight(R, HeightChange)
  174. end
  175. end;
  176. //---------------------------------------
  177. //---****--- Class TAvlTree ---*****-----
  178. //---------------------------------------
  179. constructor TAvlTree.Create;
  180. begin
  181. inherited;
  182. FRoot := nil;
  183. end;
  184. destructor TAvlTree.Destroy;
  185. begin
  186. Clear;
  187. inherited;
  188. end;
  189. procedure TAvlTree.Clear;
  190. begin
  191. TreeDispose(FRoot);
  192. FRoot := nil;
  193. end;
  194. procedure TAvlTree.DeleteNode(X: PNode);
  195. begin
  196. // delete handler installed?
  197. if Assigned(FOnDelete) then
  198. FOnDelete(Self, @X^.Data);
  199. // dispose of memory
  200. Dispose(X);
  201. Dec(FCount);
  202. end;
  203. procedure TAvlTree.TreeDispose(X: PNode);
  204. var
  205. P: PNode;
  206. begin
  207. // nothing to dispose of?
  208. if X = nil then
  209. exit;
  210. // use in-order visiting, maybe someone likes sequential ordering
  211. TreeDispose(X^.Left);
  212. P := X^.Right;
  213. // free mem
  214. DeleteNode(X);
  215. // free right child
  216. TreeDispose(P);
  217. end;
  218. function TAvlTree.Find(Key: TKeyType): TExtraData;
  219. var
  220. H: PNode;
  221. begin
  222. H := FRoot;
  223. while (H <> nil) and (H^.Data.ID <> Key) do // use conditional and
  224. if Key < H^.Data.ID then
  225. H := H^.Left
  226. else
  227. H := H^.Right;
  228. if H <> nil then
  229. Result := H^.Data.ExtraData
  230. else
  231. Result := nil;
  232. end;
  233. procedure TAvlTree.Insert(Key: TKeyType; Extra: TExtraData);
  234. var
  235. H: PNode;
  236. begin
  237. // make new node
  238. New(H);
  239. with H^ do
  240. begin
  241. Data.ID := Key;
  242. Data.ExtraData := Extra;
  243. Left := nil;
  244. Right := nil;
  245. Bal := 0;
  246. end;
  247. // insert new node
  248. InternalInsert(H, FRoot);
  249. // check tree
  250. // assert(CheckTree(FRoot));
  251. end;
  252. procedure TAvlTree.Delete(Key: TKeyType);
  253. begin
  254. InternalDelete(Key, FRoot);
  255. // assert(CheckTree(FRoot));
  256. end;
  257. procedure TAvlTree.InternalInsert(X: PNode; var P: PNode);
  258. begin
  259. if P = nil
  260. then begin P := X; Inc(FCount); FHeightChange := true end
  261. else
  262. if X^.Data.ID < P^.Data.ID then
  263. begin
  264. { less }
  265. InternalInsert(X, P^.Left);
  266. if FHeightChange then {Left branch has grown higher}
  267. case P^.Bal of
  268. 1: begin P^.Bal := 0; FHeightChange := false end;
  269. 0: begin P^.Bal := -1 end;
  270. -1: begin {Rebalance}
  271. if P^.Left^.Bal = -1
  272. then {single R rotation}
  273. begin
  274. RotR(P);
  275. //adjust balance factor:
  276. P^.Right^.Bal := 0;
  277. end
  278. else {double LR rotation}
  279. begin
  280. RotL(P^.Left);
  281. RotR(P);
  282. //adjust balance factor:
  283. case P^.Bal of
  284. -1: begin P^.Left^.Bal := 0; P^.Right^.Bal := 1 end;
  285. 0: begin P^.Left^.Bal := 0; P^.Right^.Bal := 0 end;
  286. 1: begin P^.Left^.Bal := -1; P^.Right^.Bal := 0 end;
  287. end;
  288. end;
  289. P^.Bal := 0;
  290. FHeightChange := false;
  291. // assert(CheckTree(P));
  292. end{-1}
  293. end{case}
  294. end else
  295. if X^.Data.ID > P^.Data.ID then
  296. begin
  297. { greater }
  298. InternalInsert(X, P^.Right);
  299. if FHeightChange then {Right branch has grown higher}
  300. case P^.Bal of
  301. -1: begin P^.Bal := 0; FHeightChange := false end;
  302. 0: begin P^.Bal := 1 end;
  303. 1: begin {Rebalance}
  304. if P^.Right^.Bal = 1
  305. then {single L rotation}
  306. begin
  307. RotL(P);
  308. //adjust balance factor:
  309. P^.Left.Bal := 0;
  310. end
  311. else {double RL rotation}
  312. begin
  313. RotR(P^.Right);
  314. RotL(P);
  315. //adjust balance factor
  316. case P^.Bal of
  317. 1: begin P^.Right^.Bal := 0; P^.Left^.Bal := -1 end;
  318. 0: begin P^.Right^.Bal := 0; P^.Left^.Bal := 0 end;
  319. -1: begin P^.Right^.Bal := 1; P^.Left^.Bal := 0 end;
  320. end;
  321. end;
  322. P^.Bal := 0;
  323. FHeightChange := false;
  324. // assert(CheckTree(P));
  325. end{1}
  326. end{case}
  327. end {greater} else begin
  328. {X already present; do not insert again}
  329. FHeightChange := false;
  330. end;
  331. // assert(CheckTree(P));
  332. end;{InternalInsert}
  333. procedure TAvlTree.InternalDelete(X: TKeyType; var P: PNode);
  334. var
  335. Q: PNode;
  336. H: TData;
  337. begin
  338. if P = nil then
  339. FHeightChange := false
  340. else
  341. if X < P^.Data.ID then
  342. begin
  343. InternalDelete(X, P^.Left);
  344. if FHeightChange then BalanceLeft(P, FHeightChange)
  345. end else
  346. if X > P^.Data.ID then
  347. begin
  348. InternalDelete(X, P^.Right);
  349. if FHeightChange then BalanceRight(P, FHeightChange)
  350. end else begin
  351. if P^.Right = nil then
  352. begin Q := P; P := P^.Left; FHeightChange := true end
  353. else if P^.Left = nil then
  354. begin Q := P; P := P^.Right; FHeightChange := true end
  355. else
  356. begin
  357. DelRM(P^.Left, Q, FHeightChange);
  358. H := P^.Data;
  359. P^.Data := Q^.Data;
  360. Q^.Data := H;
  361. if FHeightChange then BalanceLeft(P, FHeightChange)
  362. end;
  363. DeleteNode(Q)
  364. end;{eq}
  365. end;{InternalDelete}
  366. function TAvlTree.Lowest: PData;
  367. var
  368. H: PNode;
  369. begin
  370. H := FRoot;
  371. if H = nil then
  372. begin
  373. Result := nil;
  374. exit;
  375. end;
  376. while H^.Left <> nil do
  377. H := H^.Left;
  378. Result := @H^.Data;
  379. end;
  380. end.