Commit 57de152

mo khan <mo.khan@gmail.com>
2020-09-20 23:41:28
refactor: change colouring algorithm
1 parent 2a9f5f3
src/03/avl_tree.c
@@ -188,28 +188,54 @@ static bool is_odd(int value) {
   return !is_even(value);
 }
 
-RBTree *_avl_tree_to_rb_tree(AVLTree *tree, AVLTree *parent) {
+static RBTree *to_rb_tree(AVLTree *tree, AVLTree *parent) {
   if (!tree)
     return NULL;
 
-  enum Colour colour = (parent && is_even(parent->height) && is_odd(tree->height)) ? red : black;
-  RBTree *rb_tree = rb_tree_initialize_with(tree->value, colour);
+  RBTree *rb_tree = rb_tree_initialize(tree->value);
 
-  rb_tree->left = _avl_tree_to_rb_tree(tree->left, tree);
+  rb_tree->left = to_rb_tree(tree->left, tree);
   if (rb_tree->left)
     rb_tree->left->parent = rb_tree;
 
-  rb_tree->right = _avl_tree_to_rb_tree(tree->right, tree);
+  rb_tree->right = to_rb_tree(tree->right, tree);
   if (rb_tree->right)
     rb_tree->right->parent = rb_tree;
   return rb_tree;
 }
 
+static void colour_children(RBTree *a, RBTree *b);
+
+static void colour(RBTree* tree, enum Colour colour) {
+  if (!tree)
+    return;
+
+  tree->colour = colour;
+  colour_children(tree->left, tree->right);
+}
+
+static void colour_children(RBTree *a, RBTree *b) {
+  int a_height = rb_tree_height(a);
+  int b_height = rb_tree_height(b);
+
+  if (a_height < b_height || is_odd(a_height))
+    colour(a, black);
+  else
+    colour(a, red);
+
+  if (b_height < a_height || is_odd(b_height))
+    colour(b, black);
+  else
+    colour(b, red);
+}
+
 RBTree *avl_tree_to_rb_tree(AVLTree *tree) {
   if (!tree)
     return NULL;
 
-  return _avl_tree_to_rb_tree(tree, NULL);
+  RBTree *rb_tree = to_rb_tree(tree, NULL);
+  colour(rb_tree, black);
+  return rb_tree;
 }
 
 void avl_tree_inspect(AVLTree *tree) {
src/03/avl_tree_test.c
@@ -326,8 +326,11 @@ Ensure(to_rb_tree_returns_a_new_red_black_tree) {
     expected = rb_tree_insert(expected, items[i]);
   }
 
-  RBTree *rb_tree = avl_tree_to_rb_tree(tree);
-  assert_that(rb_equals(expected, rb_tree), is_equal_to(true));
+  RBTree *actual = avl_tree_to_rb_tree(tree);
+
+  assert_that(rb_equals(expected, actual), is_equal_to(true));
+  assert_that(rb_tree_is_valid(actual), is_equal_to(true));
+  assert_that(rb_tree_is_valid(expected), is_equal_to(true));
 }
 
 Ensure(to_rb_tree_handles_trees_with_a_large_depth) {
src/03/rb_tree.c
@@ -176,7 +176,7 @@ static void print_tree(RBTree *tree, int level) {
     printf(" ");
 
   if (tree) {
-    printf("(%d:%c P:%d)\n", tree->value, tree->colour == red ? 'R' : 'B', tree->parent ? tree->parent->value : -1);
+    printf("(%d%c H:%d)\n", tree->value, tree->colour == red ? 'R' : 'B', rb_tree_height(tree));
 
     if (!tree->left && !tree->right)
       return;
@@ -261,3 +261,10 @@ bool rb_tree_is_valid(RBTree *tree) {
 
   return rb_tree_is_valid(tree->left) && rb_tree_is_valid(tree->right);
 }
+
+int rb_tree_height(RBTree *tree) {
+  if (!tree)
+    return 1;
+
+  return 1 + max(rb_tree_height(tree->left), rb_tree_height(tree->right));
+}
src/03/rb_tree.h
@@ -20,3 +20,4 @@ bool rb_equals(RBTree *tree, RBTree *other_tree);
 bool rb_tree_is_valid(RBTree *tree);
 int rb_tree_size(RBTree *tree);
 void rb_tree_inspect(RBTree *tree);
+int rb_tree_height(RBTree *tree);
src/03/rb_tree_test.c
@@ -277,6 +277,24 @@ Ensure(is_valid_return_true) {
   assert_that(rb_tree_is_valid(tree), is_equal_to(true));
 }
 
+Ensure(height_returns_one) {
+  assert_that(rb_tree_height(NULL), is_equal_to(1));
+}
+
+Ensure(height_returns_three_when_left_subtree_is_present) {
+  RBTree *tree = rb_tree_initialize(10);
+  tree = rb_tree_insert(tree, 5);
+
+  assert_that(rb_tree_height(tree), is_equal_to(3));
+}
+
+Ensure(height_returns_three_when_right_subtree_is_present) {
+  RBTree *tree = rb_tree_initialize(10);
+  tree = rb_tree_insert(tree, 15);
+
+  assert_that(rb_tree_height(tree), is_equal_to(3));
+}
+
 TestSuite *rb_tree_tests() {
   TestSuite *x = create_test_suite();
 
@@ -305,5 +323,9 @@ TestSuite *rb_tree_tests() {
   add_test(x, is_valid_returns_false_when_red_node_has_red_child);
   add_test(x, is_valid_returns_false_when_each_path_to_leaves_does_not_contain_the_same_number_of_black_nodes);
   add_test(x, is_valid_return_true);
+
+  add_test(x, height_returns_one);
+  add_test(x, height_returns_three_when_left_subtree_is_present);
+  add_test(x, height_returns_three_when_right_subtree_is_present);
   return x;
 }