master
  1#include "btree.h"
  2#include "list.h"
  3#include "stack.h"
  4#include <stdio.h>
  5
  6/**
  7 * A helper function used to print a visual
  8 * representation of a binary tree.
  9 *
 10 * @param tree the tree or subtree to inspect
 11 * @param level the level of the subtree
 12 */
 13static void inspect(BTree *tree, int level) {
 14  if (!tree)
 15    return;
 16
 17  for (int i = 0; i < level; i++)
 18    printf("  ");
 19
 20  printf("%2d\n", tree->data);
 21  inspect(tree->left, level + 1);
 22  inspect(tree->right, level + 1);
 23}
 24
 25/**
 26 * Initializes an new subtree in a binary tree
 27 *
 28 * @param parent the parent of the new btree node
 29 * @param data the data to assign to the root of the tree.
 30 * @return Returns the new subtree
 31 */
 32BTree *btree_initialize(BTree *parent, int data) {
 33  BTree *tree = malloc(sizeof(BTree));
 34  tree->parent = parent;
 35  tree->left = NULL;
 36  tree->right = NULL;
 37  tree->data = data;
 38  return tree;
 39}
 40
 41/**
 42 * Converts a binary tree into a linked list
 43 * using an in order traversal.
 44 *
 45 * @param tree The binary tree to convert
 46 * @return Returns the head of a linked list.
 47 */
 48List *btree_to_list(BTree *tree) {
 49  if (tree == NULL)
 50    return NULL;
 51
 52  List *list = NULL;
 53  Stack *stack = stack_init();
 54  BTree *tmp = tree;
 55
 56  while (true) {
 57    if (tmp) {
 58      stack_push(stack, tmp);
 59      tmp = tmp->left;
 60    } else if (stack_size(stack) == 0) {
 61      break;
 62    } else {
 63      tmp = stack_pop(stack);
 64      if (list)
 65        list_add(list, tmp);
 66      else
 67        list = list_initialize(tree);
 68      tmp = tmp->right;
 69    }
 70  }
 71
 72  return list;
 73}
 74
 75/**
 76 * Calculates the size of a binary tree
 77 *
 78 * @param tree the tree to inspect
 79 * @return Returns the # of nodes in the binary tree.
 80 */
 81int btree_size(BTree *tree) {
 82  List *list = btree_to_list(tree);
 83  return list ? list_size(list) : 0;
 84}
 85
 86/**
 87 * Determines if a subtree in a binary tree
 88 * can be used as a scapegoat to rebalance
 89 * the tree.
 90 *
 91 * @param tree the subtree to investigate
 92 * @return Returns true then subtree can be used as a scapegoat.
 93 */
 94bool btree_is_scapegoat(BTree *tree) {
 95  int size = btree_size(tree);
 96  int parent_size = btree_size(tree->parent);
 97
 98  return ((size * 3) > (parent_size * 2));
 99}
100
101/**
102 * Rebuilds a subtree by converting it
103 * to a list then rebuilding a binary tree.
104 *
105 * @param tree The tree to rebuild
106 * @return Returns the new binary tree.
107 */
108BTree *btree_rebuild(BTree *tree) {
109  List *list = btree_to_list(tree->parent);
110  int mid = (list_size(list) / 2) - 1;
111  List *new_root = list_get(list, mid);
112  int data = ((BTree *)new_root->data)->data;
113  BTree *new_broot = btree_initialize(NULL, data);
114
115  for (int i = 0; i < list_size(list); i++) {
116    if (i == mid)
117      continue;
118
119    int data = ((BTree *)list_get(list, i)->data)->data;
120    btree_insert(new_broot, data);
121  }
122  return new_broot;
123}
124
125/**
126 * Rebalances a binary tree starting from
127 * the bottom up.
128 *
129 * @param tree the subtree to rebalance
130 * @return Returns the new root of the binary tree.
131 */
132BTree *btree_rebalance(BTree *tree) {
133  if (!tree->parent)
134    return tree;
135
136  if (btree_is_scapegoat(tree))
137    return btree_rebuild(tree);
138
139  return btree_rebalance(tree->parent);
140}
141
142/**
143 * Inserts a new node into a binary tree.
144 *
145 * @param tree the tree to insert the new new into
146 * @return Returns the root of the tree.
147 */
148BTree *btree_insert(BTree *tree, int data) {
149  if (!tree)
150    return btree_initialize(NULL, data);
151
152  if (data <= tree->data)
153    if (tree->left)
154      return btree_insert(tree->left, data);
155    else {
156      tree->left = btree_initialize(tree, data);
157      return btree_rebalance(tree->left);
158    }
159  else if (tree->right)
160    return btree_insert(tree->right, data);
161  else {
162    tree->right = btree_initialize(tree, data);
163    return btree_rebalance(tree->right);
164  }
165
166  return tree;
167}
168
169/**
170 * A helper function used to print
171 * a visual representation of a binary
172 * tree.
173 *
174 * @param tree The root of the tree to inspect
175 */
176void btree_inspect(BTree *tree) { inspect(tree, 0); }