1. using System;
  2.  
  3. namespace binarySearchTree
  4. {
  5.  
  6. //-------------------------------------------------------------------------
  7. // Klasse Bst
  8. //-------------------------------------------------------------------------
  9. // Die Klasse Bst implementiert einen binären Suchbaum für Objekte, die
  10. // IComparable erfüllen.
  11. // Die Methode visit muss bei Bedarf angepasst, d.h. in einer Subclass
  12. // überschrieben werden.
  13. public class Bst
  14. {
  15. ///////////////////////////////////////////////////////////////////////
  16. // public part:
  17. ///////////////////////////////////////////////////////////////////////
  18.  
  19. //--------------exception Klassen--------------------------------------
  20. public sealed class EMPTY_TREE : Exception {}
  21. public sealed class NO_SUCH_NODE : Exception {}
  22.  
  23.  
  24. //--------------Klasse Node--------------------------------------------
  25. protected sealed class Node
  26. {
  27. public Node left; // linker Nachfolger
  28. public IComparable info; // Info-Feld
  29. public Node right; // rechter Nachfolger
  30.  
  31. public int count; // Zaehler fuer identische Knoten
  32. }
  33.  
  34.  
  35. //--------------Bst----------------------------------------------------
  36. public Bst()
  37. {
  38. root = null;
  39. }
  40.  
  41. //--------------insert-------------------------------------------------
  42. public void insert(IComparable ding)
  43. {
  44. rec_insert(ding, ref root);
  45. }
  46.  
  47. //--------------traverse_inorder---------------------------------------
  48. public void traverse_inorder( )
  49. {
  50. rec_traverse_inorder( root );
  51. }
  52.  
  53. //--------------traverse_inorder_invert--------------------------------
  54. public void traverse_inorder_invert( )
  55. {
  56. rec_traverse_inorder_invert( root );
  57. }
  58.  
  59. //--------------find---------------------------------------------------
  60. // Ein 'IComparable' ding im Baum suchen.
  61. // Erzeugt die exception NO_SUCH_NODE, falls der Knoten nicht gefunden
  62. // wird. Sonst wird die Methode visit für den gefundenen Knoten
  63. // ausgeführt:
  64. public void find( IComparable ding )
  65. {
  66. rec_find( ding, root );
  67. }
  68.  
  69. //--------------deleteAll----------------------------------------------
  70. // Entfernt den gesamten Knoten mit Inhalt ding. Der Wert des Zählers
  71. // für identische Knoten wird dabei nicht beachtet.
  72. public void deleteAll(IComparable ding)
  73. {
  74. rec_deleteAll(ding, ref root);
  75. }
  76.  
  77. //--------------depth--------------------------------------------------
  78. // Die Tiefe des Baums bestimmen.
  79. // Erzeugt evtl. die exception EMPTY_TREE
  80. public int depth()
  81. {
  82. max_depth = 0;
  83. actual_depth = 0;
  84.  
  85. if( root == null ) throw new EMPTY_TREE();
  86.  
  87. rec_depth( root );
  88.  
  89. return max_depth - 1; // Baum mit einem Knoten -> Tiefe 0 !
  90. }
  91.  
  92. //--------------nodes--------------------------------------------------
  93. // Liefert die Anzahl aller Knoten, mehrfach vorhandene Knoten
  94. // werden mitgezählt.
  95. public int nodes()
  96. {
  97. no_of_nodes = 0;
  98.  
  99. rec_nodes( root );
  100.  
  101. return no_of_nodes;
  102. }
  103.  
  104. //--------------nodes_RString------------------------------------------
  105. // Liefert die Anzahl aller Knoten rechtsbündig in einem 6-stelligen
  106. // string. Mehrfach vorhandene Knoten werden mitgezählt.
  107. public string nodes_RString()
  108. {
  109. return nodes().ToString().PadLeft( 6, ' ' );
  110. }
  111.  
  112. //--------------non_ident_nodes----------------------------------------
  113. // Liefert die Anzahl nicht identischer Knoten, mehrfach vorhandene
  114. // Knoten werden nicht mitgezählt.
  115. public int non_ident_nodes()
  116. {
  117. no_of_non_ident_nodes = 0;
  118.  
  119. rec_non_ident_nodes( root );
  120.  
  121. return no_of_non_ident_nodes;
  122. }
  123.  
  124. //--------------non_ident_nodes_RString--------------------------------
  125. // Liefert die Anzahl aller Knoten rechtsbündig in einem 6-stelligen
  126. // string. Mehrfach vorhandene Knoten werden mitgezählt.
  127. public string non_ident_nodes_RString()
  128. {
  129. return non_ident_nodes().ToString().PadLeft( 6, ' ' );
  130. }
  131.  
  132. //--------------reset--------------------------------------------------
  133. public void reset()
  134. {
  135. root = null;
  136. max_depth = 0;
  137. actual_depth = 0;
  138. no_of_nodes = 0;
  139. no_of_non_ident_nodes = 0;
  140. }
  141.  
  142.  
  143. ///////////////////////////////////////////////////////////////////////
  144. // protected / private part:
  145. ///////////////////////////////////////////////////////////////////////
  146.  
  147. private Node root;
  148.  
  149. private int max_depth; // Tiefe des Baums
  150. private int actual_depth; // momentane Tiefe
  151. private int no_of_nodes; // Anzahl aller Knoten
  152. private int no_of_non_ident_nodes; // Anzahl nicht identischer Knoten
  153.  
  154.  
  155. //--------------rec_insert---------------------------------------------
  156. private void rec_insert( IComparable ding , ref Node tree )
  157. {
  158. if( tree == null )// Einfügeposition gefunden, neuen Knoten anlegen:
  159. {
  160. tree = new Node();
  161.  
  162. // Daten in neuen Knoten schreiben:
  163. tree.left = null;
  164. tree.info = ding;
  165. tree.right = null;
  166. tree.count = 1;
  167. }
  168. else
  169. {
  170. if( ding.CompareTo(tree.info) < 0 ) // links weiter suchen:
  171. rec_insert( ding, ref tree.left );
  172.  
  173. else if ( ding.CompareTo(tree.info) > 0 ) // rechts weiter suchen:
  174. rec_insert( ding, ref tree.right );
  175.  
  176. else // gleiches Ding gefunden, Anzahl inkrementieren:
  177. tree.count = tree.count + 1;
  178. }
  179. }
  180.  
  181. //--------------rec_traverse_inorder-----------------------------------
  182. private void rec_traverse_inorder( Node tree )
  183. {
  184. if (tree != null)
  185. {
  186. rec_traverse_inorder(tree.left);
  187. visit(tree.info, tree.count);
  188. rec_traverse_inorder(tree.right);
  189. }
  190. }
  191.  
  192. //--------------rec_traverse_inorder_invert----------------------------
  193. private void rec_traverse_inorder_invert( Node tree )
  194. {
  195. if (tree != null)
  196. {
  197. rec_traverse_inorder_invert(tree.right);
  198. visit(tree.info, tree.count);
  199. rec_traverse_inorder_invert(tree.left);
  200. }
  201. }
  202.  
  203. //--------------rec_find-----------------------------------------------
  204. private void rec_find(IComparable ding, Node tree)
  205. {
  206.  
  207. if (tree == null)
  208. {
  209. throw new NO_SUCH_NODE();
  210. }
  211. else
  212. {
  213. if (ding.CompareTo(tree.info) < 0)
  214. {
  215. rec_find(ding, tree.left);
  216. }
  217. else if (ding.CompareTo(tree.info) > 0)
  218. {
  219. rec_find(ding, tree.right);
  220. }
  221. else if (ding.CompareTo(tree.info) == 0)
  222. {
  223. Console.WriteLine("Knoten mit Inhalt '" + tree.info + "' wurde gefunden");
  224. }
  225. }
  226. }
  227.  
  228. //--------------findMin------------------------------------------------
  229. // Sucht kleinstes Element im Baum tree.
  230. // Diese Methode wird von rec_deleteAll aufgerufen.
  231. private Node findMin(Node tree)
  232. {
  233. if (tree == null)
  234. {
  235. throw new NO_SUCH_NODE();
  236. }
  237. else
  238. {
  239. if (tree.left == null)
  240. {
  241. return tree;
  242. }
  243. else
  244. {
  245. return findMin(tree.left);
  246. }
  247. }
  248. }
  249.  
  250. //--------------rec_deleteAll------------------------------------------
  251. private void rec_deleteAll(IComparable ding, ref Node tree)
  252. {
  253. if (tree == null)
  254. throw new NO_SUCH_NODE();
  255. else
  256. {
  257. if (ding.CompareTo(tree.info) < 0)
  258. rec_deleteAll(ding, ref tree.left);
  259. else if (ding.CompareTo(tree.info) > 0)
  260. rec_deleteAll(ding, ref tree.right);
  261. else
  262. {
  263. //Knoten ist Blatt -> Ref auf ihn wird gelöscht
  264. if (tree.left == null && tree.right == null)
  265. {
  266. tree = null;
  267. }
  268. //Knoten hat keinen rechten Nachfolger
  269. else if (tree.left != null && tree.right == null)
  270. {
  271. tree = tree.left;
  272. tree.left = null;
  273. }
  274. //Knoten hat keinen linken Nachfolger
  275. else if (tree.left == null && tree.right != null)
  276. {
  277. tree = tree.right;
  278. tree.right = null;
  279. }
  280.  
  281. //Knoten hat zwei Childs
  282. else if (tree.left != null && tree.right != null)
  283. {
  284. tree.info = findMin(tree.right).info;
  285. tree.count = findMin(tree.right).count;
  286. rec_deleteAll(tree.info, ref tree.right);
  287. }
  288. }
  289. }
  290. }
  291.  
  292. //--------------visit--------------------------------------------------
  293. // visit wird beim Besuch eines Knotens ausgeführt.
  294. // Hier: ding und die entspr. Anzahl werden in einer Zeile auf der
  295. // Console ausgegeben.
  296. //
  297. // visit muss in Subclasses angepasst, also überschrieben werden.
  298. //
  299. protected virtual void visit( IComparable ding, int anzahl )
  300. {
  301. int zProZeile = 60; // Zeichen pro Ausgabezeile
  302.  
  303. string str = ( anzahl.ToString() +
  304. Environment.NewLine ).PadLeft( zProZeile, '.' );
  305.  
  306. str = ding + str.Substring( ding.ToString().Length,
  307. str.Length - ding.ToString().Length );
  308.  
  309. Console.Write( str );
  310. }
  311.  
  312. //--------------rec_depth----------------------------------------------
  313. // Berechnet die maximale Tiefe des Baums.
  314. // Zur Implementation: Vor jedem rekursiven Aufruf wird der Zähler
  315. // inkrementiert (beim "Abstieg"), nach jedem rekursiven Aufruf wird
  316. // der Zähler dekrementiert (beim "Aufstieg").
  317. private void rec_depth( Node tree )
  318. {
  319. if( tree != null )
  320. {
  321. actual_depth = actual_depth + 1;
  322. if ( actual_depth > max_depth )
  323. max_depth = actual_depth;
  324.  
  325. rec_depth( tree.left);
  326.  
  327. //actual_depth = actual_depth - 1;
  328. //actual_depth = actual_depth + 1;
  329. //if (actual_depth > max_depth)
  330. // max_depth = actual_depth;
  331.  
  332. rec_depth( tree.right);
  333.  
  334. actual_depth = actual_depth - 1;
  335. }
  336. }
  337.  
  338. //--------------rec_nodes----------------------------------------------
  339. // Zählt alle Knoten mit einer preorder-Durchmusterung.
  340. private void rec_nodes( Node tree )
  341. {
  342. if (tree != null)
  343. {
  344. no_of_nodes = no_of_nodes + tree.count;
  345.  
  346. rec_nodes( tree.right);
  347. rec_nodes( tree.left);
  348. }
  349. }
  350.  
  351. //--------------rec_non_ident_nodes------------------------------------
  352. // Zählt alle nicht identischen Knoten mit einer preorder-Durchmusterung.
  353. private void rec_non_ident_nodes( Node tree )
  354. {
  355. if (tree != null)
  356. {
  357. no_of_non_ident_nodes = no_of_non_ident_nodes + 1;
  358.  
  359. rec_non_ident_nodes( tree.right);
  360. rec_non_ident_nodes( tree.left);
  361. }
  362. }
  363.  
  364. }
  365. }
  366.