АВТ
Language:

Remote Training on Programming

Problems On-line status Contests FAQ
For authors:
Register  ||  Login
 
Hello, Guest! Login or register.

243. Trees

Time Limit: 1 seconds
Memory Limit:8000KB
Points:5
View Problem Statistics Submit Problem added Undefined

Создайте иерархию классов, изображенную на следующем рисунке:

 

Базовый класс Tree описывает структуру данных "упорядоченное дерево" в общем виде.

Классы-наследники соответствуют двум вариантам реализации:

  • LR_Tree – на основе представления «левый сын-правый брат»
  • Ar_Tree – указатели на детей для каждого узла хранятся в массиве внутри него

 

Классы имеют следующий интерфейс:

//базовый класс дерево
class Tree
{
public:

  // тип данных для вершин дерева
  struct Node
  {
    int data; //некие данные, хранящиеся в узлах (например, номера)
    friend class Tree;
    //виртуальный деструктор - для корректного удаления потомков
    //через указатели на предков
    virtual ~Node(){};
  };


protected:

  //корень дерева
  Node *_root;

public:

  Tree(void);
  virtual ~Tree(void);

  //количество узлов в дерево
  int size(void) const;

  //возвратить указатель на корень дерева
  Node* root(void);

  //----виртуальные абстрактные функции - здесь описывается только их вид,
  //а реализовываться они будут по-разному в классах-наследниках-----

  //возвратить первого сына узла n
  virtual Node* first_child(const Node *n) const=0;

  //возвратить следующего сына узла n
  virtual Node* next_child(const Node *n, const Node *c) const=0;

  //возвратить родителя узла n
  virtual Node* parent(const Node *n) const=0;

  //создать нового сына для узла parent, поставить его в конец других
  //детей (для упрощения проверки :-) ) и возвратить указатель на него
  //если создаётся новый корень, то указывается parent=NULL
  virtual Node* new_node(Node *parent) = 0;

  //удалить поддерево с корнем в указанной вершине
  virtual void delete_subtree(Node *node) = 0;

  //----функции обхода деревьев - реализуйте посредством вызова виртуальных функций----

  //тип данных - указатель на функцию пользователя
  typedef void (*userfunc) (Node *node, int level);

  //выполнить обход в глубину, для каждого узла вызвать функцию f,
  //куда передать узел и его глубину
  //дети каждого узла должны перебираться в том порядке, в каком они хранятся 
  void dfs(userfunc f);

  //выполнить обход в ширину, для каждого узла вызывать функцию f
  //куда передать узел и его глубину
  //дети каждого узла должны перебираться в том порядке, в каком они хранятся
  void bfs(userfunc f);

  //-----функции класса-----
  static int trees_count(void) {//количество деревьев, в данный момент созданных в программе
    return trees_cnt;
  }

private:

};

///////////////////////////////////////////////////////////////////
//конкретная реализация №1 - представление "левый сын-правый брат"
///////////////////////////////////////////////////////////////////
class LR_Tree : public Tree
{

public:

  struct LR_Node : public Node
  {
    //расширьте структуру так, как считаете нужным
  };

  //выполните реализации всех виртуальных функций, описанных в базовом классе
  virtual Node* first_child(const Node *n) const;
  virtual Node* next_child(const Node *n, const Node *c) const;
  virtual Node* parent(const Node *n) const;
  virtual Node* new_node(Node *parent);
  virtual void delete_subtree(Node *node);

  //создайте необходимые конструкторы, деструктор, перегрузите операцию присваивания
  LR_Tree& operator= (const LR_Tree &r); //операция присваивания
  LR_Tree(void){};
  LR_Tree(const LR_Tree &r); //копировщик
  virtual ~LR_Tree(void); //деструктор

};

/////////////////////////////////////////////////////////////
//конкретная реализация №2 для не сильно ветвистых деревьев -
//в каждом узле хранится массив указателей на детей
/////////////////////////////////////////////////////////////
class Ar_Tree : public Tree
{
public:

  struct Ar_Node : public Node
  {
    //расширьте структуру так, как считаете нужным
  };

