Шаг 85.
Пример программы, реализующей простейшие операции над графом, представленным структурой Вирта

    На этом шаге мы приведем пример программы, реализующей простейших операций над графом, представленным структурой Вирта.

    Приведем программу, демонстрирующую работу всех приведенных на предыдущем шаге функций.


    Пример. Построение динамической структуры Вирта, соответствующей ориентированному графу, вывод на экран его структуры, добавление и удаление ребер, добавление и удаление вершин.
#include <iostream.h>
#define TRUE 1
#define FALSE 0
typedef int Boolean;
typedef struct L *Lref; //Тип: указатель на заголовочный узел.
typedef struct T *Tref; //Тип: указатель на дуговой узел.
//Описание типа заголовочного узла.
typedef struct L 
{
  int Key;    //Имя заголовочного узла.
  int Count;  //Количество предшественников.
  Tref Trail; //Указатель на список смежности.
  Lref Next;  //Указатель на следующий узел в 
              //списке заголовочных узлов.
} Leader;

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

class Spisok {
  private:
    Lref Head; //Указатель на список заголовочных узлов.
    Lref Tail; //Указатель на фиктивный элемент 
               //в конце списка заголовочных узлов.
    Lref SearchGraph(int);
    Lref Search(int);
  public:
    Spisok () {//Инициализация списка заголовочных узлов.
               Head = Tail = new (Leader); }
    ~Spisok(); //Деструктор.
    void MakeGraph();
    void AddGraph(int, int);
    void DeleteGraph(int, int);
    void PrintGraph();
    void DeleteY(int);
    void Free1Graph(Lref *, Lref *);
    void Free2Graph(Tref *); 
};

void main ()
{
  Spisok A;
  int x,y; //Начало и конец дуги.

  //Построение и вывод структуры Вирта.
  A.MakeGraph ();
  A.PrintGraph (); cout<<endl;
  cout<< "Добавим к графу новую дугу...\n";
  cout<< "Введите начало дуги: "; cin>>x;
  cout<< "Введите конец дуги: "; cin>>y;
  A.AddGraph (x,y);
  A.PrintGraph (); cout<<endl;
  cout<< "Добавим к графу новое ребро...\n";
  cout<< "Введите первую концевую вершину ребра: "; cin>>x;
  cout<< "Введите вторую концевую вершину ребра: "; cin>>y;
  A.AddGraph (x,y);
  A.AddGraph (y,x);
  A.PrintGraph (); cout<<endl;
  cout<< "Удалим из графа заданную дугу...\n";
  cout<< "Введите начало дуги: "; cin>>x;
  cout<< "Введите конец дуги: "; cin>>y;
  A.DeleteGraph (x,y);
  A.PrintGraph (); cout<<endl;
  cout<< "Удалим из графа заданное ребро...\n";
  cout<< "Введите первую концевую вершину ребра: "; cin>>x;
  cout<< "Введите вторую концевую вершину ребра: "; cin>>y;
  A.DeleteGraph (x,y);
  A.DeleteGraph (y,x);
  A.PrintGraph (); cout<<endl;
  cout<< "Введите удаляемую вершину: "; cin>>y;
  A.DeleteY (y);
  A.PrintGraph (); cout<<endl;
}

Spisok::~Spisok()
{
  //Очистка структуры Вирта.
  Lref t = Head;
  while (t!=Tail)
  { Free2Graph (&(*t).Trail); t = (*t).Next; }
  Free1Graph (&Head,&Tail);
  delete Tail;
}

Lref Spisok::SearchGraph (int w)
//Функция возвращает указатель на заголовочный узел 
//с ключом w. Если заголовочный узел отсутствует, то он 
//добавляется в список. Head - указатель на структуру Вирта.
{
  Lref h;

  h = Head; (*Tail).Key = w;
  while ((*h).Key!=w) h = (*h).Next;
  if (h==Tail)
  //В списке заголовочных узлов нет узла с ключом w.
  //Поместим его в конец списка Head.
  { Tail = new (Leader); (*h).Count = 0; 
    (*h).Trail = NULL; (*h).Next = Tail; }
  return h;
}

Lref Spisok::Search (int w)
//Функция возвращает указатель на заголовочный узел 
//ключом w. Если узел отсутствует, то функция возвращает NULL .
{
  Lref h = Head;
  (*Tail).Key = w; //Поиск "с барьером".
  while ((*h).Key!=w) h = (*h).Next;
  if (h==Tail) //В списке заголовочных узлов нет узла с ключом w.
    h = NULL;
  return h;
} 

