SQL.RU
 client/server technologies
 
 Главная | Документация | Статьи | Книги | Форум | Опросы | Рассылка | Работа | Поиск | FAQ |

Добро пожаловать в форум, Guest  >>  Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик  Ответить
 Пятничная задачка: дерево арифметического выражения   [new]
Volder
Member

Откуда: Москва
Сообщений: 471
недавно товарищ подкинул мне задачку:
с помощью SQL построить иерархическое дерево арифметического выражения.
Что это такое я не знал. Поискав в интернете, нашел характерные черты, определяющие такое дерево:
1. деpево, в котоpом узлам соответствуют опеpации (операторы), а листьям - опеpанды (числа).
2. Постpоение начинается с коpня, в качестве котоpого выбиpается опеpация, выполняющаяся последней).
3. Также выполняется условие, что у узла два потомка (что понятно).

Таким образом, на входе подается арифметическое выражение в виде строки.
результат представить в виде: ID, Parent_ID, Value.
где ID - уникально идентифицирующий номер оператора или операнда в выражении.
PARENT_ID - родительский ему ID.
VAL - сам оператор или операнд.

Упрощение:
в качестве операторов могут быть только +,-,*,/
также может быть любое количество скобок с любым уровнем вложенности.

Чтобы лучше понять - пару примеров:
выражение '(1+2)*(3+4)-5'
результат:
        ID  PARENT_ID VAL                   LEVEL
---------- ---------- ---------------- ----------
         9             -                        1
         7          9    *                      2
         3          7      +                    3
         1          3        1                  4
         2          3        2                  4
         6          7      +                    3
         4          6        3                  4
         5          6        4                  4
         8          9    5                      2
         
визуально:

               -
              / \
             *   5
           /  \
          +    +
         / \  / \
        1   2 3  4
        
        
пример посложнее:
выражение: '6*(7*5+2*2/(5*3)+6)+4'
результат:
        ID  PARENT_ID VAL                        LEVEL
---------- ---------- --------------------- ----------
        17             +                             1
        15         17    *                           2
        14         15      +                         3
        12         14        +                       4
         4         12          *                     5
         3          4            5                   6
         2          4            7                   6
        11         12          /                     5
         7         11            *                   6
         5          7              2                 7
         6          7              2                 7
        10         11            *                   6
         9         10              3                 7
         8         10              5                 7
        13         14        6                       4
         1         15      6                         3
        16         17    4                           2

визуально:
                         +
                        / \
                       4   *
                          / \
                         6   +
                            / \
                           6   +
                              /  \
                             *   '/'
                            / \   / \
                           5  7  *    *
                                / \  / \
                               2  2 3   5     

Я решил в лоб не оч красиво.
мое решение только для 10-ки.
Товарищ уверен, что можно решить аналитикой.
Он близок, но пока окончательного запроса нет.

Вот такая вот головоломочка, надеюсь интересно будет.

PS значения ID могут быть отличные от значений в моем результате.
Главное, чтобы они уникально идентифицровали оператор\операнд в выражении и отражали взаимосвязи.
18 май 07, 10:40    [4153642] Ответить | Цитировать    Сообщить модератору

 Re: Пятничная задачка: дерево арифметического выражения   [new]
Elic
Member

Откуда: Минск
Сообщений: 20493
Volder
3. Также выполняется условие, что у узла два потомка (что понятно).
Выражение уже "нормализовано"?
Т.е. не бывает a+b+c или a*(b+c)*d, а будет (a+b)+c или (a*(b+c))*d ?
18 май 07, 10:55    [4153783] Ответить | Цитировать    Сообщить модератору

 Re: Пятничная задачка: дерево арифметического выражения   [new]
Бабичев Сергей
Member

Откуда: Красноярск
Сообщений: 2491
Покажи свой запрос для 10-ки.
Наверняка там MODEL в связке с регулярными выражениями используются.

Я так понимаю, сложность именно с переложением MODEL на аналитику?
18 май 07, 10:58    [4153804] Ответить | Цитировать    Сообщить модератору

 Re: Пятничная задачка: дерево арифметического выражения   [new]
Elic
Member

Откуда: Минск
Сообщений: 20493
Elic
Выражение уже "нормализовано"?
Отбой. Уже вижу, что нет.
IMHO, SQL-ная овчинка выделки не будет стоить.
18 май 07, 10:58    [4153809] Ответить | Цитировать    Сообщить модератору

 Re: Пятничная задачка: дерево арифметического выражения   [new]
Volder
Member

Откуда: Москва
Сообщений: 471
Elic
Elic
Выражение уже "нормализовано"?
Отбой. Уже вижу, что нет.
IMHO, SQL-ная овчинка выделки не будет стоить.

Ага, не нормализованное м.б.

