Алгоритм сортувальної станції — метод синтаксичного розбору математичних виразів наданих в інфіксній нотації. Його можна використовувати для отримання інверсного польського запису (ПОЛІЗ) або абстрактного синтаксичного дерева. Алгоритм було винайдено Дейкстрою і названо алгоритм «сортувальної станції», бо ця операція нагадує дію залізничної сортувальної станції.
Як обчислювач ПОЛІЗ, алгоритм сортувальної станції — це стековий алгоритм. Інфіксні форму виразів використовує більшість людей, наприклад 3+4 або 3+4*(2−1). Для перетворення використовуються дві текстові змінні (рядки), вхідний і вихідний. Також задіюється стек, що містить оператори ще не додані в вихідну чергу. Для перетворення програма посимвольно читає початкові дані й виконує дії виходячи з прочитаного символу.
Просте перетворення
- Початкові дані: 3+4
- Додаємо 3 до черги на виході (щоразу як читається число, воно записується на вихід)
- Заштовхується + (або його ID) у стек операторів
- Додаємо 4 до черги на виході
- По прочитанню виразу виштовхуємо оператор зі стеку та додаємо його до вихідної черги.
- Наразі він лиш один, «+».
- Вихід 3 4 +
Тут ми вже побачили пару правил:
- Всі числа додаються до виходу одразу по прочитанню.
- Наприкінці всього виразу, виштовхуємо всі оператори зі стеку й додаємо їх до черги на виході.
Подробиці алгоритму
- Допоки на вході ще є позначки:
- Прочитати позначку.
- Якщо це число, додати до черги на виході.
- Якщо це позначка функції, тоді заштовхнути його у стек.
- Якщо позначка — це відокремлювач аргументів функції (наприклад, кома):
- Доки позначка на верхівці стеку це не ліва дужка, виштовхувати зі стеку оператори до черги на виході. Якщо ліва дужка так і не зустрілась, тоді або відокремлювач не на своєму місці, або пропущені дужки.
- Якщо позначка — це оператор, o1, тоді:
- доки на верхівці стеку оператор, o2, і
- або o1ліво-асоціативний і його першість менша ніж чи дорівнює першості o2,
- або o1 право-асоціативний і першість менша ніж у o2,
- виштовхнути o2 зі стеку до черги на виході;
- заштовхнути o1 на стек.
- Якщо позначка це ліва дужка, заштовхнути на стек.
- Якщо права дужка:
- Допоки не зустрінеться ліва дужка, виштовхувати оператори зі стека до черги на виході.
- Виштовхнути ліву дужку зі стеку, але не до черги на виході.
- Якщо позначка на верхівці стеку — це позначка функції, виштовхнути її до черги на виході.
- Якщо стек завершився, а ліва дужка не зустрілась, тоді вона була пропущена.
- Коли вже немає позначок на вході:
- Доки ще є оператори в стеці:
- Якщо оператор на верхівці стеку — це дужка, значить була пропущена дужка.
- Виштовхнути оператори до черги на виході.
- Вихід.
Для розбору складності цього алгоритму за часом виконання, можна спостерегти, що кожна позначка буде прочитана один раз, кожне число, функція чи оператор буде надрукована один раз і кожна функція, оператор або дужка буде заштовхнута на стек і виштовхнута звідти один раз — отже, не більше сталої кількості операцій буде виконано з кожною позначкою, звідси час виконання O(n) — лінійний щодо розміру вхідних даних.
Алгоритм сортувальної станції також можна застосовувати для отримання префіксного запису (також відомого як польська нотація). Для цього необхідно почати з даного рядка в зворотному напрямку, і тоді розвернути чергу на виході(внаслідок чого перетворивши чергу на виході на стек на виході).
Приклад реалізації на C++
//алгоритм сортувальної станції string shuntingYard(const string& input) { Stack<char> stack; string output(""); unsigned length = input.length(); for (unsigned i = 0; i < length; ++i) { //перевірка чи вхідний символ є частиною числа(врахування унарного '-') if (isNumber(input[i]) || (input[i] == '-' && i == 0) || (i > 0 && input[i-1] == '(' && input[i] == '-')) { //перевірка це останній символ числа,щоб поставити після нього пробіл if(i + 1 == length || isOperator(input[i+1]) || input[i+1] == '(' || input[i+1] == ')') { output = output + input[i] + ' '; } else { output = output + input[i]; } } else if (input[i] == '(') { stack.push('('); } else if (input[i] == ')') { while (stack.top() != '(') { output = output + stack.pop()+ ' '; } stack.pop(); } else if (isOperator(input[i])) { while (!stack.isEmpty() && (opPreced(stack.top()) >= opPreced(input[i]))) { output = output + stack.pop() + ' '; } stack.push(input[i]); } else { //помилка вхідних даних throw "Помилка вхідних даних"; } } //виводимо символи що залишились у стеку unsigned stackSize = stack.size(); if (stackSize > 0) { for (unsigned i = 0; i < stackSize - 1; ++i) { output = output + stack.pop() + ' '; } output = output + stack.pop(); } return output; } // Функція для визначення пріоритету операцій unsigned opPreced(const char ch) { switch(ch) { case '^': return 3; case '*': case '/': return 2; case '+': case '-': return 1; } // для випадку вхідного символу '(' return 0; } bool isNumber(char ch) { return (('0' <= ch) && (ch <= '9')) || (ch == '.'); } bool isOperator(char ch) { return (ch == '+' || ch == '-' || ch == '/' || ch == '*' || ch == '^'); }
Посилання
- Оригінальний опис алгоритму Дейкстрою
Вікіпедія, Українська, Україна, книга, книги, бібліотека, стаття, читати, завантажити, безкоштовно, безкоштовно завантажити, mp3, відео, mp4, 3gp, jpg, jpeg, gif, png, малюнок, музика, пісня, фільм, книга, гра, ігри, мобільний, телефон, android, ios, apple, мобільний телефон, samsung, iphone, xiomi, xiaomi, redmi, honor, oppo, nokia, sonya, mi, ПК, web, Інтернет
Algoritm sortuvalnoyi stanciyi metod sintaksichnogo rozboru matematichnih viraziv nadanih v infiksnij notaciyi Jogo mozhna vikoristovuvati dlya otrimannya inversnogo polskogo zapisu POLIZ abo abstraktnogo sintaksichnogo dereva Algoritm bulo vinajdeno Dejkstroyu i nazvano algoritm sortuvalnoyi stanciyi bo cya operaciya nagaduye diyu zaliznichnoyi sortuvalnoyi stanciyi Yak obchislyuvach POLIZ algoritm sortuvalnoyi stanciyi ce stekovij algoritm Infiksni formu viraziv vikoristovuye bilshist lyudej napriklad 3 4 abo 3 4 2 1 Dlya peretvorennya vikoristovuyutsya dvi tekstovi zminni ryadki vhidnij i vihidnij Takozh zadiyuyetsya stek sho mistit operatori she ne dodani v vihidnu chergu Dlya peretvorennya programa posimvolno chitaye pochatkovi dani j vikonuye diyi vihodyachi z prochitanogo simvolu Proste peretvorennyaZobrazhennya algoritmu sho vikoristovuye trigilkove zaliznichnij vuzol Pochatkovi dani opracovuyutsya po odnomu simvolu za raz yaksho otrimana zminna abo nomer vona kopiyuyetsya pryamo na vihid b d f h Yaksho zh ce operator vin zashtovhuyetsya v stek operatoriv c e odnak yaksho starshinstvo menshe nizh u operatora na verhivci steka abo voni mayut odnakove starshinstvo j operator livoasociativnij todi toj operator vishtovhuyetsya zi steka j zapisuyetsya na vihid g Nasamkinec operator sho zalishilis u steci vishtovhuyutsya i dodayutsya do vihodu Pochatkovi dani 3 4Dodayemo 3 do chergi na vihodi shorazu yak chitayetsya chislo vono zapisuyetsya na vihid Zashtovhuyetsya abo jogo ID u stek operatoriv Dodayemo 4 do chergi na vihodi Po prochitannyu virazu vishtovhuyemo operator zi steku ta dodayemo jogo do vihidnoyi chergi Narazi vin lish odin Vihid 3 4 Tut mi vzhe pobachili paru pravil Vsi chisla dodayutsya do vihodu odrazu po prochitannyu Naprikinci vsogo virazu vishtovhuyemo vsi operatori zi steku j dodayemo yih do chergi na vihodi Podrobici algoritmuDopoki na vhodi she ye poznachki Prochitati poznachku Yaksho ce chislo dodati do chergi na vihodi Yaksho ce poznachka funkciyi todi zashtovhnuti jogo u stek Yaksho poznachka ce vidokremlyuvach argumentiv funkciyi napriklad koma Doki poznachka na verhivci steku ce ne liva duzhka vishtovhuvati zi steku operatori do chergi na vihodi Yaksho liva duzhka tak i ne zustrilas todi abo vidokremlyuvach ne na svoyemu misci abo propusheni duzhki Yaksho poznachka ce operator o1 todi doki na verhivci steku operator o2 iabo o1livo asociativnij i jogo pershist mensha nizh chi dorivnyuye pershosti o2 abo o1 pravo asociativnij i pershist mensha nizh u o2 dd vishtovhnuti o2 zi steku do chergi na vihodi dd zashtovhnuti o1 na stek dd Yaksho poznachka ce liva duzhka zashtovhnuti na stek Yaksho prava duzhka Dopoki ne zustrinetsya liva duzhka vishtovhuvati operatori zi steka do chergi na vihodi Vishtovhnuti livu duzhku zi steku ale ne do chergi na vihodi Yaksho poznachka na verhivci steku ce poznachka funkciyi vishtovhnuti yiyi do chergi na vihodi Yaksho stek zavershivsya a liva duzhka ne zustrilas todi vona bula propushena dd Koli vzhe nemaye poznachok na vhodi Doki she ye operatori v steci Yaksho operator na verhivci steku ce duzhka znachit bula propushena duzhka Vishtovhnuti operatori do chergi na vihodi dd Vihid Dlya rozboru skladnosti cogo algoritmu za chasom vikonannya mozhna sposteregti sho kozhna poznachka bude prochitana odin raz kozhne chislo funkciya chi operator bude nadrukovana odin raz i kozhna funkciya operator abo duzhka bude zashtovhnuta na stek i vishtovhnuta zvidti odin raz otzhe ne bilshe staloyi kilkosti operacij bude vikonano z kozhnoyu poznachkoyu zvidsi chas vikonannya O n linijnij shodo rozmiru vhidnih danih Algoritm sortuvalnoyi stanciyi takozh mozhna zastosovuvati dlya otrimannya prefiksnogo zapisu takozh vidomogo yak polska notaciya Dlya cogo neobhidno pochati z danogo ryadka v zvorotnomu napryamku i todi rozvernuti chergu na vihodi vnaslidok chogo peretvorivshi chergu na vihodi na stek na vihodi Priklad realizaciyi na C algoritm sortuvalnoyi stanciyi string shuntingYard const string amp input Stack lt char gt stack string output unsigned length input length for unsigned i 0 i lt length i perevirka chi vhidnij simvol ye chastinoyu chisla vrahuvannya unarnogo if isNumber input i input i amp amp i 0 i gt 0 amp amp input i 1 amp amp input i perevirka ce ostannij simvol chisla shob postaviti pislya nogo probil if i 1 length isOperator input i 1 input i 1 input i 1 output output input i else output output input i else if input i stack push else if input i while stack top output output stack pop stack pop else if isOperator input i while stack isEmpty amp amp opPreced stack top gt opPreced input i output output stack pop stack push input i else pomilka vhidnih danih throw Pomilka vhidnih danih vivodimo simvoli sho zalishilis u steku unsigned stackSize stack size if stackSize gt 0 for unsigned i 0 i lt stackSize 1 i output output stack pop output output stack pop return output Funkciya dlya viznachennya prioritetu operacij unsigned opPreced const char ch switch ch case return 3 case case return 2 case case return 1 dlya vipadku vhidnogo simvolu return 0 bool isNumber char ch return 0 lt ch amp amp ch lt 9 ch bool isOperator char ch return ch ch ch ch ch PosilannyaOriginalnij opis algoritmu Dejkstroyu