#include <cassert>
#include <cstdlib>
#include <unistd.h>
#include <iostream>
#include <string>


// Deja vu, c++ style.

   struct tree_node;
   struct list_node;

static tree_node * tree_null = 0;
static list_node * list_null = 0;


struct tree_node {

  int val;
  tree_node * left, * right;

  tree_node(int val) : val(val), left(0), right(0) { }
 ~tree_node() { delete left; delete right; left = right = tree_null; }

  private:

    tree_node(const tree_node &) { 
      assert(!"calling the tree-node copy constructor"); }

    tree_node & operator = (const tree_node &) {
      assert(!"calling the tree-node assignment"); 
      return *this; 
      }
  };


struct list_node {
  
  int val;
  list_node * prev, * next;

  list_node(int v) : val(v), prev(0), next(0) { }
  list_node(int v, list_node * p, list_node * n) : val(v), prev(p), next(n) { }
 ~list_node() { delete next; next = prev = list_null; }

  private:

    list_node(const list_node &) { 
      assert(!"calling the list-node copy constructor"); }

    list_node & operator = (const list_node &) {
      assert(!"calling the list-node assignment");
      return *this; 
      }
  };


struct ptr_pair {
  list_node * begin, * end;
  ptr_pair(list_node * b, list_node * e) : begin(b), end(e) { }
  };


// Deja vu, c++ style;

   static tree_node * fold(const list_node *, unsigned);
   static list_node * make_list(unsigned &);
   static void print_list(std::ostream &, const list_node *);
   static void print_tree(std::ostream &, const tree_node *, std::string);
   static void run_test(bool);


static ptr_pair
flatten(const tree_node * root) {

  // Flatten the tree at the given root into a list, return pointers to the
  // ends of the list.

  if (root == tree_null)
    return ptr_pair(list_null, list_null);

  ptr_pair
    left_pp = flatten(root->left),
    right_pp = flatten(root->right);

  list_node * const mid = 
    new list_node(root->val, left_pp.end, right_pp.begin);

  if (mid->prev == list_null)
    left_pp.begin = mid;
  else
    mid->prev->next = mid;

  if (mid->next == list_null)
    right_pp.end = mid;
  else
    mid->next->prev = mid;

  return ptr_pair(left_pp.begin, right_pp.end);
  }


static tree_node *
fold(const list_node * head, unsigned size) {

  // Fold the given list of the given size into a tree, return a pointer to the
  // tree's root.

  if (size == 0)
    return tree_null;

  const unsigned h = size/2;
  const list_node * mid = head;
  for (unsigned i = h; i > 0; i--) {
    assert(mid);
    mid = mid->next;
    }
  assert(mid);

  tree_node * root = new tree_node(mid->val);

  if (size > 1) {
    root->left = fold(head, h);
    root->right = fold(mid->next, size - h - 1);
    }

  return root;
  }


static bool
list_same(const list_node * const lst1, const list_node * const lst2) {

  // Return the number of elements in the given list.

  if ((lst1 == list_null) and (lst2 == list_null))
    return true;
  if ((lst1 == list_null) or (lst2 == list_null))
    return false;

  return (lst1->val == lst2->val) and list_same(lst1->next, lst2->next);
  }


int 
main() {

  srandom(getpid());

  for (int i = 0; i < 10; i++)
    run_test(true);
  }


static list_node *
make_list(unsigned & size) {

  // Create and return a random list of integers.

  size = random() % 20;
  list_node head(0);
  list_node * tail = &head;

  for (unsigned i = 0; i < size; i++)
    tail = tail->next = new list_node(random() % 100, tail, list_null);
  if (head.next)
    head.next->prev = list_null;

  tail = head.next;
  head.next = list_null;

  return tail;
  }


static void
print_list(std::ostream & os, const list_node * head) {

  // Print the given list to the given output streaml.

  while (head) {
    os << head->val;
    os << " ";
    head = head->next;
    }
  os << "\n";
  }


static void
print_tree(std::ostream & os, const tree_node * root, std::string indent) {

  // Print the given tree to the given output stream, using the given indentation.

  if (root != tree_null) {
    os << indent << root->val << "\n";
    print_tree(os, root->left, indent + "  ");
    print_tree(os, root->right, indent + "  ");
    }
  }


static void
run_test(bool print) {

  // Run a folding-flattening test.

  unsigned size;
  const list_node * const lst = make_list(size);
  if (print) print_list(std::cout, lst);

  const tree_node * const tre = fold(lst, size);
  if (print) print_tree(std::cout, tre, "");

  const ptr_pair pp = flatten(tre);
  if (print) print_list(std::cout, pp.begin);

  assert(list_same(lst, pp.begin));
  }


// g++ -o tree-list -gstabs -ansi -pedantic -Wall tree-list.cc && ( ulimit -c 0 ; ./tree-list )


// $Log: tree-list.cc,v $
// Revision 1.1  2003/11/25 22:57:22  rclayton
// Initial revision
//


syntax highlighted by Code2HTML, v. 0.9