// recursion.c -- 2分木を扱う再帰関数の例

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

// 2分木のデータ構造

typedef struct _tree {
  char           node;     // 節のデータ (1文字)
  struct _tree  *left;     // 左の子へのポインタ
  struct _tree  *right;    // 右の子へのポインタ
} Tree;

// 2分木の節の生成

Tree *node(char c, Tree *l, Tree *r) {
  Tree *t = (Tree *) malloc(sizeof(Tree));
  if (t == NULL) {
    perror("malloc() failed in node()");
    exit(EXIT_FAILURE);
  }
  t->node  = c;
  t->left  = l;
  t->right = r;
  return t;
}

// 2分木の葉の生成

Tree *leaf(char c) {
  return node(c, NULL, NULL);
}

// 木を再帰的に表示

void show(const Tree *t) {
  if (t == NULL) {
    putchar('#');
  } else {
    putchar(t->node);
    putchar('(');
    show(t->left);
    putchar(',');
    show(t->right);
    putchar(')');
  }
}

// 木の大きさ(節の総数)を再帰的に計算

int size(const Tree *t) {
  if (t == NULL) return 0;
  else           return (size(t->left) + size(t->right) + 1);
}

// 木の大きさの再帰計算の様子を表示

int display(const Tree *t) {
  static int depth = -1;
  int i, size;
  depth++;

  // 関数の開始直後,節情報を表示
  for (i = 1; i <= depth; i++) printf(">       ");
  if (t == NULL) printf("#\n");
  else           printf("'%c'\n", t->node);

  // 節数の計算本体
  if (t == NULL) size = 0;
  else           size = display(t->left) + display(t->right) + 1;

  // 関数の終了直前,部分木の大きさを表示
  for (i = 1; i <= depth; i++) printf(">       ");
  printf("size = %d\n", size);

  depth--;
  return size;
}

// 木を表す文字列,木の節数,節数の再帰計算の過程 を順に表示

int main(void) {

  Tree *t = node('+',   // 算術式 a*b + c/d を表す木
                 node('*', leaf('a'), leaf('b')),
                 node('/', leaf('c'), leaf('d'))
                 );

  printf("t = "); show(t); putchar('\n');
  printf("size(t) = %d\n", size(t));
  printf("computation of size(t) :\n"); display(t);
  // 処理を続けるなら t が指す木の記憶域を開放する

  return EXIT_SUCCESS;
}