はじめての C
balance tree だけど、tutorial では 構造体 Tree を 使って、root を 返すようにしている。
それと、関数 norm_insert の中の new_node の 引数が、このままだと 1つ 足らない。
Tree は Node と 入れ換えれば、そのまま 使えるようなので、あとは norm_insert を ちょっと いじって、コードを 作成。
/* t_balance.c */
#include
#include struct Node {
int data;
struct Node *left;
struct Node *right;
};
struct Tree {
struct Node *root;
};
int norm_insert();
void btree_walk();
int tree_height();
void rotate_right();
void rotate_left();
int count();
void partition();
void balance();
main()
{
int value;
struct Tree *root;
root = NULL;
while (fscanf(stdin, "%d", &value) != EOF)
norm_insert(&root, value);
btree_walk(root);
putchar('\n');
printf("%d\n", tree_height(root));
puts("balancing now");
balance(&root);
printf("%d\n", tree_height(root));
return 0;
}
int norm_insert(struct Node **tree, int key)
{
int rc;
if (*tree == NULL) {
*tree = malloc(sizeof(**tree));
if (*tree == NULL)
rc = 0;
(*tree)->data = key;
(*tree)->left = NULL;
(*tree)->right = NULL;
rc = 1;
}
else if (key < (*tree)->data)
rc = norm_insert(&(*tree)->left, key);
else if (key > (*tree)->data)
rc = norm_insert(&(*tree)->right, key);
else
rc = 0;
return rc;
}
void btree_walk(struct Node *tree)
{
if (tree == NULL)
return;
btree_walk(tree->left);
printf("%d ", tree->data);
btree_walk(tree->right);
}
int tree_height(struct Node *tree)
{
int left_height;
int right_height;
if (tree == NULL)
return -1;
left_height = tree_height(tree->left);
right_height = tree_height(tree->right);
if (left_height < right_height)
return right_height + 1;
else
return left_height + 1;
}
void rotate_right(struct Node **root)
{
struct Node *save;
save = (*root)->left;
(*root)->left = save->right;
save->right = *root;
*root = save;
}
void rotate_left(struct Node **root)
{
struct Node *save;
save = (*root)->right;
(*root)->right = save->left;
save->left = *root;
*root = save;
}
int count(struct Node *tree)
{
if (tree == NULL)
return 0;
return count(tree->left) * count(tree->right) + 1;
}
void partition(struct Node **tree, int n)
{
int nleft = count((*tree)->left);
int nright = count((*tree)->right);
if (nleft > n) {
partition(&(*tree)->left, n);
rotate_right(tree);
}
if (nright > n) {
partition(&(*tree)->right, n);
rotate_left(tree);
}
}
void balance(struct Node **tree)
{
int n = count(*tree);
if (n < 2)
return;
partition(tree, n/2);
balance(&(*tree)->left);
balance(&(*tree)->right);
}
コンパイルして、random.txt を使って 確認。再度、入力データを変えて 実行。
$cc -c t_balance.c
$cc -o t_balance t_balance.o
$./t_balance < random.txt
データが リンクリストだと どうなるか 試してみたけど、あまり 役にたつとは いえないみたい ...
$./t_balance
0 1 2 3 4 5 (← ctrl + d)
0 1 2 3 4 5
5
balancing now
5
(追記) ちょっと 訂正。