Перечень статей   Терминология   Choose language


Элементарный алгоритм - волновой


Примеры

Пример 1. Выбрать сотрудников, зарплата которых выше средней в их подразделении, в порядке убывания зарплаты.

create table department {
  id         num      primary key,
  name       string,
  sum        num      fictional,
  amount     num      fictional
};
create table employee {
  id         num      primary key,
  name       string,
  salary     num,
  department num      references department (id)
};
Запрос таков:
department.employee[^.sum^.sum+salary ^.amount^.amount+1];
department[#sum #amount].employee[-1§salary>^.sum/^.amount] ;
Вывод базы данных приведен ниже (поле "department" таблицы "employee" не выводится, т.к. оно уже использовано при построении выходных данных).
<department id="1"  name="Technical">
  <employee id="54" name="Fraud"   salary="3200">
  <employee id="72" name="Kitter"  salary="3100">
  <employee id="31" name="Tomson"  salary="3000">
</department>
<department id="2"  name="Marketting">
  <employee id="25" name="Johnson" salary="4100">
  <employee id="64" name="Smith"   salary="4000">
</department>

Пример 2. Пусть существует ряд городов, которые сообщаются рейсами некоторого транспорта без промежуточных остановок. Требуется узнать:

Все названия городов хранятся в таблице "city". Следующим звеном ("flight") в дереве является список городов, в которые можно вылететь из данного (условиями такой возможности являются наличие рейса и достаточное время для пересадки), поля "c1" - город отправления, "c2" - город прибытия, "t1" - время отправления, "t2" - время прибытия, "day" - дни недели, по которым осуществляется перелет. Адрес города "a" находится в поле "tab.from", адрес города "b" - в поле "tab.to", адреса городов "b", "c", "d" - в таблице "through".
create table city (
  id     num primary key,
  name   string
);
create table flight (
  c1     num references city (id),
  c2     num references city (id),
  t1     time,
  t2     time,
  day    weekdays
);
create table through (
  ref    num references city (id)
);
create table tab (
  from   num,
  to     num
);
Ответ на первый вопрос:
tab.from -> #city.flight/c1:c2[#c1 #c2].#city[id=tab.to] ;
<flight t1="5.30"  t2="8.30"  day="sunday">
<flight t1="7.30"  t2="10.30" day="monday">
<flight t1="9.30"  t2="12.30" day="tuesday">
<flight t1="15.30" t2="18.30" day="wednesday">
<flight t1="17.30" t2="20.30" day="thursday">
<flight t1="19.30" t2="22.30" day="friday">
<flight t1="7.30"  t2="10.30" day="saturday">
Ответ на второй вопрос:
tab.from -> #city.(flight/c1:c2[#day="monday" t1-^^.t2>30min].city)*||id=tab.to ;
<flight   t1="5.30"  t2="5.50">
 <city    id="15"    name="C">
  <flight t1="7.00"  t2="11.00">
   <city  id="18"    name="B">
  </flight>
 </city>
</flight>
<flight   t1="5.10"  t2="12.10">
 ...
  <city   id="18"    name="B">
 ...
</flight>
А ответ на третий вопрос выглядит так.
tab.from -> city.flight/c1:c2[day="monday"].city[id<~through.ref].(
 flight/c1:c2.city[id<~through.ref]
)*||day="friday" id=tab.from ;
<city          id="18"    name="A">
 <flight       t1="5.30"  t2="13.00"  day="monday">
  <city        id="23"    name="D">
   ...
  </city>
 </flight>

 <flight       t1="5.30"  t2="5.50"  day="monday">
  <city        id="18"    name="B">
   <flight     t1="7.00"  t2="11.00" day="tuesday">
    <city      id="14"    name="C">
     <flight   t1="12.00" t2="13.00" day="wednesday">
      <city    id="23"    name="D">
       <flight t1="14.00" t2="17.00" day="thursday">
        <city  id="15"    name="A">
       </flight>
      </city>
     </flight>
    </city>
   </flight>
  </city>
 </flight>

</city>

Пример 3.1 Пусть мы ищем в графе путь, проходящий через минимальное количество вершин. Каждая вершина есть запись в таблице "point". Связи между вершинами хранятся в таблице "bond". Путь ищется из вершины, первичный ключ которой задан в поле "tab.from" (начальная вершина), к вершине, первичный ключ которой задан в поле "tab.to" (конечная вершина), таблица "tab" имеет единственную запись.

create table point (
  id     num primary key,
  prev   num references point (id) fictional
);
create table bond (
  p1     num references point (id),
  p2     num references point (id)
);
create table tab (
  from   num references point (id),
  to     num references point (id)
);

Переберем все вершины от начальной к конечной - распространяется волна перебора. Каждая вершина в поле "prev" содержит первичный ключ вершины, из которой пришла волна.

Начальное значение установим равным "null" для всех вершин.

point[prevnull];
-- update point set prev=null;
Каждую из веpшин, до которой дошел фронт волны, назовем вершиной фронта. Все вершины, имеющие связи с вершиной фронта, будем называть следующий вершиной. Если у следующей вершины поле "prev" равно "null", то в ней полю "prev" присваивается адрес вершины фронта. Поиск ведется до тех пор, пока волна не дойдет до конечной вершины или пока не будут исчерпаны все вершины.
tab.from -> point.(bond/p1:p2.point[prev=null prev^^])*||id=tab.to;
Если поле "prev" последней вершины не равно "null", то путь в графе существует, и один из путей закодирован в значениях полей "prev". Выведем этот путь.
tab.to -> point[prev≠null] ?{
  tab.from -> point[#prev].(#bond/p1:p2.point[#prev=^^])*||id=tab.to 
} {{
  '<p>Pass does not exist</p>' 
}};
<point    id="3">
 <point   id="4"
  ...
   <point   id="11"
  ...
 </point>
</point>

Пример 3.2 Если вместо поля "prev" использовать множество "set" (вначале не содержащее ни одной записи), то в него можно записать точки фронта, первыми одновременно достигшие данного узла (для обнаружения одновременности введено поле дискретного времени "moment", равное удвоенному количеству пройденных вершин). Это позволяет найти несколько путей в графе (если они существуют).

create table point (
  id     num primary key,
  moment num fictional
);
create table bond (
  p1     num references point (id),
  p2     num references point (id)
);
create table set {
  ref    num references point (id),
  prev   num references point (id)
};
create table tab (
  from   num references point (id),
  to     num references point (id)
);
то заполнение множества будет таким
point[momentnull];
~~set;
-- update point set moment=null;
-- delete from set;
tab.from -> point.(bond/p1:p2.point[
  (moment=null moment!),moment=! set/ref<+>[prev^^^]
                                   ])*||id=tab.to;
А запрос для получения многих путей выглядит так
tab.to -> point.set ?{
  tab.from -> point.(bond/p1:p2.point[ set/ref{}.prev=^^^ ])*||id=tab.to 
} {{
  '<p>Pass does not exist</p>' 
}};

Пример 3.3 Если вместо множества "set" использовать список "list"

create table point (
  id     num primary key,
  moment num fictional,
  lnk    num references list  (id)
);
create table bond (
  p1     num references point (id),
  p2     num references point (id)
);
create table list {
  id     num primary key,
  prev   num references point (id),
  next   num references list  (id)
};
create table tab (
  from   num references point (id),
  to     num references point (id)
);
то заполнение списка будет таким
point[momentnull];
~~list;
tab.from -> point.(bond/p1:p2.point[
  moment=null list{  1}[prev^^^]  moment!,
  moment=!    list{$+1}[prev^^^]
                                   ])*||id=tab.to;
А запрос для получения многих путей выглядит так
tab.to -> point.list ?{
  tab.from -> point.(bond/p1:p2.point[ list{}[point=^^^] ])*||id=tab.to 
} {{
  '<p>Pass does not exist</p>' 
}};

Пример 4.1 Каждая вершина, ссылаясь на другую вершину, указывает вес связи до новой вершины (в поле "weight"). Требуется найти такой путь в графе, для которого минимальна сумма весов. Предполагается, что в графе не существует контур отрицательного суммарного веса (который бы позволял сделать вес пути сколь угодно малым, "прокрутившись" в контуре необходимое количество раз. Например, в симметричном графе weightab=weightba, таким контуром является любое ребро с отрицательным весом).

create table point (
  id     num primary key,
  prev   num references point (id) fictional,
  sum    float4 fictional
);
create table bond (
  p1     num references point (id),
  p2     num references point (id),
  weight float4
);
create table tab (
  from   num references point (id),
  to     num references point (id)
);
Ищем путь
point[prevnull sumnull];
tab.from -> point.(bond/p1:p2.point[
  sum=null, sum>^^.sum+^.weight
  prev^^  sum^^.sum+^.weight    ])*||id=tab.to;
Извлекается путь выражением из
примера 3.1.

Пример 4.2 Если вместо поля "prev" использовать множество "set"

create table point (
  id     num primary key,
  moment num fictional,
  sum    float4 fictional
);
create table bond (
  p1     num references point (id),
  p2     num references point (id),
  weight float4
);
create table set {
  ref    num references point (id),
  prev   num references point (id)
};
create table tab (
  from   num references point (id),
  to     num references point (id)
);
то заполнение множества будет таким
point[momentnull];
~~set;
tab.from -> point.(bond/p1:p2.point[
  (moment=null 
   set/ref<+>[prev^^^] moment! ),
  (sum>^^^.sum+^^.weight, sum=^^^.sum+^^.weight moment>!
   ~~set
   set/ref<+>[prev^^^]  sum^^^.sum+^^.weight moment! ),
  (sum=^^^.sum+^^.weight moment=!
   set/ref<+>[prev^^^] )
])*||id=tab.to;
Извлекается путь выражением из примера 3.2.

Пример 4.3 Если вместо множества "set" использовать список "list"

create table point (
  id     num primary key,
  moment num fictional,
  lnk    num references list  (id),
  sum    float4 fictional
);
create table bond (
  p1     num references point (id),
  p2     num references point (id),
  weight float4
);
create table list {
  id     num primary key,
  prev   num references point (id),
  next   num references list  (id)
};
create table tab (
  from   num references point (id),
  to     num references point (id)
);
Ищем путь
point[momentnull];
~~list;
tab.from -> point.(bond/p1:p2.point[
  (sum=null, sum>^^^.sum+^^.weight, sum=^^^.sum+^^.weight moment>!
   ~~list    list{1}[prev^^^]     sum^^^.sum+^^.weight moment!),
  (sum=^^^.sum+^^.weight moment=!   list{$+1}[prev^^^])
])*||id=tab.to;
Извлекается путь выражением из примера 3.3.


Тюрин Дмитрий



Перечень статей   Терминология   Choose language


Сайт управляется системой uCoz