  //конструктор, в качестве параметра принимающий максимальную "ветвистость"
  //дерева, т.е. размер массивов детей в узлах дерева
  Ar_Tree(int branchiness);

  //выполните реализации всех виртуальных функций, описанных в базовом классе
  virtual Node* first_child(const Node *n) const;
  virtual Node* next_child(const Node *n, const Node *c) const;
  virtual Node* parent(const Node *n) const;
  virtual Node* new_node(Node *parent);
  virtual void delete_subtree(Node *node);

  //создайте деструктор, перегрузите операцию присваивания и др., если что ещё нужно

  Ar_Tree(const Ar_Tree &r); //копировщик
  virtual Ar_Tree::~Ar_Tree(void);   //деструктор
  Ar_Tree& operator= (const Ar_Tree &r); //операция присваивания

};


//во все классы можно добавлять любые недостающие данные
//(желательно только в разделы private и protected)

//это должно стоять в конце вашего кода при отправке в систему
#include "trees-test.h"

//ваш код не должен содержать функцию main
Пример проверок, которые будут выполняться над вашим классом:
//простой вывод в строчку
void myfunc1(Tree::Node *node, int level)
{
  cout << node->data << " ";
}

void test1(void){

  Tree* trees[2]; //массив из нескольких деревьев

  //создаём сильноветвящееся дерево, заполняем в нём пару уровней
  trees[0] = new LR_Tree;
  Tree::Node *root = trees[0]->new_node(NULL); root->data = 1;
  for (int i=2; i<=4; i++)  {
    Tree::Node *node = trees[0]->new_node(root);
    node->data = i;
    for (int j=1000; j<=1001; j++)
    {
      Tree::Node *node2 = trees[0]->new_node(node);
      node2->data = j;
    }
  }

  //создаём не очень ветвящееся дерево, заполняем несколько уровней
  trees[1] = new Ar_Tree(3);
  Tree::Node *root2 = trees[1]->new_node(NULL); root2->data = 1;
  for (int i=2; i<=3; i++)  {
    Tree::Node *node = trees[1]->new_node(root2);
    node->data = i;
    for (int j=4; j<=6; j++)
    {
      Tree::Node *node2 = trees[1]->new_node(node);
      node2->data = j;
    }
  }

  //выполняем разные обходы и выводим их на экран разными способами
  for(int i=0; i<2; i++)
  {
    trees[i]->dfs(myfunc1); cout << endl;
    trees[i]->bfs(myfunc1); cout << endl;
  }

  //проверяем, как работает перечисление сыновей узла
  for(int i=0; i<2; i++) {
    Tree::Node *root = trees[i]->root();
    Tree::Node *node = trees[i]->first_child(root);
    while (node!=NULL)
    {
      cout << node->data << " ";
      node = trees[i]->next_child(root,node);
    }
    cout << endl;
  }

  //проверяем, как работает удаление поддеревьев
  for(int i=0; i<2; i++)
  {
    Tree::Node *node = trees[i]->first_child(trees[i]->root());
    trees[i]->delete_subtree(node);
    trees[i]->bfs(myfunc1); cout << endl;
  }

  //удаляем деревья
  for(int i=0; i<2; i++)
    delete trees[i];

}
Пример результата, который должен получиться:
1 2 1000 1001 3 1000 1001 4 1000 1001 
1 2 3 4 1000 1001 1000 1001 1000 1001 
1 2 4 5 6 3 4 5 6 
1 2 3 4 5 6 4 5 6 
2 3 4 
2 3 
1 3 4 1000 1001 1000 1001 
1 3 4 5 6 

View Problem Statistics Submit Author/source:
Educational Courses / Data Structures and Algorithms / Data Structures /
249. Power of number 2 243. 251. КЛП->ЛКП 252. ЛКП->КЛП 253. Луч
Educational Courses / C/C++for EPO-21 / Продолжение следует /
97. Progression 243.
We can all benefit by doing occasional "toy" programs, when artificial restrictions are set up, so that we are forced to push our abilities to the limit. The art of tackling miniproblems with all our energy will sharpen our talents for the real problems. Donald E. Knuth.
time generating 0.531 sec.
© Copyright VSTU, AVT, Nosov D.A.