Шаг 90.
Второй пример использования топологической сортировки

    На этом шаге мы рассмотрим еще пример использования топологической сортировки .

    Ниже мы приведем реализацию некоторого алгоритма детерминированного выбора ведущего элемента с нулевым количеством предшественников при топологической сортировке. Установите самостоятельно в чем его идея!

#include <iostream.h>
typedef struct Leader  *Lref; //Тип: указатель на заголовочный узел.
typedef struct Trailer *Tref; //Тип: указатель на дуговой узел.
//Описание типа заголовочного узла.
typedef struct Leader 
{
  int Key;    //Информационное поле.
  int Count;  //Количество предшественников.
  int CountF; //Количество последователей.
  Tref Trail; 
  Lref Next;  
};

//Описание типа дугового узла.
typedef struct Trailer 
{
  Lref Id; 
  Tref Next; 
};

class Spisok {
  private:
    Lref Head; //Указатель на список заголовочных узлов.
    Lref Tail; //Указатель на фиктивный элемент 
               //в конце списка заголовочных узлов.
    int z;     //Количество узлов, не имеющих предшественников.
    int  Length_List(Tref);
    void Sorting (Lref);
  public:
    Spisok () {//Инициализация списка заголовочных узлов.
               Head = Tail = new (Leader); z = 0;};
    Lref L (int); 
    void Poisk();
    void Vyvod();
    void Zapoln();
};

void Spisok::Zapoln()
// Заполнение полей CountF узлов построенного графа.
{ 
  Lref p; // Рабочий указатель.

  p = Head;
  while ( p!=Tail)
  {
    p->CountF = Length_List (p->Trail);
    p = p->Next;
  }
}

void Spisok::Poisk()
{
  Lref p,q; // Рабочие указатели.
  
  p = Head; Head = NULL;
  while (p!=Tail)
  {
     q = p; p = p->Next;
     if (q->Count==0)
       { q->Next = Head; Head = q; }
   }
}

Lref Spisok::L (int w) 
//Функция возвращает указатель на ведущего с ключом w.
{
  Lref h = Head;

  Tail->Key = w;
  while (h->Key!=w) h = h->Next;
  if (h==Tail)
  // В списке нет элемента с ключом w.
  {
    Tail = new (Leader); z++;
    h->Count = 0; h->Trail = NULL; h->Next = Tail;
  }
  return h;
}

void Spisok::Vyvod()
{
  Lref p,q; // Рабочие указатели.
  Tref t;
  
  cout << "\nРезультат топологической сортировки:\n";
  q = Head;
  while ( q!=NULL) 
  {
     Sorting (q);
     cout << q->Key << " "; 
     z--;
     t = q->Trail; q = q->Next;
     while (t!=NULL)
     {
       p = t->Id; p->Count--;
       if  (p->Count==0) // Включение (*p) в список ведущих.
         { p->Next = q; q = p; }
       t = t->Next;
     }
  }
  if (z!=0)
      cout << "\nМножество не является частично упорядоченным!\n";
}

int Spisok::Length_List (Tref T)
// Функция позволяет найти количество элементов в линейном списке.
// T - указатель на звено, следующее за заглавным звеном.
{
  if (T==NULL) return 0;
  else  return 1 + Length_List(T->Next);
}

void Spisok::Sorting (Lref Head)
// Сортировка списка элементов по полю CountF
// в порядке убывания.
// 21.10.93 (c) Коврижных Д. & Швецкий М.В.
{
  Lref UkZv_1,UkZv_2;
  int A,B,C;
  Tref D;
  Lref UkZv_3; // Рабочий указатель.
  Tref UkZv_4; // Рабочий указатель.

  UkZv_1 = Head;
  while ( UkZv_1!=NULL )
  {
     UkZv_2 = UkZv_1->Next;
     while  (UkZv_2!=NULL)
     {
       if  (UkZv_1->CountF < UkZv_2->CountF)
         {
           A              = UkZv_1->Key;
           B              = UkZv_1->Count;
           C              = UkZv_1->CountF;
           D              = UkZv_1->Trail;

           UkZv_1->Key    = UkZv_2->Key;
           UkZv_1->Count  = UkZv_2->Count;
           UkZv_1->CountF = UkZv_2->CountF;
           UkZv_1->Trail  = UkZv_2->Trail;

           UkZv_2->Key    = A;
           UkZv_2->Count  = B;
           UkZv_2->CountF = C;
           UkZv_2->Trail  = D;

           UkZv_3 = Head;
           while  (UkZv_3!=NULL)
           {
              UkZv_4 = UkZv_3->Trail;
              while  (UkZv_4!=NULL)
              {
                 if  (UkZv_4->Id==UkZv_1)
                      UkZv_4->Id = UkZv_2;
                 else
                   if ( UkZv_4->Id==UkZv_2 ) UkZv_4->Id = UkZv_1;
                 UkZv_4 = UkZv_4->Next;
              }
              UkZv_3 = UkZv_3->Next;
           }
         }
       UkZv_2 = UkZv_2->Next;
     }
     UkZv_1 = UkZv_1->Next;
  }
}

void main()
{
  Spisok A;
  Lref p,q; // Рабочие указатели.
  Tref t;
  int  x,y; // Рабочие переменные.

  // Фаза ввода.
  cout << "Задайте отношение частичного порядка...\n";
  cout << "Элемент "; 
  cin >> x; 
  cout << " предшествует элементу ";
  while (x!=0)
  {
    cin >> y;
    p = A.L(x); q = A.L(y);
    t = new (Trailer); t->Id = q; t->Next = p->Trail;
    p->Trail = t; q->Count += 1;
    cout << "Элемент "; 
    cin >> x;
    cout << " предшествует элементу ";
  }
  // Заполнение полей CountF узлов построенного графа.
  A.Zapoln();
  // Поиск ведущих с нулевым количеством предшественников.
  A.Poisk();
  // Фаза вывода.
  A.Vyvod();
}
Текст этой программы можно взять здесь.

    На следующем шаге мы продолжим рассматривать примеры использования топологической сортировки.




Предыдущий шаг Содержание Следующий шаг