БлогNot. C++: произвольное дерево из чисел с ограниченным количеством потомков узла

C++: произвольное дерево из чисел с ограниченным количеством потомков узла

Ниже приведён листинг простого примера на работу с произвольным деревом чисел (см. поле info структуры). Так как узлы сравниваются между собой по значениям info, все они предполагаются разными. В реальном приложении можно оценивать это info как идентификатор записи, добавив в структуру любые произвольные данные.

По условию задачи, максимальное количество потомков ограничиваем константным значением COUNT. Заметим, что в реальных приложениях память всё равно лучше выделять некоторыми "порциями", как, собственно, и делают стандартные контейнеры STL. Каждый раз "перевыделять" оперативку функциями вроде realloc чревато "дырками" в памяти приложения, а всё время делать delete и new при добавлении нового элемента в контейнер слишком не экономично.

В принципе, подобный листинг есть и вот здесь, только с malloc и "опасной" realloc. Также здесь дерево выводится в консоль в "древовидной" форме и есть метод для удаления поддерева.

Код проверен в Visual Studio 2010 Express, где благополучно сработал.

/* Простой пример на произвольное дерево из чисел info, 
максимальное количество потомков ограничено */
#include <cstdio>
#include <cstdlib>

const int COUNT = 10; //макс. количество потомков
struct tree { //произвольное дерево
 int info; //информационное поле
 tree **childs; //указатель на массив потомков
 int count; //количество потомков - для удобства
};

void error (int n) { //Сообщения об ошибках и выход
 switch (n) {
 case 0: printf("\nNormal stutdown"); break;
 case 1: printf("\nNo memory!"); break;
 case 2: printf("\nToo many child items!"); break;
 default: printf("\nUnknown error!"); break;
 }
 fflush(stdin);  getchar(); exit(n);
}

tree *init (tree *p, int info) { //Инициализация узла
 p->info = info; p->childs = nullptr; p->count = 0; return p;
}

void print1 (tree *p) { //Вывод одного узла
 printf ("Item %d (%d childs)\n",p->info,p->count);
}

void print (tree *p, int tab=0) { //Вывод всего дерева (поддерева) с узла p
 print1 (p);
 for (int i = 0; i < p->count; i++) {
  for (int k=0; k<=tab; k++) printf ("\t");
  print (p->childs[i],++tab);
  --tab;
 }
}

tree *search (tree *t, int info) { //Поиск в дереве t узла со значением info
 if (t->info == info) return t;
 else if (t->count>0) {
  for (int i = 0; i < t->count; i++) {
   tree *p = search(t->childs[i], info); //рекурсия!
   if (p != nullptr) return p;
  }
  return nullptr;
 }
 else return nullptr;
}

tree *search_parent (tree *t, tree *p) { //Поиск в дереве t родителя для узла p
 if (t->count>0) {
  for (int i=0; i<t->count; i++) {
   if (t->childs[i]->info==p->info) return t;
   else {
    tree *s=search_parent (t->childs[i],p);
    if (s != nullptr) return s;
   }
  }
  return nullptr;
 }
 else return nullptr;
}

tree *add (tree *ptr, int parentinfo, int info) { 
 //Добавление потомка со значением info родителю с parentinfo
 tree *p = search (ptr, parentinfo); //ищем в дереве родителя
 if (p) {
  if (p->count == 0) {
   p->childs = new tree * [COUNT];
   if (p->childs == nullptr) error(1);
   p->childs[0] = new tree;
   if (p->childs[0] == nullptr) error(1);
   p->count = 1;
  }
  else if (p->count < COUNT-1) {
   p->childs[p->count] = new tree;
   if (p->childs[p->count] == nullptr) error(1);
   p->count++;
  }
  else error (2);
  return init(p->childs[p->count - 1], info);
 }
 return nullptr;
}

void remove (tree *t, tree *p) { //Удаление из дерева t узла p и его потомков
 tree *item = search(t, p->info);
 if (item) {
  tree *parent = search_parent (t, item);
  if (parent) { //Есть родитель - "сжать" массив его потомков
   for (int i=0; i<parent->count; i++) if (parent->childs[i]->info==item->info) {
    for (int k=i; k<parent->count-1; k++) parent->childs[k]=parent->childs[k+1];
    parent->count--;
   }
  }
  if (item->count>0) {
   for (int i = item->count-1; i>-1; i--) {
    remove (t,item->childs[i]);
   }
   item->count = 0;
  }
  delete item;
 }
}

int main(void) {
 tree head; //один узел есть сразу
 init(&head,1);
 tree *ptr = &head;
 
 add(ptr, 1, 2); //узел "2" - потомок "1"
 add(ptr, 1, 3);
 add(ptr, 1, 4);
 tree *ptr2=add(ptr, 2, 5); 
  //сохраним указатель на узел "5" для последующего удаления этого поддерева
 add(ptr, 2, 6);
 add(ptr, 5, 7);
 add(ptr, 7, 8);
 add(ptr, 6, 9);
 
 printf("\nSearch test: ");
 tree *s = search(ptr,5);
 if (s) print1(s); else printf("Not found");
 
 printf("\nAll items:\n");
 print(ptr);

 remove (ptr,ptr2);
 printf("\nAll items after deleting:\n");
 print(ptr);

 error(0);
}

Вот что вывело это приложение:

Search test: Item 5 (1 childs)

All items:
Item 1 (3 childs)
        Item 2 (2 childs)
                Item 5 (1 childs)
                        Item 7 (1 childs)
                                Item 8 (0 childs)
                Item 6 (1 childs)
                        Item 9 (0 childs)
        Item 3 (0 childs)
        Item 4 (0 childs)

All items after deleting:
Item 1 (3 childs)
        Item 2 (1 childs)
                Item 6 (1 childs)
                        Item 9 (0 childs)
        Item 3 (0 childs)
        Item 4 (0 childs)

Normal stutdown

08.02.2017, 11:50 [5656 просмотров]


теги: c++ программирование учебное studio

К этой статье пока нет комментариев, Ваш будет первым