views:

76

answers:

3

Hello, guys. I think I've created an AVL tree implementation, but as AVL Tree is quite a complex structure, I need to test it. So the question is - how can I test it? Have you got any ideas? Up to this moment I have the following tests:

  1. basic sanity check - checks that for every node height equals max. height of child nodes + 1, balance is in [-1, 1], left child's key < this node's key < right child's key, and there are no circular references (like left child of a node is a node himself);

  2. check that inorder traversal on an AVL tree (and on a binary search tree in the whole) will return values from the underlying set in order;

  3. check that an AVL tree's height is strictly less than 1.44*log2(N+2)-1 (there N is number of elements) - proved by AVL tree creators;

  4. visual check - doesn't work that well, I try to draw a tree (rootnode in the first line, his direct children on the next line, childen of rootnode's direct childen on the third line and so on), but that works only on small trees, for big trees it becomes a complete mess;

  5. (?????) Russian wikipedia says that it is proven experimentally, that for two insertions one rebalancing needed and for five removals also one rebalancing needed, but is it really so? English wikipedia says nothing about it, and for my AVL one rebalancing needed for two insertions or for four removals, which is not quite the same.

Maybe these tests are enough, but if there are any more tests, not difficult to implement, why not to do it?

+1  A: 

If you really want to hammer your implementation, you should do some black-box tests with lots of different insertion-order and removal-order patterns. Here are some ideas that come to mind:

  • Random order
  • Increasing order
  • Decreasing order
  • Interleave two streams, one with increasing, one with decreasing order
    • Start with similar values and diverge
    • Start at the ends and meet in the middle
    • Start at the ends and cross to opposite ends
  • Random-walk with upwards, downwards and neutral biases
  • Mix up insertions and removals in combinations of the above patterns.

You should not only test correctness, but also performance, subject to the above patterns, which may require building up largish data sets, so that you can meaningfully measure the performance. Everything is fast with 100 elements, but with 105 elements, the difference between O(N2) and O(N log N) will be huge.

You should also test for bad inputs, e.g., adding or removing the same value twice (assuming you don't allow duplicates).

Marcelo Cantos
I definitely like your idea about measuring performance.
Graf
+1  A: 

For insert and delete, there are a particular number (about five for each, I recall) of tree operations which can occur.

You need to set up a tree immediately prior to one of these operations such that adding another particular element will cause a known one of these operations to occur.

You then inspect the tree - dump it out. It'll be a fairly simple tree, no more than about ten elements.

If every insert/delete operation works correctly, you will have validated the vital core behaviour of your tree.

(Note, one of the (I think it was) insert operations cannot be checked in this way - it's an intermediate state which exists temporarily).

Blank Xavier
+1  A: 

A key property of an AVL tree is that each of its sub-trees is also an AVL tree. That means that covering the basic scenarios should give you a broad coverage of the AVL tree functionality.

In other words, these tests done on the smallest tree structure that allows them are the most important ones:

  • Creating a new tree.
  • Inserting the first value.
  • Inserting a bigger value.
  • Inserting a smaller value.
  • Inserting a value that causes LL Rotation.
  • Same for the other rotations.
  • Same for Removing.
  • All the variants of Finding values.

If your implementation passes these tests, it would probably pass them on larger trees. Note that performance and memory usage is not tested here.

dahunter
I like your idea about testing all possible rotations (LL, LR, RL, RR) - 4 cases for insert, 4 cases for removal.
Graf