y_bintree.inc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. /*----------------------------------------------------------------------------*-
  2. ===================================
  3. Y Sever Includes - Binary Tree Core
  4. ===================================
  5. Description:
  6. Provides functions to generate balanced binary search trees for efficient
  7. searching of large arrays by value. Left branch is less than, right branch
  8. is greater than or equal to for multiple matching values.
  9. Legal:
  10. Version: MPL 1.1
  11. The contents of this file are subject to the Mozilla Public License Version
  12. 1.1 (the "License"); you may not use this file except in compliance with
  13. the License. You may obtain a copy of the License at
  14. http://www.mozilla.org/MPL/
  15. Software distributed under the License is distributed on an "AS IS" basis,
  16. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  17. for the specific language governing rights and limitations under the
  18. License.
  19. The Original Code is the SA:MP script information include.
  20. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  21. Portions created by the Initial Developer are Copyright (C) 2008
  22. the Initial Developer. All Rights Reserved.
  23. Contributors:
  24. ZeeX, koolk
  25. Thanks:
  26. Peter, Cam - Support.
  27. ZeeX - Very productive conversations.
  28. koolk - IsPlayerinAreaEx code.
  29. TheAlpha - Danish translation.
  30. breadfish - German translation.
  31. Fireburn - Dutch translation.
  32. yom - French translation.
  33. 50p - Polish translation.
  34. Zamaroht - Spanish translation.
  35. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
  36. for me to strive to better.
  37. Pixels^ - Running XScripters where the idea was born.
  38. Matite - Pestering me to release it and using it.
  39. Very special thanks to:
  40. Thiadmer - PAWN.
  41. Kye/Kalcor - SA:MP.
  42. SA:MP Team past, present and future - SA:MP.
  43. Version:
  44. 0.1.3
  45. Changelog:
  46. 12/08/07:
  47. Fixed a bug with empty trees.
  48. 14/04/07:
  49. Updated header documentation with more than changelog.
  50. 10/04/07:
  51. Added parents for easy deletion.
  52. Added node deletion code.
  53. 08/04/07:
  54. Added Bintree_Add()
  55. 24/03/07:
  56. First version.
  57. Functions:
  58. Public:
  59. -
  60. Core:
  61. Bintree_QSort - Custom implementaion of QSort to keep pointers.
  62. Bintree_SortHalf - Itteratively balances halves of an array.
  63. Stock:
  64. Bintree_Generate - Generates a balanced binary tree from given input.
  65. Bintree_Reset - Resets a position in a tree.
  66. Bintree_FindValue - Finds the pointer for a value in the tree.
  67. Bintree_Add - Adds an item to a generated tree.
  68. Bintree_Delete - Removes an item from a tree.
  69. Bintree_UpdatePointers - Updates the pointers after a target change.
  70. Static:
  71. Bintree_Compress - Removes space from an altered tree.
  72. Bintree_FindMin - Finds the smallest value on a branch.
  73. Bintree_FindMax - Finds the largest value on a branch.
  74. Inline:
  75. Bintree_Sort - Entry point for Bintree_QSort.
  76. Bintree_Fill - Entry point for Bintree_SortHalf.
  77. API:
  78. -
  79. Callbacks:
  80. -
  81. Definitions:
  82. BINTREE_NO_BRANCH - Nowhere to go from the number in required direction.
  83. BINTREE_NOT_FOUND - Failure return.
  84. Enums:
  85. E_BINTREE_TREE - Structure of a leaf of a binary tree.
  86. E_BINTREE_INPUT - Structure of an array of data to be added to a tree.
  87. Macros:
  88. -
  89. Tags:
  90. Bintree - Binary tree type.
  91. Variables:
  92. Global:
  93. -
  94. Static:
  95. -
  96. Commands:
  97. -
  98. Compile options:
  99. -
  100. Operators:
  101. -
  102. -*----------------------------------------------------------------------------*/
  103. #include <YSI\internal\y_version>
  104. #define BINTREE_NO_BRANCH -1
  105. #define BINTREE_NOT_FOUND -1
  106. enum E_BINTREE_TREE
  107. {
  108. E_BINTREE_TREE_VALUE,
  109. E_BINTREE_TREE_LEFT,
  110. E_BINTREE_TREE_RIGHT,
  111. E_BINTREE_TREE_PARENT,
  112. E_BINTREE_TREE_POINTER
  113. }
  114. enum E_BINTREE_INPUT
  115. {
  116. E_BINTREE_INPUT_VALUE,
  117. E_BINTREE_INPUT_POINTER
  118. }
  119. //#define leafs<%1> %1][E_BINTREE_TREE
  120. //#define Bintree:%1[%2] Bintree:%1[%2][E_BINTREE_TREE]
  121. #define BinaryTree:%1<%2> Bintree:%1[%2][E_BINTREE_TREE]
  122. /*----------------------------------------------------------------------------*-
  123. Function:
  124. Bintree_Sort
  125. Params:
  126. input[][E_BINTREE_INPUT] - Data to sort.
  127. size - Size of data to sort.
  128. Return:
  129. -
  130. Notes:
  131. Entry point for Bintree_QSort.
  132. -*----------------------------------------------------------------------------*/
  133. #define Bintree_Sort(%1,%2) \
  134. Bintree_QSort((%1), 0, (%2) - 1)
  135. /*----------------------------------------------------------------------------*-
  136. Function:
  137. Bintree_Fill
  138. Params:
  139. BinaryTree:output<> - Destination for balanced tree.
  140. data[][E_BINTREE_INPUT] - Source data.
  141. size - Size of data.
  142. Return:
  143. Bintree_SortHalf.
  144. Notes:
  145. Entry point for Bintree_SortHalf.
  146. -*----------------------------------------------------------------------------*/
  147. #define Bintree_Fill(%1,%2,%3) \
  148. Bintree_SortHalf((%1), (%2), 0, (%3), 0, BINTREE_NO_BRANCH)
  149. /*----------------------------------------------------------------------------*-
  150. Function:
  151. Bintree_Generate
  152. Params:
  153. BinaryTree:output<> - Binary tree to store the data in.
  154. input[][E_BINTREE_INPUT] - Input data to get the data from.
  155. size - Number of items to sort.
  156. Return:
  157. -
  158. Notes:
  159. Just calls the sort and fill routines.
  160. -*----------------------------------------------------------------------------*/
  161. stock Bintree_Generate(BinaryTree:output<>, input[][E_BINTREE_INPUT], size)
  162. {
  163. if (!size)
  164. {
  165. output[0][E_BINTREE_TREE_PARENT] = BINTREE_NO_BRANCH;
  166. output[0][E_BINTREE_TREE_LEFT] = BINTREE_NO_BRANCH;
  167. output[0][E_BINTREE_TREE_RIGHT] = BINTREE_NO_BRANCH;
  168. return 0;
  169. }
  170. Bintree_Sort(input, size);
  171. Bintree_Fill(output, input, size);
  172. return 1;
  173. }
  174. /*----------------------------------------------------------------------------*-
  175. Function:
  176. Bintree_Reset
  177. Params:
  178. BinaryTree:tree<> - Array to reset.
  179. pointer - Position to reset.
  180. Return:
  181. -
  182. Notes:
  183. Initialises the array for use.
  184. -*----------------------------------------------------------------------------*/
  185. stock Bintree_Reset(BinaryTree:tree<>, pointer = 0)
  186. {
  187. tree[pointer][E_BINTREE_TREE_VALUE] = 0;
  188. tree[pointer][E_BINTREE_TREE_LEFT] = BINTREE_NO_BRANCH;
  189. tree[pointer][E_BINTREE_TREE_RIGHT] = BINTREE_NO_BRANCH;
  190. tree[pointer][E_BINTREE_TREE_PARENT] = BINTREE_NO_BRANCH;
  191. tree[pointer][E_BINTREE_TREE_POINTER] = BINTREE_NOT_FOUND;
  192. }
  193. /*----------------------------------------------------------------------------*-
  194. Function:
  195. Bintree_FindValue
  196. Params:
  197. BinaryTree:tree<> - Tree to find the data in.
  198. value - Value to search for.
  199. &cont - Start point.
  200. &old - The last real leaf.
  201. Return:
  202. -
  203. Notes:
  204. Itterates through the array following the various paths till it locates
  205. the value provided or reaches a dead end. If the current value is greater
  206. than the search value, the search goes left, otherwise right.
  207. If cont is not -1 the search will start from the data pointed to by the
  208. data pointed to by conts' right path, this is to allow collisions to be
  209. passed over if you want a subsequent one.
  210. -*----------------------------------------------------------------------------*/
  211. stock Bintree_FindValue(BinaryTree:tree<>, value, &cont = 0, &old = 0)
  212. {
  213. new
  214. treeValue;
  215. while (cont != BINTREE_NO_BRANCH)
  216. {
  217. old = cont;
  218. treeValue = tree[old][E_BINTREE_TREE_VALUE];
  219. if (value < treeValue) cont = tree[old][E_BINTREE_TREE_LEFT];
  220. else
  221. {
  222. cont = tree[old][E_BINTREE_TREE_RIGHT];
  223. if (value == treeValue)
  224. {
  225. return tree[old][E_BINTREE_TREE_POINTER];
  226. }
  227. }
  228. }
  229. return BINTREE_NOT_FOUND;
  230. }
  231. /*----------------------------------------------------------------------------*-
  232. Function:
  233. Bintree_QSort
  234. Params:
  235. numbers[][E_BINTREE_INPUT] - Data to sort.
  236. left - Start index.
  237. right - End index.
  238. Return:
  239. -
  240. Notes:
  241. Custom version of QSort (see YSI_misc) allows for E_BINTREE_INPUT data
  242. types, preserving the relative pointers for the sorted data.
  243. -*----------------------------------------------------------------------------*/
  244. Bintree_QSort(numbers[][E_BINTREE_INPUT], left, right)
  245. {
  246. new
  247. pivot = numbers[left][E_BINTREE_INPUT_VALUE],
  248. pointer = numbers[left][E_BINTREE_INPUT_POINTER],
  249. l_hold = left,
  250. r_hold = right;
  251. while (left < right)
  252. {
  253. while ((numbers[right][E_BINTREE_INPUT_VALUE] >= pivot) && (left < right)) right--;
  254. if (left != right)
  255. {
  256. numbers[left][E_BINTREE_INPUT_VALUE] = numbers[right][E_BINTREE_INPUT_VALUE];
  257. numbers[left][E_BINTREE_INPUT_POINTER] = numbers[right][E_BINTREE_INPUT_POINTER];
  258. left++;
  259. }
  260. while ((numbers[left][E_BINTREE_INPUT_VALUE] <= pivot) && (left < right)) left++;
  261. if (left != right)
  262. {
  263. numbers[right][E_BINTREE_INPUT_VALUE] = numbers[left][E_BINTREE_INPUT_VALUE];
  264. numbers[right][E_BINTREE_INPUT_POINTER] = numbers[left][E_BINTREE_INPUT_POINTER];
  265. right--;
  266. }
  267. }
  268. numbers[left][E_BINTREE_INPUT_VALUE] = pivot;
  269. numbers[left][E_BINTREE_INPUT_POINTER] = pointer;
  270. pivot = left;
  271. left = l_hold;
  272. right = r_hold;
  273. if (left < pivot) Bintree_QSort(numbers, left, pivot - 1);
  274. if (right > pivot) Bintree_QSort(numbers, pivot + 1, right);
  275. }
  276. /*----------------------------------------------------------------------------*-
  277. Function:
  278. Bintree_SortHalf
  279. Params:
  280. BinaryTree:output<> - Destination array.
  281. data[][E_BINTREE_INPUT] - Source array.
  282. index - Start index of the source for processing.
  283. upper - End index of the source for processing.
  284. offset - Current offset in the destination array for writing.
  285. Return:
  286. Size of balanced tree.
  287. Notes:
  288. Recursively calls itself. Bisects the passed array and passed each half
  289. back to itself, with the middle value of each half being the left and
  290. right branches of the middle value of the passed array (which isn't
  291. included in either bisected half). This is itterative so those are again
  292. split and again split. If the passed array is only one or two elements
  293. big the behaviour is set and hardcoded.
  294. Equal values SHOULD branch right, the code is designed for this however
  295. the generation is not fully tested (it mostly branches right but adjacent
  296. after bisecting values haven't been tested).
  297. Based on code written for PHP by me.
  298. -*----------------------------------------------------------------------------*/
  299. Bintree_SortHalf(BinaryTree:output<>, data[][E_BINTREE_INPUT], index, upper, offset, parent)
  300. {
  301. new
  302. num = upper - index;
  303. if (!num) return offset;
  304. if (num == 1)
  305. {
  306. output[offset][E_BINTREE_TREE_VALUE] = data[index][E_BINTREE_INPUT_VALUE];
  307. output[offset][E_BINTREE_TREE_POINTER] = data[index][E_BINTREE_INPUT_POINTER];
  308. output[offset][E_BINTREE_TREE_PARENT] = parent;
  309. output[offset][E_BINTREE_TREE_LEFT] = BINTREE_NO_BRANCH;
  310. output[offset][E_BINTREE_TREE_RIGHT] = BINTREE_NO_BRANCH;
  311. }
  312. else if (num == 2)
  313. {
  314. output[offset][E_BINTREE_TREE_VALUE] = data[index][E_BINTREE_INPUT_VALUE];
  315. output[offset][E_BINTREE_TREE_POINTER] = data[index][E_BINTREE_INPUT_POINTER];
  316. output[offset][E_BINTREE_TREE_PARENT] = parent;
  317. output[offset][E_BINTREE_TREE_LEFT] = BINTREE_NO_BRANCH;
  318. output[offset][E_BINTREE_TREE_RIGHT] = ++offset;
  319. output[offset][E_BINTREE_TREE_VALUE] = data[++index][E_BINTREE_INPUT_VALUE];
  320. output[offset][E_BINTREE_TREE_POINTER] = data[index][E_BINTREE_INPUT_POINTER];
  321. output[offset][E_BINTREE_TREE_PARENT] = offset - 1;
  322. output[offset][E_BINTREE_TREE_LEFT] = BINTREE_NO_BRANCH;
  323. output[offset][E_BINTREE_TREE_RIGHT] = BINTREE_NO_BRANCH;
  324. }
  325. else
  326. {
  327. new
  328. half = num / 2,
  329. off = half + index,
  330. right;
  331. while (off && data[off][E_BINTREE_INPUT_VALUE] == data[off - 1][E_BINTREE_INPUT_VALUE]) off--;
  332. right = Bintree_SortHalf(output, data, index, off, offset + 1, offset);
  333. output[offset][E_BINTREE_TREE_VALUE] = data[off][E_BINTREE_INPUT_VALUE];
  334. output[offset][E_BINTREE_TREE_POINTER] = data[off][E_BINTREE_INPUT_POINTER];
  335. output[offset][E_BINTREE_TREE_PARENT] = parent;
  336. output[offset][E_BINTREE_TREE_LEFT] = offset + 1;
  337. output[offset][E_BINTREE_TREE_RIGHT] = right;
  338. return Bintree_SortHalf(output, data, off + 1, upper, right, offset);
  339. }
  340. return offset + 1;
  341. }
  342. /*----------------------------------------------------------------------------*-
  343. Function:
  344. Bintree_Add
  345. Params:
  346. BinaryTree:data<> - Array to add to.
  347. pointer - Pointer to add.
  348. value - Value to add.
  349. offset - Location in the array to store the data.
  350. maxsize - Size of data.
  351. Return:
  352. Next free location
  353. Notes:
  354. -
  355. native Bintree_Add(BinaryTree:tree<>, pointer, value, offset, maxsize = sizeof (data));
  356. -*----------------------------------------------------------------------------*/
  357. stock Bintree_Add(BinaryTree:data<>, pointer, value, offset, maxsize = sizeof (data))
  358. {
  359. if (offset >= maxsize) return BINTREE_NOT_FOUND;
  360. if (offset)
  361. {
  362. new
  363. leaf,
  364. old;
  365. while (Bintree_FindValue(data, value, leaf, old) != BINTREE_NOT_FOUND) continue;
  366. //Bintree_Reset(data, offset);
  367. if (value < data[old][E_BINTREE_TREE_VALUE]) data[old][E_BINTREE_TREE_LEFT] = offset;
  368. else data[old][E_BINTREE_TREE_RIGHT] = offset;
  369. data[offset][E_BINTREE_TREE_PARENT] = old;
  370. data[offset][E_BINTREE_TREE_LEFT] = BINTREE_NO_BRANCH;
  371. data[offset][E_BINTREE_TREE_RIGHT] = BINTREE_NO_BRANCH;
  372. data[offset][E_BINTREE_TREE_VALUE] = value;
  373. data[offset][E_BINTREE_TREE_POINTER] = pointer;
  374. return offset + 1;
  375. }
  376. else
  377. {
  378. data[0][E_BINTREE_TREE_PARENT] = BINTREE_NO_BRANCH;
  379. data[0][E_BINTREE_TREE_LEFT] = BINTREE_NO_BRANCH;
  380. data[0][E_BINTREE_TREE_RIGHT] = BINTREE_NO_BRANCH;
  381. data[0][E_BINTREE_TREE_VALUE] = value;
  382. data[0][E_BINTREE_TREE_POINTER] = pointer;
  383. return 1;
  384. }
  385. }
  386. /*----------------------------------------------------------------------------*-
  387. Function:
  388. Bintree_Delete
  389. Params:
  390. BinaryTree:tree<> - Data.
  391. index - Index to remove.
  392. count - Number of binary tree items.
  393. Return:
  394. -
  395. Notes:
  396. The left branch is usually larger due to the division
  397. method used so we start there. Even though right is
  398. >= and left is only < in even sized arrays the greater
  399. chunk (unless there's only 2 items) goes left.
  400. Called itteratively to ensure branches are maintained.
  401. -*----------------------------------------------------------------------------*/
  402. stock Bintree_Delete(BinaryTree:source<>, index, count)
  403. {
  404. new
  405. branch,
  406. old = index;
  407. while (TRUE)
  408. {
  409. if ((branch = source[old][E_BINTREE_TREE_LEFT]) != BINTREE_NO_BRANCH) branch = Bintree_FindMax(source, branch);
  410. else if ((branch = source[old][E_BINTREE_TREE_RIGHT]) != BINTREE_NO_BRANCH) branch = Bintree_FindMin(source, branch);
  411. else
  412. {
  413. if ((branch = source[old][E_BINTREE_TREE_PARENT]) != BINTREE_NO_BRANCH)
  414. {
  415. if (source[branch][E_BINTREE_TREE_LEFT] == old) source[branch][E_BINTREE_TREE_LEFT] = BINTREE_NO_BRANCH;
  416. else source[branch][E_BINTREE_TREE_RIGHT] = BINTREE_NO_BRANCH;
  417. }
  418. return Bintree_Compress(source, old, count);
  419. }
  420. new
  421. value = source[old][E_BINTREE_TREE_VALUE],
  422. pointer = source[old][E_BINTREE_TREE_POINTER];
  423. source[old][E_BINTREE_TREE_VALUE] = source[branch][E_BINTREE_TREE_VALUE];
  424. source[old][E_BINTREE_TREE_POINTER] = source[branch][E_BINTREE_TREE_POINTER];
  425. source[branch][E_BINTREE_TREE_VALUE] = value;
  426. source[branch][E_BINTREE_TREE_POINTER] = pointer;
  427. old = branch;
  428. }
  429. return BINTREE_NO_BRANCH;
  430. }
  431. /*----------------------------------------------------------------------------*-
  432. Function:
  433. Bintree_Compress
  434. Params:
  435. BinaryTree:tree<> - Array to compress.
  436. index - Point to start at.
  437. count - Number of items total.
  438. Return:
  439. -
  440. Notes:
  441. -
  442. -*----------------------------------------------------------------------------*/
  443. static stock Bintree_Compress(BinaryTree:data<>, index, count)
  444. {
  445. new
  446. index2 = index + 1;
  447. while (index < count)
  448. {
  449. new
  450. left = (data[index][E_BINTREE_TREE_LEFT] = data[index2][E_BINTREE_TREE_LEFT]),
  451. right = (data[index][E_BINTREE_TREE_RIGHT] = data[index2][E_BINTREE_TREE_RIGHT]),
  452. parent = (data[index][E_BINTREE_TREE_PARENT] = data[index2][E_BINTREE_TREE_PARENT]);
  453. data[index][E_BINTREE_TREE_VALUE] = data[index2][E_BINTREE_TREE_VALUE];
  454. data[index][E_BINTREE_TREE_POINTER] = data[index2][E_BINTREE_TREE_POINTER];
  455. if (left != BINTREE_NO_BRANCH) data[left][E_BINTREE_TREE_PARENT] = index;
  456. if (right != BINTREE_NO_BRANCH) data[right][E_BINTREE_TREE_PARENT] = index;
  457. if (parent != BINTREE_NO_BRANCH)
  458. {
  459. if (data[parent][E_BINTREE_TREE_LEFT] == index2) data[parent][E_BINTREE_TREE_LEFT] = index;
  460. else if (data[parent][E_BINTREE_TREE_RIGHT] == index2) data[parent][E_BINTREE_TREE_RIGHT] = index;
  461. }
  462. index++;
  463. index2++;
  464. }
  465. return count - 1;
  466. }
  467. /*----------------------------------------------------------------------------*-
  468. Function:
  469. Bintree_FindMin
  470. Params:
  471. BinaryTree:data<> - Array to search.
  472. offset - Start of branch to search.
  473. Return:
  474. -
  475. Notes:
  476. Finds the smallest value on a branch
  477. -*----------------------------------------------------------------------------*/
  478. static stock Bintree_FindMin(BinaryTree:data<>, offset)
  479. {
  480. new
  481. branch;
  482. while ((branch = data[offset][E_BINTREE_TREE_LEFT]) != BINTREE_NO_BRANCH) offset = branch;
  483. return offset;
  484. }
  485. /*----------------------------------------------------------------------------*-
  486. Function:
  487. Bintree_FindMax
  488. Params:
  489. BinaryTree:data<> - Array to search.
  490. offset - Start of branch to search.
  491. Return:
  492. -
  493. Notes:
  494. Finds the largest value on a branch
  495. -*----------------------------------------------------------------------------*/
  496. static stock Bintree_FindMax(BinaryTree:data<>, offset)
  497. {
  498. new
  499. branch;
  500. while ((branch = data[offset][E_BINTREE_TREE_RIGHT]) != BINTREE_NO_BRANCH) offset = branch;
  501. return offset;
  502. }
  503. /*----------------------------------------------------------------------------*-
  504. Function:
  505. Bintree_UpdatePointers
  506. Params:
  507. BinaryTree:data<> - Data to modify.
  508. offset - Pointer to modify values after.
  509. mod - Value to modify by.
  510. Return:
  511. -
  512. Notes:
  513. Used for updating pointers when the target data has been modifed (i.e. a
  514. value has been removed from the array and the array shifted).
  515. -*----------------------------------------------------------------------------*/
  516. stock Bintree_UpdatePointers(BinaryTree:data<>, offset, size, mod = -1)
  517. {
  518. for (new i = 0; i < size; i++)
  519. {
  520. if (data[i][E_BINTREE_TREE_POINTER] > offset) data[i][E_BINTREE_TREE_POINTER] += mod;
  521. }
  522. }