void Spisok::MakeGraph ()
//Функция возвращает указатель Head на структуру 
//Вирта, соответствующую ориентированному графу.
{
  int x,y;
  Lref p,q;    //Рабочие указатели.
  Tref t,r;    // Рабочие указатели.
  Boolean Res; //Флаг наличия дуги.

  cout<<"Вводите начальную вершину дуги: ";
  cin>>x;
  while (x!=0)
  {
    cout<<"Вводите конечную вершину дуги: "; cin>>y;
    //Определим, существует ли в графе дуга (x,y)?
    p=SearchGraph (x); q=SearchGraph (y);
    r = (*p).Trail; Res = FALSE; 
    while ((r!=NULL)&&(!Res)) 
      if ((*r).Id==q) Res = TRUE; 
      else r = (*r).Next; 
    if (!Res) //Если дуга отсутствует, то поместим её в граф.
    { t = new (Trailer); (*t).Id = q; 
      (*t).Next = (*p).Trail; (*p).Trail = t; (*q).Count++; } 
    cout<<"Вводите начальную вершину дуги: "; cin>>x;
  }
}

void Spisok::AddGraph (int x,int y)
//Добавление дуги (x,y) (если ее не было!) к структуре
//Вирта, соответствующей ориентированному графу Head.
{
  Lref p,q;    //Рабочие указатели.
  Tref t,r;    //Рабочие указатели.
  Boolean Res; //Флаг наличия в графе данной дуги.

  //Определим, существует ли в графе дуга (x,y)? 
  p=SearchGraph (x); q=SearchGraph (y);
  r = (*p).Trail; Res = FALSE;
  while ((r!=NULL)&&(!Res)) 
    if ((*r).Id==q) Res = TRUE; else r = (*r).Next;
  if (!Res)
  { //Если дуга отсутствует, то поместим её в граф.
    t = new (Trailer); (*t).Id = q; (*t).Next = (*p).Trail; 
    (*p).Trail = t; (*q).Count++;
  }
} 

void Spisok::DeleteGraph (int x,int y)
//Функция возвращает указатель Head на структуру 
//Вирта, соответствующую ориентированному графу
//и полученную удалением дуги (x,y).
{
  Lref p,q;    //Рабочие указатели.
  Tref t,r;    //Рабочие указатели.
  Boolean Res; //Флаг наличия в графе данной дуги.

  //Определим, существует ли в графе дуга (x,y)?
  p=Search (x); q= Search (y);
  if ((p!=NULL)&&(q!=NULL))
  { //Вершины x и y в графе есть.
    r = (*p).Trail; Res = FALSE; 
    while ((r!=NULL)&&(!Res)) 
      if ((*r).Id==q) Res = TRUE; 
      else r = (*r).Next; 
   if (Res) //Если дуга существует, то удалим её.
   if (r==(*p).Trail)
     { (*p).Trail = (*(*p).Trail).Next; delete r; (*q).Count--; } 
   else 
    {
      t = (*p).Trail; 
      while ((*t).Next!=r) t = (*t).Next;
      (*t).Next = (*(*t).Next).Next; delete r; (*q).Count--; }
    }
} 

void Spisok::PrintGraph ()
//Вывод структуры Вирта, заданной указателем 
//Head и соответствующей ориентированному графу.
{
  Lref p; //Рабочий указатель.
  Tref q; //Рабочий указатель.

  p = Head;
  while (p!=Tail)
  {
    cout<<"("<<(*p).Key; q = (*p).Trail; 
    while (q!=NULL) 
    { cout<<(*(*q).Id).Key; q = (*q).Next; } 
    cout<<")"; p = (*p).Next; cout<<" ";
  }
}

void Spisok::DeleteY (int y)
//Функция возвращает указатель Head на структуру Вирта, 
//соответствующую графу с удаленной вершиной y.
{ 
  Lref p,q; //Рабочие указатели.
  Tref r,s; //Рабочие указатели.
  int x;    //Рабочая переменная.
  //Удаление всех дуг (x,y), оканчивающихся  в вершине y.
  p = Head; 
  while (p!=Tail) 
  { x = (*p).Key; DeleteGraph (x,y); p = (*p).Next; } 
  //Удаление списка смежности вершины y.
  p=SearchGraph (y); r = (*p).Trail;
  while (r!=NULL) 
  { s = r; r = (*r).Next; (*(*s).Id).Count++; delete s; } 
  //Удаление узла, содержащего вершину y, из  списка заголовочных узлов.
  q = Head; 
  if (q==p) { Head = (*Head).Next; delete q; } 
  else { 
    while ((*q).Next!=p) q = (*q).Next; 
    (*q).Next = (*p).Next; delete p; }
} 

void Spisok::Free1Graph (Lref *Head, Lref *Tail)
//Очистка динамической памяти, занятой линейным списком, 
// заданным указателем *Head.
{
  if (*Head!=*Tail)
  { Free1Graph (&(**Head).Next,Tail); delete *Head; *Head = NULL; }
} 

void Spisok::Free2Graph (Tref *X)
//Очистка динамической памяти, занятой линейным списком, 
// заданным указателем *X.
{
  if (*X!=NULL)
  { Free2Graph (&(**X).Next); delete *X; *X = NULL; }
}
Текст этой программы можно взять здесь.

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




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