АВТ
Язык:

Дистанционный практикум по программированию

Задачи Online статус Соревнования
Новости Справка СДО
 
Здравствуйте, Гость! Войдите с паролем или зарегистрируйтесь.

243. Деревья

Ограничение времени: 1 сек.
Ограничение памяти:65536 КБайт
Баллы:100
Статистика Послать на проверку Задачу добавил Неизвестный

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

 

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

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

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

 

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

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

  // тип данных для вершин дерева
  struct Node
  {
    int data; //некие данные, хранящиеся в узлах (например, номера)
    //виртуальный деструктор - для корректного удаления потомков
    //через указатели на предков
    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 

Статистика Послать на проверку Обсуждение задачи Автор/источник:
Учебные курсы / Алгоритмы и структуры данных / Структуры данных /
1947. Дерево по уровням 243. 251. КЛП->ЛКП 1948. Коммерческий калькулятор 252. ЛКП->КЛП
Учебные курсы / Программирование на языке высокого уровня / Продолжение следует /
1647. IntArrayList 243. 215. Множество 97. Прогрессия 1648. Фигуры
 
время генерации 0.093 сек.
© Copyright ВоГУ, АВТ, Носов Д.А., Андрианов И.А.