EPICS ARCHIVER V4
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups
AVLTree.h
1 // ------------------ -*- c++ -*- -------------------------
2 // $Id: AVLTree.h,v 1.4 2006/05/12 20:36:50 kasemir Exp $
3 //
4 // Please refer to NOTICE.txt,
5 // included as part of this distribution,
6 // for legal information.
7 //
8 // Kay-Uwe Kasemir, kasemir@lanl.gov
9 // --------------------------------------------------------
10 
11 #ifndef __AVL_TREE_H
12 #define __AVL_TREE_H
13 
14 // tools
15 #include "tools/GenericException.h"
16 #include "tools/AutoFilePtr.h"
17 
18 template<class Item> const char* toString(const Item& i);
19 template<class Item> int sort_compare(const Item& i1, const Item& i2);
20 
23 
26 template<class Item> class AVLItem {
27 
28 public:
29 
31  AVLItem(const Item &i)
32  : item(i), left(0), right(0), balance(0)
33  {}
34 
36  Item item;
37 
40 
43 
45  short balance;
46 
47 private:
48 
49  PROHIBIT_DEFAULT_COPY(AVLItem);
50 
51 };
52 
58 template<class Item> int sort_compare(const Item& a, const Item& b);
59 
64 template<class Item> class AVLTree
65 {
66 public:
67  AVLTree()
68  { root = 0; }
69 
70  ~AVLTree()
71  { clear(); }
72 
75  void add(const Item &item)
76  {
77  try
78  {
79  AVLItem<Item> *n = new AVLItem<Item>(item);
80  insert(n, &root);
81  }
82  catch (...)
83  {
84  throw GenericException(__FILE__, __LINE__, "AVLTree::add failed");
85  }
86  }
87 
89 
93  bool find(Item &item)
94  {
95  AVLItem<Item> *n = root;
96  int comp;
97  while (n)
98  {
99  comp = sort_compare(item, n->item);
100  if (comp == 0)
101  {
102  item = n->item;
103  return true;
104  }
105  else if (comp >0)
106  n = n->left;
107  else
108  n = n->right;
109  }
110  return false;
111  }
112 
114  void traverse(void (*visit) (const Item &, void *), void *arg=0)
115  { visit_inorder (visit, root, arg); }
116 
118  void clear()
119  {
120  cleanup(root);
121  root = 0;
122  }
123 
125 
129  void make_dotfile(const char *name);
130 
132  bool selftest()
133  { return check_balance(root); }
134 
135 private:
136  PROHIBIT_DEFAULT_COPY(AVLTree);
137  AVLItem<Item> *root;
138 
139  void rotate_right(AVLItem<Item> **node)
140  {
141  if ((*node)->left->balance == 1)
142  rotate_left(&(*node)->left);
143  AVLItem<Item> *l = (*node)->left;
144  (*node)->left = l->right;
145  l->right = *node;
146  // Stole the balance recalc from Brad Appleton, http://www.bradapp.net
147  if (l->balance == -1)
148  (*node)->balance += 2;
149  else
150  (*node)->balance += 1;
151 
152  if ((*node)->balance == 1)
153  l->balance += 2;
154  else
155  l->balance += 1;
156  *node = l;
157  }
158 
159  void rotate_left(AVLItem<Item> **node)
160  {
161  if ((*node)->right->balance == -1)
162  rotate_right(&(*node)->right);
163  AVLItem<Item> *r = (*node)->right;
164  (*node)->right = r->left;
165  r->left = *node;
166 
167  if (r->balance == 1)
168  (*node)->balance -= 2;
169  else
170  (*node)->balance -= 1;
171 
172  if ((*node)->balance == -1)
173  r->balance -= 2;
174  else
175  r->balance -= 1;
176  *node = r;
177  }
178 
179  // Result: Did we grow the tree from *node on down?
180  bool insert(AVLItem<Item> *new_node, AVLItem<Item> **node)
181  {
182  if (*node == 0)
183  {
184  *node = new_node;
185  return true;
186  }
187  int comp = sort_compare(new_node->item, (*node)->item);
188  if (comp == 0)
189  { // Don't insert new node, only update data item
190  (*node)->item = new_node->item;
191  delete new_node;
192  return false;
193  }
194  if (comp > 0)
195  {
196  if (insert(new_node, & ((*node)->left)))
197  {
198  --(*node)->balance;
199  if ((*node)->balance < -1)
200  {
201  rotate_right(node);
202  return false;
203  }
204  return (*node)->balance < 0;
205  }
206  }
207  else if (comp < 0)
208  {
209  if (insert(new_node, & ((*node)->right)))
210  {
211  ++(*node)->balance;
212  if ((*node)->balance > 1)
213  {
214  rotate_left(node);
215  return false;
216  }
217  return (*node)->balance > 0;
218  }
219  }
220  return false;
221  }
222 
223  void visit_inorder(void (*visit) (const Item &, void *),
224  AVLItem<Item> *node, void *arg)
225  {
226  if (node)
227  {
228  visit_inorder(visit, node->left, arg);
229  visit(node->item, arg);
230  visit_inorder(visit, node->right, arg);
231  }
232  }
233 
234  void print_dot_node(FILE *f, AVLItem<Item> *node, int &i)
235  {
236  ++i;
237  int me = i;
238  fprintf(f, "n%d [ label=\"%s (%d)\" ];\n",
239  me, toString(node->item), (int)node->balance);
240  if (node->left)
241  {
242  fprintf(f, "n%d -> n%d\n", me, i+1);
243  print_dot_node(f, node->left, i);
244  }
245  if (node->right)
246  {
247  fprintf(f, "n%d -> n%d\n", me, i+1);
248  print_dot_node(f, node->right, i);
249  }
250  }
251 
252  void cleanup(AVLItem<Item> *node)
253  {
254  if (node)
255  {
256  cleanup(node->left);
257  cleanup(node->right);
258  delete node;
259  }
260  }
261 
262  int height(AVLItem<Item> *node)
263  {
264  if (node == 0)
265  return 0;
266  int l = height(node->left)+1;
267  int r = height(node->right)+1;
268  return (l>r) ? l : r;
269  }
270 
271  // balance should be -1, 0, 1
272  // and match the actual sub-tree-height difference
273  bool check_balance(AVLItem<Item> *node)
274  {
275  if (node == 0)
276  return true;
277  if (node->balance < -1 ||
278  node->balance > 1)
279  return false;
280  if (node->balance !=
281  height(node->right) - height(node->left))
282  return false;
283  return check_balance(node->left) &&
284  check_balance(node->right);
285  }
286 };
287 
288 template<class Item>
289 void AVLTree<Item>::make_dotfile(const char *name)
290 {
291  char filename[200];
292  int i;
293  sprintf(filename, "%s.dot", name);
294  try
295  {
296  AutoFilePtr f(filename, "wt");
297  if (!f)
298  return;
299  fprintf(f, "# dot -Tpng %s.dot -o %s.png && eog %s.png\n",
300  name, name, name);
301  fprintf(f, "\n");
302  fprintf(f, "digraph AVLTree\n");
303  fprintf(f, "{\n");
304  i=0;
305  print_dot_node(f, root, i);
306  fprintf(f, "}\n");
307  }
308  catch (...) {}
309 }
310 
312 
313 #endif
314 
int sort_compare(const Item &i1, const Item &i2)
Comparison function used by AVLTree.
void make_dotfile(const char *name)
Generates a graphviz &#39;dot&#39; file.
Definition: AVLTree.h:289
void clear()
Delete all tree entries.
Definition: AVLTree.h:118
bool find(Item &item)
Try to find item in tree.
Definition: AVLTree.h:93
AVL-type balanced tree.
Definition: AVLTree.h:64
Auto-close FILE pointer wrapper.
Definition: AutoFilePtr.h:15
short balance
balance
Definition: AVLTree.h:45
Item item
item
Definition: AVLTree.h:36
AVL tree item.
Definition: AVLTree.h:26
AVLItem * left
Left pointer.
Definition: AVLTree.h:39
bool selftest()
Tests if the tree is AVL-balanced.
Definition: AVLTree.h:132
AVLItem(const Item &i)
Constructor.
Definition: AVLTree.h:31
Generic Exception: Base class for exceptions.
Definition: GenericException.h:45
void traverse(void(*visit)(const Item &, void *), void *arg=0)
Sorted (inorder) traverse, calling visitor routine on each item.
Definition: AVLTree.h:114
AVLItem * right
Right pointer.
Definition: AVLTree.h:42
void add(const Item &item)
Add (copy) Item into the tree.
Definition: AVLTree.h:75