Nickolay.info. Алгоритмы. Произвольное и бинарное деревья

Первый листинг реализует дерево, каждый узел которого может иметь произвольное число потомков. Соответственно, при описании структуры с типом tree достаточно указать конструкцию tree **childs;, которая будет служить указателем на текущий список узлов-потомков. Для простоты в нашем дереве всего одно информационное поле int info;, но в этом плане программу нетрудно расширить. Реализованы добавление, поиск, печать узлов.

#include <stdio.h>
#include <stdlib.h>
#include <alloc.h>
typedef struct tree {
 int info;
 tree **childs;
 unsigned count;
};
int const size1=sizeof(tree);

void error (int c) {
 printf ("\nError: ");
 switch (c) {
  case 1:  printf(" no memory"); break;
  default: printf(" unknown");   break;
 }
 exit (c);
}
tree *init (tree *p,int info) {
 p->info=info;
 p->count=0;
 p->childs=NULL;
 return p;
}
void print1 (tree *p) {
 printf ("\nnode %6d: %2d child(s)",
  p->info,p->count);
}
void printnode (tree *p) {
 print1 (p);
 for (int i=0; i<p->count; i++) 
  print1 (p->childs[i]);
}
tree *searchnode (tree *t, int info) {
 if (t->info == info) return t;
 else if (t->count>0) {
  for (int i=0; i<t->count; i++) {
   tree *p=searchnode (t->childs[i],info);
   if (p!=NULL) return p;
  }
  return NULL;
 }
 else return NULL;
}
tree *addnode (tree *ptr, int parentinfo, 
 int info) {
 tree *p=searchnode (ptr,parentinfo);
 if (p!=NULL) {
  if (p->childs==NULL) {
   p->childs = (tree **)malloc
    (sizeof(tree *));
   if (p->childs==NULL) error (1);
   p->childs[0]=(tree *)malloc(size1);
   if (p->childs[0]==NULL) error (1);
   (p->count)=1;
  }
  else {
   p->childs = (tree **)
   realloc(p->childs,sizeof(tree *)
    *(p->count+1));
   if (p->childs==NULL) error (1);
   p->childs[p->count]=(tree *)
    malloc(size1);
   if (p->childs[p->count]==NULL) 
    error (1);
   (p->count)++;
  }
  return init (p->childs[p->count-1],info);
 }
 return NULL;
}

void main () {
 tree head,temp,*ptr;
 ptr=&head;
 init(ptr,1);
 addnode (ptr,1,2);
 addnode (ptr,1,3);
 addnode (ptr,2,4);
 tree *s=searchnode (ptr,2);
 printf ("\n With node after search:");
 if (s!=NULL) printnode (s);
 else printf ("\nNULL");
 printf ("\n With root:");
 printnode (ptr);
 getchar ();
}

Во втором примере дерево - бинарное, то есть, у каждого узла лишь два потомка - левая и правая подветви, описанные указателями btree *left,*right;. Это дает возможности удобного рекурсивного поиска и обхода.

#include <stdio.h>
#include <iostream.h>
#include <string.h>
#include <alloc.h>

typedef struct btree {
 int val;
 btree *left,*right;
};

//----- Рекурсивный поиск в двоичном дереве---------------
// Возвращается указатель на найденную вершину
btree *Search(btree *p, int v) {
 if (p==NULL) return(NULL);                    // Ветка пустая
 if (p->val == v) return(p);                   // Вершина найдена
 if (p->val > v)                               // Сравнение с текущим
  return(Search(p->left,v));                   // Левое поддерево
 else
  return(Search(p->right,v));                  // Правое поддерево
}

//----- Включение значения в двоичное дерево--------------
// функция возвращает указатель на созданную вершину,
// либо на существующее поддерево
btree *Insert(btree *pp, btree *v) {
 if (pp == NULL) {           // Найдена свободная ветка
                             // Создать вершину дерева
  btree *q = new btree;      // и вернуть указатель
  q->val = v->val;
  q->left = q->right = NULL;
  return q;
 }
 if (pp->val == v->val) return pp;
 if (pp->val > v->val)                           // Перейти в левое или
  pp->left=Insert(pp->left,v);                   // правое поддерево
 else
  pp->right=Insert(pp->right,v);
 return pp;
}

// Рекурсивный обход двоичного дерева с выводом
// значений вершин в порядке возрастания
void Scan(btree *p) {
 if (p==NULL) return;
 Scan(p->left);
 cout << p->val << endl;
 Scan(p->right);
}


// Рекурсивный обход двоичного дерева с нумерацией вершин
// снизу-вверх слева-направо, n - текущий номер вершины
int Scan2 (btree * p, int n) {
 if (p==NULL) return n;
 Scan2 (p->left,n);
 n++;
 cout << n << ") " << p->val << endl;
 n=Scan2(p->right,n) ;
 return n;
}


// Рекурсивный обход двоичного дерева с последовательной
// нумерацией вершин в возвратом указателя на вершину с заданным номером
// Глобальный счетчик вершин передается через указатель
btree *ScanNum(btree *p, int *n) {
 btree *q;
 if (p==NULL) return NULL;
 q=ScanNum(p->left,n);
 if (q!=NULL) return q;
 if ((*n)-- ==0) return p;
 return ScanNum(p->right,n);
}

int main (void) {
 int v=1;
 btree *root=NULL;
 int depth=1;
 // ввод узлов 
 while (1) {
  printf ("\n введите узел дерева или 0 для выхода:");
  fflush (stdin);
  scanf ("%d",&v);
  if (!v) break;
  btree node;
  node.val=v;
  root=Insert (root,&node);
 }
 // поиск значения
 printf ("\n введите узел для поиска:");
 fflush (stdin);
 scanf ("%d",&v);
 btree *found=Search (root,v);
 if (found) printf ("\n found %d\n",found->val);
 else printf ("\n not found %d\n",v);
 // нумерация вершин
 printf ("\nScan:\n");
 Scan (root);
 printf ("\n введите начальный номер вершины:");
 fflush (stdin);
 scanf ("%d",&v);
 // поиск по номеру вершины
 printf ("\nScan2:\n");
 Scan2 (root,v);
 printf ("\nScan&Num:\n");
 found=ScanNum (root,&v);
 if (found) printf ("\n found %d\n",found->val);
 else printf ("\n not found %d\n",v);
 fflush (stdin);
 getchar ();
}

 В этом архиве (лаб. 7, весь архив около 2.5 Мб) - реализации всех основных динамических структур данных на Си: односвязный и двусвязный списки, стек, очередь

Рейтинг@Mail.ru

вверх гостевая; E-mail