2
0

gset.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. {
  2. This file is part of the Free Pascal FCL library.
  3. BSD parts (c) 2011 Vlado Boza
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY;without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {$mode objfpc}
  11. unit gset;
  12. interface
  13. const RED=true;
  14. const BLACK=false;
  15. type
  16. { TSetIterator }
  17. generic TSetIterator<T, TNode>=class
  18. public
  19. type PNode=^TNode;
  20. TLSetIterator = specialize TSetIterator<T, TNode>;
  21. var FNode:PNode;
  22. function GetData:T; Inline;
  23. function Next:boolean;
  24. function MoveNext:boolean; Inline;
  25. function GetEnumerator : TLSetIterator; Inline;
  26. function Prev:boolean;
  27. property Data:T read GetData;
  28. property Current:T read GetData;
  29. end;
  30. generic TSet<T, TCompare>=class
  31. public
  32. type
  33. PNode=^Node;
  34. Node=record
  35. Data:T;
  36. Left,Right:PNode;
  37. Parent:PNode;
  38. Color:boolean;
  39. end;
  40. TIterator=specialize TSetIterator<T, Node>;
  41. var
  42. private
  43. FBase:PNode;
  44. FSize:SizeUInt;
  45. function CreateNode(Data:T):PNode;inline;
  46. procedure DestroyNodeAndChilds(nod:PNode);
  47. procedure DestroyNode(nod:PNode);
  48. function RotateRight(nod:PNode):PNode;inline;
  49. function RotateLeft(nod:PNode):PNode;inline;
  50. procedure FlipColors(nod:PNode);inline;
  51. function IsRed(nod:PNode):boolean;inline;
  52. function Insert(value:T; nod:PNode; out position:PNode):PNode;
  53. function FixUp(nod:PNode):PNode;inline;
  54. function MoveRedLeft(nod:PNode):PNode;inline;
  55. function MoveRedRight(nod:PNode):PNode;inline;
  56. function DeleteMin(nod:PNode):PNode;
  57. function Delete(value:T; nod:PNode):PNode;
  58. function Min(nod:PNode):PNode;inline;
  59. public
  60. function Find(value:T):TIterator;inline;
  61. function FindLess(value:T):TIterator;inline;
  62. function FindLessEqual(value:T):TIterator;inline;
  63. function FindGreater(value:T):TIterator;inline;
  64. function FindGreaterEqual(value:T):TIterator;inline;
  65. function InsertAndGetIterator(value:T):TIterator;inline;
  66. procedure Insert(value:T);inline;
  67. function Min:TIterator;inline;
  68. function Max:TIterator;inline;
  69. procedure Delete(value:T);inline;
  70. public constructor Create;
  71. public destructor Destroy;override;
  72. function Size:SizeUInt;
  73. function IsEmpty:boolean;
  74. function NFind(value:T):PNode;inline;
  75. function NFindLess(value:T):PNode;inline;
  76. function NFindLessEqual(value:T):PNode;inline;
  77. function NFindGreater(value:T):PNode;inline;
  78. function NFindGreaterEqual(value:T):PNode;inline;
  79. function NInsert(value:T):PNode;inline;
  80. function NMin:PNode;inline;
  81. function NMax:PNode;inline;
  82. end;
  83. implementation
  84. constructor TSet.Create;
  85. begin
  86. FBase:=nil;
  87. FSize:=0;
  88. end;
  89. destructor TSet.Destroy;
  90. begin
  91. DestroyNodeAndChilds(FBase);
  92. end;
  93. function TSet.Size:SizeUInt;
  94. begin
  95. Size:=FSize;
  96. end;
  97. function TSet.IsEmpty:boolean;
  98. begin
  99. IsEmpty := FSize=0;
  100. end;
  101. procedure TSet.DestroyNodeAndChilds(nod:PNode);
  102. begin
  103. if nod = nil then exit;
  104. DestroyNodeAndChilds(nod^.left);
  105. DestroyNodeAndChilds(nod^.right);
  106. DestroyNode(nod);
  107. end;
  108. procedure TSet.DestroyNode(nod:PNode);
  109. begin
  110. Finalize(nod^.Data);
  111. dispose(nod);
  112. dec(FSize);
  113. end;
  114. function TSet.CreateNode(Data:T):PNode;inline;
  115. var temp:PNode;
  116. begin
  117. temp:=new(PNode);
  118. Initialize(temp^.Data);
  119. temp^.Data:=Data;
  120. temp^.Left:=nil;
  121. temp^.Right:=nil;
  122. temp^.Parent:=nil;
  123. temp^.Color:=RED;
  124. inc(FSize);
  125. CreateNode:=temp;
  126. end;
  127. function TSet.RotateRight(nod:PNode):PNode;inline;
  128. var temp:PNode;
  129. begin
  130. temp:=nod^.Left;
  131. temp^.Parent:=nod^.Parent;
  132. nod^.Parent:=temp;
  133. nod^.Left:=temp^.Right;
  134. temp^.Right:=nod;
  135. if(nod^.Left<>nil) then nod^.Left^.Parent:=nod;
  136. temp^.Color:=nod^.Color;
  137. nod^.Color:=RED;
  138. exit(temp);
  139. end;
  140. function TSet.RotateLeft(nod:PNode):PNode;inline;
  141. var temp:PNode;
  142. begin
  143. temp:=nod^.Right;
  144. temp^.Parent:=nod^.Parent;
  145. nod^.Parent:=temp;
  146. nod^.Right:=temp^.Left;
  147. temp^.Left:=nod;
  148. if(nod^.Right<>nil) then nod^.Right^.Parent:=nod;
  149. temp^.Color:=nod^.Color;
  150. nod^.Color:=RED;
  151. exit(temp);
  152. end;
  153. procedure TSet.FlipColors(nod:PNode);inline;
  154. begin
  155. nod^.Color:= not nod^.Color;
  156. nod^.Left^.Color := not nod^.Left^.Color;
  157. nod^.Right^.Color := not nod^.Right^.Color;
  158. end;
  159. function TSet.FixUp(nod:PNode):PNode;inline;
  160. begin
  161. if(IsRed(nod^.Right)) and (not IsRed(nod^.Left)) then nod := rotateLeft(nod);
  162. if(IsRed(nod^.Left)) and (IsRed(nod^.Left^.Left)) then nod := rotateRight(nod);
  163. if(IsRed(nod^.Right)) and (IsRed(nod^.Left)) then flipColors(nod);
  164. FixUp:=nod;
  165. end;
  166. function TSet.MoveRedLeft(nod:PNode):PNode;inline;
  167. begin
  168. flipColors(nod);
  169. if (IsRed(nod^.Right^.Left)) then begin
  170. nod^.Right := rotateRight(nod^.Right);
  171. nod := rotateLeft(nod);
  172. flipColors(nod);
  173. end;
  174. MoveRedLeft:=nod;
  175. end;
  176. function TSet.MoveRedRight(nod:PNode):PNode;inline;
  177. begin
  178. flipColors(nod);
  179. if (IsRed(nod^.Left^.Left)) then begin
  180. nod := rotateRight(nod);
  181. flipColors(nod);
  182. end;
  183. MoveRedRight:=nod;
  184. end;
  185. function TSet.DeleteMin(nod:PNode):PNode;
  186. begin
  187. if (nod^.Left = nil) then begin
  188. DestroyNode(nod);
  189. exit(nil);
  190. end;
  191. if ((not IsRed(nod^.Left)) and (not IsRed(nod^.Left^.Left))) then nod := MoveRedLeft(nod);
  192. nod^.Left := DeleteMin(nod^.Left);
  193. exit(FixUp(nod));
  194. end;
  195. function TSet.Delete(value:T; nod:PNode):PNode;
  196. begin
  197. if (TCompare.c(value, nod^.Data)) then begin
  198. if (nod^.Left=nil) then exit(nod);
  199. if ((not IsRed(nod^.Left)) and ( not IsRed(nod^.Left^.Left))) then
  200. nod := MoveRedLeft(nod);
  201. nod^.Left := Delete(value, nod^.Left);
  202. end
  203. else begin
  204. if (IsRed(nod^.Left)) then begin
  205. nod := rotateRight(nod);
  206. end;
  207. if ((not TCompare.c(value,nod^.Data)) and (not TCompare.c(nod^.Data,value)) and (nod^.Right = nil)) then
  208. begin
  209. DestroyNode(nod);
  210. exit(nil);
  211. end;
  212. if (nod^.Right=nil) then exit(nod);
  213. if ((not IsRed(nod^.Right)) and (not IsRed(nod^.Right^.Left))) then nod := MoveRedRight(nod);
  214. if ((not TCompare.c(value,nod^.Data)) and (not TCompare.c(nod^.Data,value))) then begin
  215. nod^.Data := Min(nod^.Right)^.Data;
  216. nod^.Right := DeleteMin(nod^.Right);
  217. end
  218. else nod^.Right := Delete(value, nod^.Right);
  219. end;
  220. exit(FixUp(nod));
  221. end;
  222. procedure TSet.Delete(value:T);inline;
  223. begin
  224. if(FBase<>nil) then FBase:=Delete(value, FBase);
  225. if(FBase<>nil) then FBase^.Color:=BLACK;
  226. end;
  227. function TSet.Find(value:T):TIterator;inline;
  228. var ret:TIterator; x:PNode;
  229. begin
  230. x := NFind(value);
  231. if x = nil then exit(nil);
  232. ret := TIterator.create;
  233. ret.FNode := x;
  234. Find := ret;
  235. end;
  236. function TSet.NFind(value:T):PNode;inline;
  237. var x:PNode;
  238. begin
  239. x:=FBase;
  240. while(x <> nil) do begin
  241. if(TCompare.c(value,x^.Data)) then x:=x^.Left
  242. else if(TCompare.c(x^.Data,value)) then x:=x^.Right
  243. else begin
  244. exit(x);
  245. end;
  246. end;
  247. exit(nil);
  248. end;
  249. function TSet.FindLess(value:T):TIterator;inline;
  250. var ret:TIterator; x:PNode;
  251. begin
  252. x := NFindLess(value);
  253. if x = nil then exit(nil);
  254. ret := TIterator.create;
  255. ret.FNode := x;
  256. FindLess := ret;
  257. end;
  258. function TSet.NFindLess(value:T):PNode;inline;
  259. var x,cur:PNode;
  260. begin
  261. x:=nil;
  262. cur:=FBase;
  263. while (cur <> nil) do begin
  264. if (TCompare.c(cur^.Data, value)) then
  265. begin
  266. x:=cur;
  267. cur:=cur^.right;
  268. end else
  269. cur:=cur^.left;
  270. end;
  271. NFindLess := x;
  272. end;
  273. function TSet.FindLessEqual(value:T):TIterator;inline;
  274. var ret:TIterator; x:PNode;
  275. begin
  276. x := NFindLessEqual(value);
  277. if x = nil then exit(nil);
  278. ret := TIterator.create;
  279. ret.FNode := x;
  280. FindLessEqual := ret;
  281. end;
  282. function TSet.NFindLessEqual(value:T):PNode;inline;
  283. var x,cur:PNode;
  284. begin
  285. x:=nil;
  286. cur:=FBase;
  287. while (cur <> nil) do begin
  288. if (not TCompare.c(value, cur^.data)) then
  289. begin
  290. x:=cur;
  291. cur:=cur^.right;
  292. end else
  293. cur:=cur^.left;
  294. end;
  295. NFindLessEqual := x
  296. end;
  297. function TSet.FindGreater(value:T):TIterator;inline;
  298. var ret:TIterator; x:PNode;
  299. begin
  300. x := NFindGreater(value);
  301. if x = nil then exit(nil);
  302. ret := TIterator.create;
  303. ret.FNode := x;
  304. FindGreater := ret;
  305. end;
  306. function TSet.NFindGreater(value:T):PNode;inline;
  307. var x,cur:PNode;
  308. begin
  309. x:=nil;
  310. cur:=FBase;
  311. while (cur <> nil) do begin
  312. if (TCompare.c(value, cur^.Data)) then
  313. begin
  314. x:=cur;
  315. cur:=cur^.left;
  316. end else
  317. cur:=cur^.right;
  318. end;
  319. NFindGreater := x;
  320. end;
  321. function TSet.FindGreaterEqual(value:T):TIterator;inline;
  322. var ret:TIterator; x:PNode;
  323. begin
  324. x := NFindGreaterEqual(value);
  325. if x = nil then exit(nil);
  326. ret := TIterator.create;
  327. ret.FNode := x;
  328. FindGreaterEqual := ret;
  329. end;
  330. function TSet.NFindGreaterEqual(value:T):PNode;inline;
  331. var x,cur:PNode;
  332. begin
  333. x:=nil;
  334. cur:=FBase;
  335. while (cur <> nil) do begin
  336. if (not TCompare.c(cur^.Data, value)) then
  337. begin
  338. x:=cur;
  339. cur:=cur^.left;
  340. end else
  341. cur:=cur^.right;
  342. end;
  343. NFindGreaterEqual := x;
  344. end;
  345. procedure TSet.Insert(value:T);inline;
  346. var position:PNode;
  347. begin
  348. FBase:=Insert(value, FBase, position);
  349. FBase^.Color:=BLACK;
  350. end;
  351. function TSet.NInsert(value:T):PNode;inline;
  352. var position:PNode;
  353. begin
  354. FBase:=Insert(value, FBase, position);
  355. FBase^.Color:=BLACK;
  356. NInsert := position;
  357. end;
  358. function TSet.InsertAndGetIterator(value:T):TIterator;inline;
  359. var position:PNode; ret:TIterator;
  360. begin
  361. FBase:=Insert(value, FBase, position);
  362. FBase^.Color:=BLACK;
  363. ret := TIterator.create;
  364. ret.FNode := position;
  365. InsertAndGetIterator := ret;
  366. end;
  367. function TSet.Insert(value:T; nod:PNode; out position:PNode):PNode;
  368. begin
  369. if(nod=nil) then begin
  370. nod:=CreateNode(value);
  371. position:=nod;
  372. exit(nod);
  373. end;
  374. if(TCompare.c(value,nod^.Data)) then begin
  375. nod^.Left:=Insert(value, nod^.Left, position);
  376. nod^.Left^.Parent:=nod;
  377. end
  378. else if TCompare.c(nod^.Data,value) then begin
  379. nod^.Right:=Insert(value, nod^.Right, position);
  380. nod^.Right^.Parent:=nod;
  381. end
  382. else begin
  383. position:=nod;
  384. exit(nod);
  385. end;
  386. if(IsRed(nod^.Right)) and (not IsRed(nod^.Left)) then nod := rotateLeft(nod);
  387. if(IsRed(nod^.Left)) and (IsRed(nod^.Left^.Left)) then nod := rotateRight(nod);
  388. if(IsRed(nod^.Right)) and (IsRed(nod^.Left)) then flipColors(nod);
  389. Insert:=nod;
  390. end;
  391. function TSet.IsRed(nod:PNode):boolean;inline;
  392. begin
  393. if(nod=nil) then exit(false);
  394. exit(nod^.Color);
  395. end;
  396. function TSet.Min(nod:PNode):PNode;inline;
  397. var temp:PNode;
  398. begin
  399. temp:=nod;
  400. while(temp^.Left<>nil) do temp:=temp^.Left;
  401. exit(temp);
  402. end;
  403. function TSet.NMin:PNode;inline;
  404. var nod:PNode;
  405. begin
  406. if FBase=nil then exit(nil);
  407. nod:=Min(FBase);
  408. if (nod = nil) then exit(nil);
  409. NMin := nod;
  410. end;
  411. function TSet.Min:TIterator;inline;
  412. var nod:PNode;
  413. ret:TIterator;
  414. begin
  415. nod:=NMin;
  416. if (nod = nil) then exit(nil);
  417. ret := TIterator.create;
  418. ret.FNode := nod;
  419. Min := ret;
  420. end;
  421. function TSet.NMax:PNode;inline;
  422. var temp:PNode;
  423. begin
  424. if FBase=nil then exit(nil);
  425. temp:=FBase;
  426. while(temp^.Right<>nil) do temp:=temp^.Right;
  427. NMax := temp;
  428. end;
  429. function TSet.Max:TIterator;inline;
  430. var temp:PNode; ret:TIterator;
  431. begin
  432. if FBase=nil then exit(nil);
  433. temp:=FBase;
  434. while(temp^.Right<>nil) do temp:=temp^.Right;
  435. ret := TIterator.create;
  436. ret.FNode := temp;
  437. Max := ret;
  438. end;
  439. function TSetIterator.GetData:T;
  440. begin
  441. GetData:= FNode^.Data;
  442. end;
  443. function TSetIterator.Next:boolean;
  444. begin
  445. Result:=MoveNext;
  446. end;
  447. function TSetIterator.MoveNext: boolean;
  448. var temp:PNode;
  449. begin
  450. if(FNode=nil) then exit(false);
  451. if(FNode^.Right<>nil) then begin
  452. temp:=FNode^.Right;
  453. while(temp^.Left<>nil) do temp:=temp^.Left;
  454. end
  455. else begin
  456. temp:=FNode;
  457. while(true) do begin
  458. if(temp^.Parent=nil) then begin temp:=temp^.Parent; break; end;
  459. if(temp^.Parent^.Left=temp) then begin temp:=temp^.Parent; break; end;
  460. temp:=temp^.Parent;
  461. end;
  462. end;
  463. if (temp = nil) then exit(false);
  464. FNode:=temp;
  465. Result:=true;
  466. end;
  467. function TSetIterator.GetEnumerator: TLSetIterator;
  468. begin
  469. result:=self;
  470. end;
  471. function TSetIterator.Prev:boolean;
  472. var temp:PNode;
  473. begin
  474. if(FNode=nil) then exit(false);
  475. if(FNode^.Left<>nil) then begin
  476. temp:=FNode^.Left;
  477. while(temp^.Right<>nil) do temp:=temp^.Right;
  478. end
  479. else begin
  480. temp:=FNode;
  481. while(true) do begin
  482. if(temp^.Parent=nil) then begin temp:=temp^.Parent; break; end;
  483. if(temp^.Parent^.Right=temp) then begin temp:=temp^.Parent; break; end;
  484. temp:=temp^.Parent;
  485. end;
  486. end;
  487. if (temp = nil) then exit(false);
  488. FNode:=temp;
  489. Prev:=true;
  490. end;
  491. end.