ExportTree.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. using System;
  2. using System.Collections.Generic;
  3. namespace FastReport.Export
  4. {
  5. /// <summary>
  6. /// Binary tree class
  7. /// </summary>
  8. internal class BinaryTree
  9. {
  10. #region Private variables and constants
  11. // Acceptable disbalance in branches.
  12. const int DISBALANCE = 3;
  13. private int count;
  14. private int index;
  15. private BinaryTreeNode root;
  16. private BinaryTreeNode[] nodes;
  17. private float inaccuracy;
  18. private float maxDistance;
  19. private float prevValue;
  20. #endregion
  21. #region Public properties
  22. /// <summary>
  23. /// Maximal value between child and parent
  24. /// </summary>
  25. public float MaxDistance
  26. {
  27. get { return maxDistance; }
  28. set { maxDistance = value; }
  29. }
  30. /// <summary>
  31. /// Nodes count
  32. /// </summary>
  33. public int Count
  34. {
  35. get { return count; }
  36. }
  37. /// <summary>
  38. /// Root node
  39. /// </summary>
  40. public BinaryTreeNode RootNode
  41. {
  42. get { return root; }
  43. }
  44. /// <summary>
  45. /// Nodes array. Accending sorting by node value. Available after close of tree.
  46. /// </summary>
  47. public BinaryTreeNode[] Nodes
  48. {
  49. get { return nodes; }
  50. }
  51. /// <summary>
  52. /// Acceptable inaccuracy of new values.
  53. /// </summary>
  54. public float Inaccuracy
  55. {
  56. get { return inaccuracy; }
  57. set { inaccuracy = value; }
  58. }
  59. #endregion
  60. #region Private methods
  61. /// <summary>
  62. /// Recursive add value to a node.
  63. /// </summary>
  64. /// <param name="node"></param>
  65. /// <param name="value"></param>
  66. /// <returns></returns>
  67. private int AddChild(ref BinaryTreeNode node, float value)
  68. {
  69. if (node == null)
  70. {
  71. node = new BinaryTreeNode(value);
  72. count++;
  73. }
  74. else
  75. {
  76. float diff = value - node.value;
  77. if (diff < -inaccuracy)
  78. if (node.left == null)
  79. {
  80. node.left = new BinaryTreeNode(value);
  81. node.leftCount = 1;
  82. count++;
  83. }
  84. else
  85. {
  86. node.leftCount = AddChild(ref node.left, value);
  87. if (node.leftCount > node.rightCount + DISBALANCE)
  88. PollLeft(ref node);
  89. }
  90. else if (diff > inaccuracy)
  91. if (node.right == null)
  92. {
  93. node.right = new BinaryTreeNode(value);
  94. node.rightCount = 1;
  95. count++;
  96. }
  97. else
  98. {
  99. node.rightCount = AddChild(ref node.right, value);
  100. if (node.leftCount + DISBALANCE < node.rightCount)
  101. PollRight(ref node);
  102. }
  103. }
  104. return node.leftCount + node.rightCount + 1;
  105. }
  106. /// <summary>
  107. /// Poll right child node for correct balance.
  108. /// </summary>
  109. /// <param name="node"></param>
  110. private void PollRight(ref BinaryTreeNode node)
  111. {
  112. BinaryTreeNode top = node.right;
  113. BinaryTreeNode rightLeft = top.left;
  114. top.left = node;
  115. node.right = rightLeft;
  116. node.rightCount = (node.right == null) ? 0 : node.right.leftCount + node.right.rightCount + 1;
  117. top.leftCount = node.leftCount + node.rightCount + 1;
  118. node = top;
  119. }
  120. /// <summary>
  121. /// Poll left child for correct balance.
  122. /// </summary>
  123. /// <param name="node"></param>
  124. private void PollLeft(ref BinaryTreeNode node)
  125. {
  126. BinaryTreeNode top = node.left;
  127. BinaryTreeNode leftRight = top.right;
  128. top.right = node;
  129. node.left = leftRight;
  130. node.leftCount = (node.left == null) ? 0 : node.left.leftCount + node.left.rightCount + 1;
  131. top.rightCount = node.leftCount + node.rightCount + 1;
  132. node = top;
  133. }
  134. /// <summary>
  135. /// Recursive indexation of node and childs.
  136. /// </summary>
  137. /// <param name="node"></param>
  138. private void Index(BinaryTreeNode node)
  139. {
  140. if (node.left != null)
  141. Index(node.left);
  142. if (maxDistance > 0 && index > 0 && node.value - prevValue > maxDistance + inaccuracy)
  143. {
  144. float value = prevValue;
  145. while (value < node.value - maxDistance)
  146. {
  147. value += maxDistance;
  148. AddChild(ref root, value);
  149. }
  150. prevValue = node.value;
  151. }
  152. else if (index < nodes.Length)
  153. {
  154. node.index = index;
  155. nodes[index++] = node;
  156. prevValue = node.value;
  157. }
  158. if (node.right != null)
  159. Index(node.right);
  160. }
  161. #endregion
  162. #region Public methods
  163. /// <summary>
  164. /// Add new value in tree. All equals are skipped.
  165. /// </summary>
  166. /// <param name="value"></param>
  167. public void Add(float value)
  168. {
  169. AddChild(ref root, value);
  170. }
  171. /// <summary>
  172. /// Close the tree and make index array.
  173. /// </summary>
  174. public void Close()
  175. {
  176. int oldCount = 0;
  177. while (oldCount != count)
  178. {
  179. nodes = new BinaryTreeNode[count];
  180. index = 0;
  181. oldCount = count;
  182. Index(root);
  183. }
  184. }
  185. /// <summary>
  186. /// Seek of value index in the tree.
  187. /// </summary>
  188. /// <param name="value"></param>
  189. /// <returns></returns>
  190. public int IndexOf(float value)
  191. {
  192. return Find(root, value);
  193. }
  194. /// <summary>
  195. /// Find of value index in sub-tree of node.
  196. /// </summary>
  197. /// <param name="node"></param>
  198. /// <param name="value"></param>
  199. /// <returns></returns>
  200. public int Find(BinaryTreeNode node, float value)
  201. {
  202. if (node == null)
  203. return -1;
  204. if (Math.Abs(value - node.value) <= inaccuracy)
  205. return node.index;
  206. else if (value < node.value)
  207. return Find(node.left, value);
  208. else
  209. return Find(node.right, value);
  210. }
  211. /// <summary>
  212. /// Borrow values form List in the tree
  213. /// </summary>
  214. /// <param name="array"></param>
  215. public void FromList(List<float> array)
  216. {
  217. foreach (float value in array)
  218. AddChild(ref root, value);
  219. }
  220. /// <summary>
  221. /// Borrow values form array in the tree
  222. /// </summary>
  223. /// <param name="array"></param>
  224. public void FromArray(float[] array)
  225. {
  226. foreach (float value in array)
  227. AddChild(ref root, value);
  228. }
  229. /// <summary>
  230. /// Clear tree
  231. /// </summary>
  232. public void Clear()
  233. {
  234. count = 0;
  235. root = null;
  236. nodes = null;
  237. }
  238. #endregion
  239. /// <summary>
  240. /// Tree constructor
  241. /// </summary>
  242. public BinaryTree()
  243. {
  244. Clear();
  245. }
  246. }
  247. /// <summary>
  248. /// Tree node class
  249. /// </summary>
  250. internal class BinaryTreeNode
  251. {
  252. /// <summary>
  253. /// Link to left child
  254. /// </summary>
  255. public BinaryTreeNode left;
  256. /// <summary>
  257. /// Link to right child
  258. /// </summary>
  259. public BinaryTreeNode right;
  260. /// <summary>
  261. /// Node value
  262. /// </summary>
  263. public float value;
  264. /// <summary>
  265. /// Count of nodes in left sub-tree
  266. /// </summary>
  267. public int leftCount;
  268. /// <summary>
  269. /// Count of nodes in right sub-tree
  270. /// </summary>
  271. public int rightCount;
  272. /// <summary>
  273. /// Node index
  274. /// </summary>
  275. public int index;
  276. /// <summary>
  277. /// Node constructor
  278. /// </summary>
  279. /// <param name="nodeValue"></param>
  280. public BinaryTreeNode(float nodeValue)
  281. {
  282. value = nodeValue;
  283. index = -1;
  284. }
  285. }
  286. }