.: [предыдущая | оглавление | следующая] :.

13.4 Программная реализация

В основе программной реализации лежит контейнер древовидного списка (см. раздел «Организация древовидного списка»). Перечислим константы:

Тип узла И
#define AND_NODE 1
Тип узла ИЛИ
#define OR_NODE 2
Описание структуры узда дерева И-ИЛИ
typedef struct //описание узла
{
      int type; //тип узла
      int var; //количество вариантов
      void* data; //данные
} KruAOTreeNode;
Описание структуру дерева И-ИЛИ
typedef struct // заголовок дерева
{
      NodeTreeList *root; //
корень
      int size; //кол-во узлов
      int var; //кол-во вариантов
} KruAOTree;
Функция инициализация структуры дерева И-ИЛИ
void InitKruAOTree(KruAOTree *aot)
{
      aot->root=NULL;
     
aot->size=0;
      aot->var=0;
}
Функция создание узла дерева
KruAOTreeNode* CreateKruAOTreeNode(int type,void* data)
{
      KruAOTreeNode *n=new KruAOTreeNode;
      if(n==NULL) return NULL;
      n->var=0;
      n->data=data;
      n->type=type;
      return n;
}
     Функция вывода узла дерева И-ИЛИ в случае, когда по указателю data хранится строка символов
void OutputKruAOTreeNode(void *n)
{
      printf("%d %d %s\n",((KruAOTreeNode*)n)->type, ((KruAOTreeNode*)n)->var,(char*)((KruAOTreeNode*)n)->data);
      //printf("%s\n",(char*)((KruAOTreeNode*)n)->data);
}
     Функция удаления узла дерева И-ИЛИ в случае, когда по указателю data хранится строка символов
void DeleteKruAOTreeNode(void *n)
{
      delete []((KruAOTreeNode*)n)->data;
      delete (KruAOTreeNode*)n;
}
     Функция создания узла дерева И-ИЛИ по описанию в name. Структура name должна быть следующей:
<Символ типа узла><строка>
<Символ типа узла> может быть
1) A - для И-узла;
2) O - для ИЛИ-узла.
     Эта функция используется при трансляции скобочной записи дерева в древовидный список
void* CreateKruAOTreeNode(char *name)
{
      KruAOTreeNode *n=new KruAOTreeNode;
      if(n==NULL) return NULL;
      if(*name==’A’) n->type=AND_NODE;
      else n->type=OR_NODE;
      n->var=0;
      char *s=new char[strlen(&name[1])+1];
      strcpy(s,&name[1]);
      n->data=s;
      return n;
}
Функция рекурсивного подсчета вариантов в дереве И-ИЛИ
int CountVarAOTree(NodeTreeList *node)
{
      KruAOTreeNode *d;
      int res;
      if(node==NULL) return 0;
      d=(KruAOTreeNode*)node->data;
      if(node->down!=NULL)
      {
            NodeTreeList *t=node->down;
            if(d->type==AND_NODE) res=1; else res=0; //установить начальные значения для res
            while(t!=NULL)//для всех сыновей
            {
                  if(d->type==AND_NODE)
                        res=res*CountVarAOTree(t);//рекурсивный подсчет для узла И
                  else res=res+CountVarAOTree(t); //рекурсивный подсчет для узла ИЛИ
                  t=t->right;
            }
      }
      else res=1;//это лист
      d->var=res; //установить значение var для данного узла
      return res;
}
     Функция обхода узлов варианта с заданным номером, node - корень дерева, number номер варианта, func - указатель на функцию обработки узла. Функция работает по алгоритму перечисления вариантов дерева И-ИЛИ
void ForEachVarAOTree(NodeTreeList *node, int number, void (*func)(void*))
{
      KruAOTreeNode *d;
      int res;
      if(node==NULL) return;
      d=(KruAOTreeNode*)node->data;
      if(func!=NULL) func(d); //вызов функции
      if(node->down!=NULL)
      {
            NodeTreeList *t=node->down;
            if(d->type==AND_NODE) res=1; else res=0;
            while(t!=NULL)
            {
                  KruAOTreeNode *td=(KruAOTreeNode*)t->data;
                  if(d->type==AND_NODE)//для всех И-узлов
                  {
                        ForEachVarAOTree(t,number%td->var,func);
                        number/=td->var;
                  }
                  else //для одного ИЛИ-узла
                  {
                        if(number<td->var)
                        {
                             ForEachVarAOTree(t,number,func); break;
                        }
                        number-=td->var;
                  }
                  t=t->right;
            }
      }
}
     Функция обхода узлов и обработки листьев варианта с заданным номером, node - корень дерева, number-номер варианта, func - указатель на функцию обработки листа. Функция работает по алгоритму перечисления вариантов дерева И-ИЛИ.