Бабичев Сергей
Покажи свой запрос для 10-ки.
Наверняка там MODEL в связке с регулярными выражениями используются.

Я так понимаю, сложность именно с переложением MODEL на аналитику?

да там model и регулярные есть.
На аналитику не переложится напрямую.
Т.к. вначале находил обратную польскую запись (фактически процедуру в model засунул).
А потом ее (опять же model'ом) разобрал в дерево.

товарищ пробует сразу input строку перевести в дерево, расставив приоритеты оператором и анализируя открывающиеся и закрывающиеся скобки.
18 май 07, 11:06    [4153881] Ответить | Цитировать    Сообщить модератору

 Re: Пятничная задачка: дерево арифметического выражения   [new]
Volder
Member

Откуда: Москва
Сообщений: 471
Бабичев Сергей
Покажи свой запрос для 10-ки.

вот такая зверюшка у меня получилась:
SQL> with t as (select '6*(7*5+2*2/(5*3)+6)+4' s from dual),
  2  --finding back poland notation
  3  t1 as (
  4   select * from t
  5   model
  6    dimension by (0 d)
  7    measures (s, cast(null as varchar2(100)) stek, cast(null as varchar2(20)) symb, cast(null as varchar2(100)) temp, cast(null as varchar2(100)) str)
  8     rules iterate(1000) until (symb[0] is null)
  9     (symb[0]=regexp_substr(s[0], '[[:digit:]]+|[*+-/()]',1,iteration_number+1),
 10      temp[0] = case when symb[0] in ('+','-',')') then regexp_substr(stek[0],'[-+*/]*$')
 11                     when symb[0] in ('*','/')     then regexp_substr(stek[0],'[*/]*$')
 12                     else null
 13                end,
 14       str[0] = case when symb[0]=regexp_substr(symb[0],'[[:digit:]]*') then str[0]||symb[0]||''''
 15                     when symb[0] in ('+','-','*','/',')')              then str[0]||reverse(temp[0])
 16                     when symb[0] is null                               then str[0]||reverse(stek[0])
 17                     else str[0]
 18                end,
 19       stek[0] =  case when symb[0] in ('+','-')    then regexp_replace(stek[0],'[-+*/]*$')||symb[0]
 20                       when symb[0] in ('*','/')    then regexp_replace(stek[0],'[*/]*$')||symb[0]
 21                       when symb[0] = '('           then stek[0]||symb[0]
 22                       when symb[0] = ')'           then regexp_replace(stek[0],'\([-+*/]*$')
 23                       else stek[0]
 24                  end)
 25      ),
 26  t2 as (
 27  select str, level rn, rtrim(regexp_substr(str, '[[:digit:]]*''|[-+*/]', 1, level), '''') s
 28    from t1
 29  connect by regexp_substr(str, '[[:digit:]]*''|[-+*/]', 1, level) is not null
 30        ),
 31        --building tree
 32  t3 as ( select * from t2
 33              model
 34               dimension by (rn)
 35               measures(rn rn_const, rn r, rn r2,s, nvl(length(regexp_replace(s,'[[:digit:]]')),0) is_const, nvl(length(regexp_replace(s,'[[:digit:]]')),0) is_, (select length(regexp_replace(s,'[^-*+/]')) from t) cnt, cast(null as number) parent_rn, 0 parent_temp)
 36               rules iterate(100000) until (cnt[1]=0)
 37                (parent_temp[ANY] = parent_rn[CV()],
 38                 parent_rn[ANY] order by rn = case when parent_rn[CV()] is null and is_[CV()]=0 and is_[r[CV()]+1]=0 and is_[r[CV()]+2]=1 then rn_const[r[CV()]+2]
 39                                                   when parent_rn[CV()] is null and is_[CV()]=0 and is_[r2[CV()-1]] = 0 and is_[r[CV()]+1]=1 then rn_const[r[CV()]+1]
 40                                                   else parent_rn[CV()]
 41                                              end,
 42                 is_[ANY] order by rn = case when is_const[CV()]=1 and parent_rn[CV()-1] = rn_const[CV()] then 0 else is_[CV()] end,
 43                 r[ANY] order by rn desc = case when parent_rn[CV()+1] is not null then r[CV()+1] else r[CV()] end,
 44                 r2[ANY] order by rn = case when parent_rn[CV()] is not null then r2[CV()-1] else r2[CV()] end,
 45                 cnt[1] = cnt[1]-1
 46                )
 47         )
 48  select rn id, parent_rn parent_id, lpad(s, level * 2, ' ') val, level
 49    from t3
 50  connect by prior rn = parent_rn
 51   start with parent_rn is null
 52   order siblings by s
 53  /

        ID  PARENT_ID VAL                                                                                   LEVEL
---------- ---------- -------------------------------------------------------------------------------- ----------
        17             +                                                                                        1
        15         17    *                                                                                      2
        14         15      +                                                                                    3
        12         14        +                                                                                  4
         4         12          *                                                                                5
         3          4            5                                                                              6
         2          4            7                                                                              6
        11         12          /                                                                                5
         7         11            *                                                                              6
         5          7              2                                                                            7
         6          7              2                                                                            7
        10         11            *                                                                              6
         9         10              3                                                                            7
         8         10              5                                                                            7
        13         14        6                                                                                  4
         1         15      6                                                                                    3
        16         17    4                                                                                      2

17 rows selected

SQL> 
18 май 07, 14:19    [4155812] Ответить | Цитировать    Сообщить модератору

 Re: Пятничная задачка: дерево арифметического выражения   [new]
mcureenab
Member

Откуда: Murmansk
Сообщений: 5009
Можно утюгом гвозди забивать, а можно про jacc или bison почитать.

Обоснуй практическую пользу задачки, пзл.
18 май 07, 14:56    [4156145] Ответить | Цитировать    Сообщить модератору

 Re: Пятничная задачка: дерево арифметического выражения   [new]
Volder
Member

Откуда: Москва
Сообщений: 471
mcureenab
Можно утюгом гвозди забивать, а можно про jacc или bison почитать.

Обоснуй практическую пользу задачки, пзл.

калькулятор инженерный в sql написать
18 май 07, 15:20    [4156379] Ответить | Цитировать    Сообщить модератору

 Re: Пятничная задачка: дерево арифметического выражения   [new]
dmidek
Member

Откуда: Киев -> Дортмунд
Сообщений: 31258
mcureenab
Можно утюгом гвозди забивать, а можно про jacc или bison почитать.

Обоснуй практическую пользу задачки, пзл.


А зачем сразу практическая польза ?
Задачка пятничная, традиционная...

Меня лично решение Volder вдохновляет на изучение MODEL ...
18 май 07, 15:22    [4156404] Ответить | Цитировать    Сообщить модератору

 Re: Пятничная задачка: дерево арифметического выражения   [new]
mcureenab
Member

Откуда: Murmansk
Сообщений: 5009
Volder
калькулятор инженерный в sql написать


На инженерный не потянет. В синтаксисе даже унарного минуса нет, про функции я вообще молчу.
18 май 07, 15:27    [4156453] Ответить | Цитировать    Сообщить модератору

 Re: Пятничная задачка: дерево арифметического выражения   [new]
mcureenab
Member

Откуда: Murmansk
Сообщений: 5009
dmidek
mcureenab
Можно утюгом гвозди забивать, а можно про jacc или bison почитать.

Обоснуй практическую пользу задачки, пзл.


А зачем сразу практическая польза ?


Чтобы приличия соблюсти. Тем не менее вопрос открытый.

Надо же как то коллегам объяснить чем я занимаюсь!
18 май 07, 15:29    [4156490] Ответить | Цитировать    Сообщить модератору

 Re: Пятничная задачка: дерево арифметического выражения   [new]
Volder
Member

Откуда: Москва
Сообщений: 471
mcureenab

На инженерный не потянет. В синтаксисе даже унарного минуса нет, про функции я вообще молчу.

на слабовастенький понятнет
унарный минус думаю можно запросто добавить в регулярных выражениях при распарсе.
ну а если уж Вам функции подавай, то Пуск->Программы->Стандартные->Калькулятор (инженерный)
18 май 07, 15:42    [4156583] Ответить | Цитировать    Сообщить модератору

 Re: Пятничная задачка: дерево арифметического выражения   [new]
Fucker
Member

Откуда:
Сообщений: 1527
Один из подходов: Parsing in SQL
Правда Вадим вычисляет логическое выражение, но это не приниципиально...

Fucker
18 май 07, 16:07    [4156766] Ответить | Цитировать    Сообщить модератору

 Re: Пятничная задачка: дерево арифметического выражения   [new]
pan159
Member

Откуда: Москва
Сообщений: 241
Сделайте простую функцию для преобразования арифметического выражения в ПОЛИЗ (польская инверсионная запись) и все скобки исчезнут.
18 май 07, 16:21    [4156861] Ответить | Цитировать    Сообщить модератору

 Re: Пятничная задачка: дерево арифметического выражения   [new]
Volder
Member

Откуда: Москва
Сообщений: 471
pan159
Сделайте простую функцию для преобразования арифметического выражения в ПОЛИЗ (польская инверсионная запись) и все скобки исчезнут.

это и делает мой первый model из двух
18 май 07, 16:27    [4156912] Ответить | Цитировать    Сообщить модератору

Все форумы / Oracle Ответить
Generated time: 109ms.
Rambler's Top100 Powered by ActualForum 1.5.3 [s1] Copyright (c) Alex Sibilev 2000-2010