dbf_avl.pas 9.8 KB

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