void ForEachVarAOTreeLeaf(NodeTreeList *node, int number, void (*func)(void*))
{
      KruAOTreeNode *d;
      int res;
      if(node==NULL) return;
      d=(KruAOTreeNode*)node->data;
      if(node->down==NULL)//это лист
      {
            if(func!=NULL) func(d);//вызов функции
      }
      else
      {
            NodeTreeList *t=node->down;
            if(d->type==AND_NODE) res=1; else res=0;
            while(t!=NULL)
            {
                  KruAOTreeNode *td=(KruAOTreeNode*)t->data;
                  if(d->type==AND_NODE)//для всех И-узлов
                  {
                        ForEachVarAOTree(t,number%td->var,func);
                        number/=td->var;
                  }
                  else //для одного ИЛИ-узла
                  {
                        if(number<td->var)
                        {
                             ForEachVarAOTreeLeaf(t,number,func); break;
                        }
                        number-=td->var;
                  }
                  t=t->right;
            }
      }
}
     Тестовая функция для показа организации и работы с деревьями И-ИЛИ
void TestKruAOTree()
{
      // конструирование дерева
      TranslateStateTreeList tsv; //создаем структуру
      InitTranslateStateTreeList(&tsv,20,CreateKruAOTreeNode);
      //инициализируем
      //трансляция описание дерева И-ИЛИ
      // в древовидный список
      NodeTreeList *ao_tree=TranslateAscizToTreeList(&tsv,
      "A1._node-1
      (O1.1_node-2(
      A1.1.1_node-4,
      O1.1.2._node_5(
      A1.1.2.1_node-9,
      O1.1.2.2._node_10),
      A1.1.3_node-6),
      O1.2_node-3(
      A1.2.1_node-7,
      A1.2.2_node-8)");
      //подсчет количества вариантов
      int nvar=CountVarAOTree(ao_tree);
      printf("++++ var =%d\n",nvar);
      //левосторонний обход дерева И-ИЛИ печать узлов
      ForEachTreeListLeftNode(ao_tree,OutputKruAOTreeNode);
      printf("+++++++++++++++++\n");
      //левосторонний обход дерева И-ИЛИ печать листьев
      ForEachTreeListLeftLeaf(ao_tree,OutputKruAOTreeNode);
      //перечисление вариантов в дереве и печать
      for(int num=0; num<nvar; num++)
      {
            ForEachVarAOTree(ao_tree,num,OutputKruAOTreeNode);
            printf("________%d\n",num);
      }
      //очищение динамической памяти
      DeleteTranslateStateTreeList(&tsv);
      DeleteSubTreeList(ao_tree,DeleteKruAOTreeNode);
      while(!kbhit());
}
Листинг работы тестовой программы
++++ var =8
1 8 1._node-1
2 4 1.1_node-2
1 1 1.1.1_node-4
2 2 1.1.2._node_5
1 1 1.1.2.1_node-9
2 1 1.1.2.2._node_10
1 1 1.1.3_node-6
2 2 1.2_node-3
1 1 1.2.1_node-7
1 1 1.2.2_node-8
+++++++++++++++++
1 1 1.1.1_node-4
1 1 1.1.2.1_node-9
2 1 1.1.2.2._node_10
1 1 1.1.3_node-6
1 1 1.2.1_node-7
1 1 1.2.2_node-8
1 8 1._node-1
2 4 1.1_node-2
1 1 1.1.1_node-4
2 2 1.2_node-3
1 1 1.2.1_node-7
169
________0
1 8 1._node-1
2 4 1.1_node-2
2 2 1.1.2._node_5
1 1 1.1.2.1_node-9
2 2 1.2_node-3
1 1 1.2.1_node-7
________1
1 8 1._node-1
2 4 1.1_node-2
2 2 1.1.2._node_5
2 1 1.1.2.2._node_10
2 2 1.2_node-3
1 1 1.2.1_node-7
________2
1 8 1._node-1
2 4 1.1_node-2
1 1 1.1.3_node-6
2 2 1.2_node-3
1 1 1.2.1_node-7
________3
1 8 1._node-1
2 4 1.1_node-2
1 1 1.1.1_node-4
2 2 1.2_node-3
1 1 1.2.2_node-8
________4
1 8 1._node-1
2 4 1.1_node-2
2 2 1.1.2._node_5
1 1 1.1.2.1_node-9
2 2 1.2_node-3
1 1 1.2.2_node-8
________5
1 8 1._node-1
2 4 1.1_node-2
2 2 1.1.2._node_5
2 1 1.1.2.2._node_10
2 2 1.2_node-3
1 1 1.2.2_node-8
________6
1 8 1._node-1
2 4 1.1_node-2
1 1 1.1.3_node-6
2 2 1.2_node-3
1 1 1.2.2_node-8
_______7
.: [предыдущая | оглавление | следующая] :.