<
  • Главная
Статьи

Методи сортування та їх візуалізація за допомогою MQL5

  1. зміст Вступ
  2. Застосування бібліотеки Graphics \ Graphic.mqh
  3. методи сортування
  4. Всі методи на одному екрані
  5. тестуємо многопоточность
  6. Примітка від редакторів статті

зміст

Вступ

У Мережі можна знайти ряд відеороликів з демонстрацією різних видів угруповань. наприклад, тут представлена ​​візуалізація 24 алгоритмів сортування. Це відео я і взяв за основу, поряд зі списком алгоритмів сортування.

Для роботи з графіками в MQL5 розроблена спеціальна бібліотека Graphic.mqh. Вона вже описана в статтях: зокрема, тут детально розповідається про можливості бібліотеки. Моє завдання - описати її точки прикладання, практичне застосування, а також детально розповісти про самих сортуваннях. По кожній сортуванні існує як мінімум окрема стаття, а по ряду з них - цілі дослідження, тому опишу лише загальну ідею.

Застосування бібліотеки Graphics \ Graphic.mqh

Робота з бібліотекою починається з її підключення.

#include <Graphics \ Graphic.mqh>

Сортувати будемо стовпчики гістограми, застосуємо для цього функції обміну Gswap () і порівняння GBool (). Елементи, над якими будуть проводитися операції (порівняння, заміна і т.д.), виділяються кольором. Для цього кожному кольору виділений окремий об'єкт типу CCurve (крива). Щоб не розносити ці об'єкти за функціями Gswap (int i, int j, CGraphic & G, CCurve & A, CCurve & B, CCurve & C), зробимо їх глобальними. Клас CCurve не має конструктора за замовчуванням, тому просто оголосити його глобальним не вийде. Тому оголосимо глобальні покажчики типу CCurve * CMain.

Колір можна задавати трьома різними способами. Найбільш наочний з них має вигляд C'0x00,0x00,0xFF ', або C'Blue, Green, Red'. Крива створюється методом класу CGraphic CurveAdd (), який має кілька реалізацій. Для основної маси елементів зручно вибрати CurveAdd (arr, CURVE_HISTOGRAM, "Main") з одним масивом значень, для допоміжних - CurveAdd (X, Y, CURVE_HISTOGRAM, "Swap") з масивом аргументів X і масивом значень Y, так як елементів буде всього два. Масиви для допоміжних ліній зручно зробити глобальними.

#include <Graphics \ Graphic.mqh> #property script_show_inputs input int N = 42; CGraphic Graphic; CCurve * CMain; CCurve * CGreen; CCurve * CBlue; CCurve * CRed; CCurve * CViolet; double X [2], Y [2], XZ [2], YZ [2]; void OnStart () {double arr []; FillArr (arr, N); X [0] = 0; X [1] = 0; Y [0] = 0; Y [1] = 0; Graphic.Create (0, "G", 0, 30, 30, 780, 380); CMain = Graphic.CurveAdd (arr, CURVE_HISTOGRAM, "Main"); CMain.HistogramWidth (4 * 50 / N); CBlue = Graphic.CurveAdd (X, Y, CURVE_HISTOGRAM, "Pivot"); CBlue.Color (C'0xFF, 0x00,0x00 '); CBlue.HistogramWidth (4 * 50 / N); CRed = Graphic.CurveAdd (X, Y, CURVE_HISTOGRAM, "Swap"); CRed.Color (C'0x00,0x00,0xFF '); CRed.HistogramWidth (4 * 50 / N); CGreen = Graphic.CurveAdd (X, Y, CURVE_HISTOGRAM, "Borders"); CGreen.Color (C'0x00,0xFF, 0x00 '); CGreen.HistogramWidth (4 * 50 / N); CViolet = Graphic.CurveAdd (X, Y, CURVE_HISTOGRAM, "Compare"); CViolet.Color (C'0xFF, 0x00,0xFF '); CViolet.HistogramWidth (4 * 50 / N); Graphic.XAxis (). Min (- 0.5); Graphic.CurvePlot (4); Graphic.CurvePlot (2); Graphic.CurvePlot (0); Graphic.Update (); Sleep (5000); int f = ObjectsDeleteAll (0); } Void FillArr (double & arr [], int num) {int x = ArrayResize (arr, num); for (int i = 0; i <num; i ++) arr [i] = rand () / 328 +10; }

Graphic.XAxis (). Min (- 5) з адаёт відступ від осі ординат, щоб нульовий елемент не зливався з нею. Histogramwidth () - ширина стовпця.

Функція FillArr () заповнює масив випадковими числами від 10 (щоб не зливатися з віссю абсцис) до 110. Масив arr Зробити локальним, щоб функції обміну мали стандартний вигляд swap (arr, i, j). Остання команда ObjectDeleteAll стирає те, що ми намалювали. Інакше доведеться видаляти об'єкт через Меню "Список об'єктів" Ctrl + B.

Наша заготівля завершена, можна приступати до сортування.

Наша заготівля завершена, можна приступати до сортування

Функції обміну, порівняння і кордонів

Напишемо функції для візуалізації обміну, порівнянь і виділення кордонів для сортувань розподілом. Перша функція обміну void Gswap () стандартна, але з додаванням кривої CRed для виділення елементів для порівняння

void Gswap (double & arr [], int i, int j) {X [0] = i; X [1] = j; Y [0] = arr [i]; Y [1] = arr [j]; CRed.Update (X, Y); Graphic.Redraw (); Graphic.Update (); Sleep (TmS); double sw = arr [i]; arr [i] = arr [j]; arr [j] = sw; Y [0] = 0; Y [1] = 0; CRed.Update (X, Y); CMain.Update (arr); Graphic.Redraw (); Graphic.Update (); }

Спочатку виділяємо стовпці, потім через деякий час Sleep (TmS), що визначає швидкість демонстрації, повертаємо в початковий стан. Аналогічно пишемо функції порівняння для "<" і "<=" у вигляді bool GBool (double arr, int i, int j) і GBoolEq (double arr, int i, int j). У них додаємо стовпці іншого кольору CViole.

bool GBool (double & arr [], int i, int j) {X [0] = i; X [1] = j; Y [0] = arr [i]; Y [1] = arr [j]; CViolet.Update (X, Y); Graphic.Redraw (); Graphic.Update (); Sleep (TmC); Y [0] = 0; Y [1] = 0; CViolet.Update (X, Y); Graphic.Redraw (); Graphic.Update (); return arr [i] <arr [j]; }

Функція для виділення меж, стовпці якої прати не потрібно.

void GBorders (double & a [], int i, int j) {XZ [0] = i; XZ [1] = j; YZ [0] = a [i]; YZ [1] = a [j]; CGreen.Update (XZ, YZ); Graphic.Redraw (); Graphic.Update (); }

Тепер перейдемо безпосередньо до самих сортувань.

методи сортування

Перш ніж перейти до розбору методів, хочу порадити запустити програму VisualSort, яка знаходиться в прикріпленому файлі VisualSort.ex5. Вона дозволить наочно подивитися, як працює кожна сортування окремо. Повний код угруповань знаходиться під включається файлі GSort.mqh. Він вийшов досить великий, тому тут я змалював тільки основні ідеї.

  • Перша сортування, з якої зазвичай починають вивчення - сортування вибором (Selection sort). Н аходітся номер мінімального значення в поточному списку і міняємо його на значення першої невідсортоване позиції.

template <typename T> void Select (T & arr []) {int n = ArraySize (arr); for (int j = 0; j <n; j ++) {int mid = j; for (int i = j + 1; i <n; i ++) {if (arr [i] <arr [mid]) {mid = i; }} If (arr [j]> arr [mid]) {swap (arr, j, mid);}}}

Тут і далі функція обміну - це раніше написані нами Gswap (), а порівняння елементів масиву потім замінюється на GBool (). Наприклад, if (arr [i] <arr [mid]) => if (GBool (arr, i, mid).

  • Наступна сортування (яка, до речі, часто використовується при грі в карти) - сортування вставками. У цьому методі елементи вхідної послідовності проглядаються по одному, і кожен новий надійшов елемент розміщується в підходяще місце серед уже упорядкованих раніше. Базовий метод:

template <typename T> void Insert (T & arr []) {int n = ArraySize (arr); for (int i = 1; i <n; i ++) {int j = i; while (j> 0) {if (arr [j] <arr [j- 1]) {swap (arr, j, j- 1); j--; } Else j = 0; }}}

Похідні від неї - сортування Шелла (Shell Sort) і Вставка з двійковим пошуком (Binary Insertion Sort). Ідея методу Шелла полягає в порівнянні елементів, що стоять не просто поруч, а й на певній відстані один від одного. Іншими словами, це сортування вставками з попередніми «грубими» проходами. Binary Insertion використовує для пошуку місця вставки двійковий пошук. На вже згаданій вище демонстрації (VisualSort.ex5) добре видно, як Shell поступово "розчісує" масив все більш дрібної гребінкою. У цьому плані він схожий з методом Comb, описаним нижче.

  • Бульбашкова сортування і похідні від неї - шейкерні (Shake Sort), гноми (Gnom), гребінець (Comb) і Odd-Even Sort. Суть бульбашкового сортування проста: проходимся по масиву від початку до кінця і порівнюємо між собою два сусідні елементи. Якщо вони не відсортованого, міняємо їх місцями. В результаті кожної ітерації найбільший елемент буде знаходитися в кінці масиву. Потім процедура повторюється, і в результаті ми отримуємо упорядкований, відсортований масив. Базовий алгоритм бульбашкового сортування:

template <typename T> void BubbleSort (T & a []) {int n = ArraySize (a); for (int i = 0; i <n - 1; i ++) {bool swapped = false; for (int j = 0; j <n - i - 1; j ++) {if (a [j]> a [j + 1]) {swap (a, j, j + 1); swapped = true; }} If (! Swapped) break; }}

При шейкерні сортування проходи відбуваються в обидві сторони, тому "спливають" не тільки великі елементи, а й "осідають" маленькі. Гном цікава тим, що вона реалізована за все одним циклом. Наведу її код:

void GGnomeSort (double & a []) {int n = ArraySize (a); int i = 0; while (i <n) {if (i == 0 || GBoolEq (a, i- 1, i)) i ++; else {Gswap (a, i, i- 1); i--; }}}

Якщо засікти місце вже відсортованих елементів, отримаємо сортування вставками. Comb використовує ту ж саму ідею, що і Shell: проходиться по масиву гребінцями з різним кроком. Для нього навіть вирахували оптимальний коефіцієнт зменшення = 1,247 ≈ (1 / (1-е ^ (- φ))), де е - експонента; φ - "золоте" число. За швидкістю на невеликих масивах Comb і Shell не поступаються швидким сортувань. Odd-Even Sort проходить по черзі по парних / непарних елементів. Оскільки вона замислювалася як сортування для багатопотокового реалізації, то в нашому випадку абсолютно безглузда.

  • Більш складні методи засновані на принципі "розділяй і володарюй". Класичні приклади - сортування Хоара або швидке сортування

Загальна ідея алгоритму полягає в наступному: вибираємо з масиву елемент, званий опорним (pivot). Це може бути будь-який з елементів масиву. Порівнюємо всі інші елементи з опорним і переставляємо їх в масиві так, щоб розбити масив на два безперервних відрізка: "менше" опорного і "більше". Для відрізків "менших" і "великих" значень виконуємо рекурсивно ту ж послідовність операцій, якщо довжина відрізка більше одиниці. Основна ідея міститься в псевдокоді:

algorithm quicksort (A, lo, hi) is if (lo <hi) {p = partition (A, lo, hi); quicksort (A, lo, p - 1); quicksort (A, p, hi);
}

Різниця варіантів сортування в цьому випадку зводиться до різних способів розбиття масиву. У первинному варіанті покажчики біжать з різних сторін назустріч одна одній. Лівий покажчик знаходить елемент більше еталонного, а правий - менше, і вони обмінюються. В іншому варіанті обидва покажчика біжать зліва направо. Коли перший знаходить "менший" елемент, він переставляє його в позицію другого покажчика. Для випадків, коли в масиві багато однакових елементів, розбиття виділяє місце для елементів, рівних опорного. Така схема застосовується, коли потрібно, наприклад, відсортувати співробітників всього по двом ключам - "М" і "Ж". Схема розбивки на малюнку:

Для прикладу наведу лише QSortLR з варіантом розбивки Хоара:

void GQsortLR (double & arr [], int l, int r) {if (l <r) {GBorders (arr, l, r); int mid = PartitionLR (arr, l, r); GQsortLR (arr, l, mid- 1); GQsortLR (arr, mid + 1, r); }} Int PartitionLR (double & arr [], int l, int r) {int i = l- 1; int j = r; for (;;) {while (GBool (arr, ++ i, r)); j--; while (GBool (arr, r, j)) {if (j == l) break; j--;} if (i> = j) break; Gswap (arr, i, j); } Gswap (arr, i, r); YZ [0] = 0; YZ [1] = 0; CGreen.Update (XZ, YZ); Graphic.Redraw (); Graphic.Update (); return i; }

Ділити масив годі й на дві частини, а на 3, 4, 5 ... з декількома еталонними елементами. Як варіант використовується сортування DualPivot, з двома опорними елементами.

  • Інші методи, засновані на принципі "розділяй і володарюй", використовують злиття вже відсортованих елементів масиву. Вони ділять масив до тих пір поки він не стане довжини 1, тобто відсортованим, потім використовують функцію злиття, яка заодно і сортує елементи. Загальний принцип:

void GMergesort (double & a [], int l, int r) {int m = (r + l) / 2; GMergesort (a, l, m); GMergesort (a, m + 1, r); Merge (a, l, m, r); }

Сортування BitonicSort () робить одну половину масиву зростаючої, іншу спадної, потім їх з'єднує.

  • Сортування за допомогою дерев (пірамідальна сортування)

Загальний принцип наступний. Спочатку за допомогою методу "просіювання" з масиву утворюємо "купу". Потім видаляємо старший елемент, який знаходиться в вершині купи. Його поміщаємо в кінець вихідного масиву як найстарший, і на його місце ставимо останній елемент з невідсортоване частини. Будуємо нову купу розміру n-1 і т.д. "Купи" можуть бути побудовані за різними принципами. Наприклад, сортування Smooth () використовує купи, число елементів в яких одно числах Леонардо L (x + 2) = L (x + 1) + L (x) +1.

  • Сортування за лінійний час. Сортування підрахунком і порозрядні сортування MSD і LSD

Сортування підрахунком (Counting sort) - алгоритм сортування, в якому використовується діапазон чисел сортованого масиву (списку) для підрахунку співпадаючих елементів. Застосування сортування підрахунком доцільно лише тоді, коли сортовані числа мають діапазон можливих значень, який досить малий у порівнянні з сортируемое безліччю, наприклад, мільйон натуральних чисел, менших 1000. Її принцип застосовується і в порозрядних сортуваннях. Наведу алгоритм:

void CountSort (double & a []) {int count []; double aux []; int k = int (a [int (ArrayMaximum (a))] + 1); int n = ArraySize (a); ArrayResize (count, k); ArrayResize (aux, n); for (int i = 0; i <k; i ++) count [i] = 0; for (int i = 0; i <n; i ++) count [int (a [i])] ++; for (int i = 1; i <k; i ++) count [i] = count [i] + count [i- 1]; for (int j = n- 1; j> = 0; j--) aux [- count [int (a [j])]] = a [j]; for (int i = 0; i <n; i ++) a [i] = aux [i]; }

Ідея сортування підрахунком застосовуються в MSD- і LSD-сортуваннях за лінійний час. Мається на увазі час час N * R, де N - число елементів, а R - число розрядів в поданні числа в обраній системі числення. MSD (most significant digit) сортує по старшому розряду, LSD (least significant digit) - по молодшому. Наприклад, в двійковій системі LSD підрахує, скільки чисел закінчується на 0, а скільки - на 1, і потім в першу половину помістить парні числа (0), а в другу непарні (1). MSD - навпаки, починає зі старшого розряду. Якщо взяти десяткову систему то на початку вона помістить числа <100, а далі> 100. Потім масив буде знову відсортований на відрізки 0-19, 10-19, ..., 100-109 і т.д. Сортування за цим методом піддаються цілі числа. Але котирування 1.12307 можна зробити цілої 1.12307 * 100 000.

Комбінацією швидкого сортування та поразрядной отримуємо двійкову швидку сортування QuicksortB (). Тут застосовується розбивка сортування QSortLR, тільки відбір відбувається не по еталонному елементу (pivot) масиву, а по старшому розряду. Для цього тут і в LSD c MSD застосовується функція знаходження цифри n-го розряду

int digit (double x, int rdx, int pos) // Тут x число, rdx систем числення {// в нашому випадку 2, pos номер розряду int mid = int (x / pow (rdx, pos)); return mid% rdx; } Спочатку відбувається поділ по старшому розряду int d = int (log (a [ArrayMaximum (a)]) / log (2)), потім рекурсивно упорядковано частини по молодшим розрядам. Зовні схожа на QuickSortLR.

  • Деякі специфічні сортування

Циклічна сортування ( Cycle Sort ) Призначалася для систем, де перезапис даних веде до зносу ресурсів. Отже, завдання тут - знайти сортування з найменшою кількістю обмінів (Gswap). Для цього і використовуються циклічні перестановки. Грубо кажучи, 1 переставляється в 3, 3 в 2, 2 в 1. Кожен елемент переставляється або 0, або 1 раз. Все це відбувається досить довго, час O (n ^ 2). Детальніше з ідеєю і методом можна познайомитися тут .

Блукаюча сортування ( Stooge sort ). Це ще один приклад надуманої і дуже повільної сортування. Алгоритм полягає в наступному. Якщо значення елемента в кінці списку менше, ніж значення елемента на початку, то потрібно поміняти їх місцями. Якщо є 3 або більше елементів в поточному підмножині списку, то: рекурсивно викликаємо Stoodge () для перших 2/3 списку, рекурсивно викликаємо Stoodge () для останніх 2/3, знову рекурсивно викликаємо Stoodge () для перших 2/3 і т. д.

Зведена таблиця швидкості методів

Методи сортування Середній час Сортування вибором (Selection sort) O (n ^ 2) Сортування вставками (Insertion sort) O (n ^ 2) Вставками з двійковим пошуком (Binary Selection Sort) O (n ^ 2) Сортування Шелла (Shell sort) O (n * log (n)) Бульбашкова сортування (Bubble sort) O (n ^ 2) шейкерні сортування (Shaker / Cocktail sort) O (n ^ 2) Гном сортування (Gnom Sort) O (n ^ 2) Сортування гребінцем (Comb Sort) O (n * log (n)) Сортування злиттям (Merge Sort) O ( n * log (n)) Бітон сортування (Bitonic sort) O (n * log (n)) Пірамідальна сортування (Heap sort) O (n * log (n)) Плавне сортування (Smooth sort) O (n * log (n )) Швидке сортування (LR) (Quick sort LR) O (n * log (n)) Швидке сортування (LL) (Quick sort LL) O (n * log (n)) Quick Sort (ternary, LR ptrs) O ( n * log (n)) Quick Sort (ternary, LL ptrs) O (n * log (n)) Quick Sort (dual pivot) O (n * log (n)) Сортування підрахунком (Counting sort) O (n + k ) сортування за розрядами LSD (Radix LSD) O (n * k) Поразря ная сортування MSD (Radix MSD) O (n * k) Двійкова швидке сортування (Quick Binary sort) O (n * log (n)) Циклічна сортування (Cycle sort) O (n ^ 2) Stoodge sort O (n ^ 2.7)

Всі методи на одному екрані

Виведемо всі описані сортування одночасно на один екран. В вихідному відео розібрані сортування запущені по одній, потім все це змонтовано в редакторі відео. Але в торговий термінал не вбудовані можливості відеостудії. Вийти з положення можна декількома способами.

Варіант №1.

Імітувати многопоточность. Распараллеліть сортування так, щоб після кожного порівняння і обміну можна було б вийти з функції і передати чергу інший сортування, а потім знову увійти в неї на тому ж місці. З огляду на, що оператора GOTO немає, завдання ускладнюється. Ось, наприклад, як буде виглядати в цьому варіанті найпростіша сортування вибором, яка наводилася в самому початку:

void CSelect (double & arr []) {static bool ch; static int i, j, mid; int n = ArraySize (arr); switch (mark) {case 0: j = 0; mid = j; i = j + 1; ch = arr [i] <arr [mid]; if (ch) mid = i; mark = 1; return; break; case 1: for (i ++; i <n; i ++) {ch = arr [i] <arr [mid]; mark = 1; if (ch) mid = i; return; } Ch = arr [j]> arr [mid]; mark = 2; return; break; case 2: if (ch) {swap (arr, j, mid); mark = 3; return; } For (j ++; j <n; j ++) {mid = j; for (i = j; i <n; i ++) {ch = arr [i] <arr [mid]; if (ch) mid = i; mark = 1; return; } Ch = arr [j]> arr [mid]; mark = 2; return; } Break; case 3: for (j ++; j <n; j ++) {mid = j; for (i = j; i <n; i ++) {ch = arr [i] <arr [mid]; if (ch) mid = i; mark = 1; return; } Ch = arr [j]> arr [mid]; mark = 2; return; } Break; } Mark = 10; }

Це цілком робочий варіант. При такому запуску масив буде відсортований:

while (mark! = 10) {CSelectSort (arr); count ++; }

Мінлива count покаже загальна кількість порівнянь і перестановок. При цьому код розрісся в три-чотири рази, але ж це найпростіша сортування. Є ще сортування складаються з декількох функцій, рекурсивні ...

варіант №2

Є простіший варіант. У терміналі MQL5 підтримується концепція многопоточности. Щоб її реалізувати, для кожної сортування потрібно з експерта викликати призначений для користувача індикатор. Але для кожного потоку індикатор повинен бути по окремій валютній парі. У вікні Огляд Ринку (Market Watch) має бути достатньо інструментів для кожної сортування.

n = (SymbolName (n, 0), 0, "IndcatorSort", ..., SymbolName (n, 0), Sort1, N);

Тут SymbolName (n, 0) - окремий інструмент для кожного створюваного потоку і параметри, що передаються в індикатор. Для призначення імені графічного об'єкта зручно використовувати SymbolName (n, 0). На одному графіку може бути тільки один об'єкт класу CGraphic з такою назвою. Вид сортування і кількість елементів в масиві, а також розміри самого полотна CGraphic тут не показані.

У самому індикаторі відбувається вибір функції сортування і інші додаткові дії, пов'язані з оформленням (наприклад, підпис осей ім'ям сортування).

switch (SortName) {case 0: Graphic.XAxis (). Name ( "Selection"); CMain.Name ( "Selection"); Select (arr); break; case 1: Graphic.XAxis (). Name ( "Insertion"); CMain.Name ( "Insertion"); Insert (arr); break; etc .............................................}

На створення графічних об'єктів йде певний час. Тому, щоб сортування почали працювати одночасно, були додані глобальні змінні. NAME - глобальна змінна з ім'ям інструменту, якій спочатку присвоюється значення 0. Після створення всіх необхідних об'єктів вона отримує значення 1, а після завершення сортування 2. Так можна відстежувати моменти початку і закінчення угруповань. Для цього в експерта запускається таймер:

void OnTimer () {double x = 1.0; double y = 0,0; static int start = 0; for (int i = 0; i <4; i ++) {string str; str = SymbolName (i, 0); x = x * GlobalVariableGet (str); y = y + GlobalVariableGet (str); } If (x && start == 0) {start = 1; GlobalVariableSet ( "ALL", 1); PlaySound ( "Sort.wav"); } If (y == 8) {PlaySound ( "success.wav"); EventKillTimer ();}}

Тут змінна х відловлює початок, а у - кінець процесу.

На початку дії включається звук, знятий з оригінального відео. Для роботи з кодами він повинен знаходитися в папці MetaTrader / Sound разом з іншими системними звуками формату * .wav або, якщо він знаходиться в іншому місці, необхідно вказати шлях від папки MQL5. Для завершення використовується інший файл success.wav.

Отже, створюємо експерт і індикатор такого вигляду. експерт:

enum SortMethod {Selection, Insertion, .......... Методи сортування .........}; input int Xscale = 475; input int N = 64; input SortMethod Sort1; .......... Різні вхідні параметри ................. int OnInit () {for (int i = 0; i <4; i ++) {SymbolSelect (SymbolName (i, 0), 1); GlobalVariableSet (SymbolName (i, 0), 0);} ChartSetInteger (0, CHART_SHOW, 0); EventSetTimer (1); GlobalVariableSet ( "ALL", 0); x = 0 * Xscale-Xscale * 2 * (0/2); y = (0/2) * Yscale + 1; SymbolSelect (SymbolName (0, 0), 1); S1 = (SymbolName (0, 0), 0, "Sort1", 0, 0, x, y, x + Xscale, y + Yscale, SymbolName (0, 0), Sort1, N); return (0); } Void OnDeinit (const int reason) {ChartSetInteger (0, CHART_SHOW, 1); EventKillTimer (); int i = ObjectsDeleteAll (0); PlaySound ( "ok.wav"); GlobalVariableSet ( "ALL", 0); IndicatorRelease (Sort1); ....... Все що потрібно видалити ...... void OnTick () {... Пусто ...} void OnTimer () {.... Описана вище ....}

І до нього індикатор:

#include <GSort.mqh> .......... Блок вхідних параметрів .............................. ....... input int SortName; int N = 30; .................................................. .................... int OnInit () {double arr []; FillArr (arr, N); GlobalVariableSet (NAME, 0); Graphic.Create (0, NAME, 0, XX1, YY1, XX2, YY2); Graphic.IndentLeft (- 30); Graphic.HistoryNameWidth (0); CMain = Graphic.CurveAdd (arr, CURVE_HISTOGRAM, "Main"); CMain.HistogramWidth (2); CRed = Graphic.CurveAdd (X, Y, CURVE_HISTOGRAM, "Swap"); CRed.Color (C'0x00,0x00,0xFF '); CRed.HistogramWidth (width); ...... Різні графічні параметри .......................... Graphic.CurvePlotAll (); Graphic.Update (); GlobalVariableSet (NAME, 1); while (! GlobalVariableGet ( "ALL")); switch (SortName) {case 0: Graphic.XAxis (). Name ( "Selection"); CMain.Name ( "Selection"); GSelect (arr); break; ..... Список угруповань ........................................... ...} GlobalVariableSet (NAME, 2); return INIT_SUCCEEDED; } Int OnCalculate (...) {.............. Пусто ........................} void OnDeinit (const int reason) {Graphic.Destroy (); delete CMain; delete CRed; delete CViolet; delete CGreen; ObjectDelete (0, NAME); }

тестуємо многопоточность

Light.ex5 і Sort24.ex5 - готові до роботи програми. Вони скомпільовані через ресурси і нічого більше не вимагають. При роботі з кодами вони повинні бути встановлені в відповідні папки індикаторів і звуків.

Версія Sort24.ex5 з 24 угрупованнями на моєму звичайному одноядерному комп'ютері нестабільна, допрацьовує через раз. Треба закрити все зайве і нічого не чіпати. У кожній сортування п'ять графічних об'єктів - чотири криві і полотно. Всі вони безперервно перемальовувати. Двадцять чотири потоки створюють 120 (!) Окремих безупинно мінливих графічних об'єкта в 24 потоках. Її я зробив просто як демонстрацію, що таке в принципі можливо і більше з нею не працював.

Її я зробив просто як демонстрацію, що таке в принципі можливо і більше з нею не працював

Робоча, досить стабільна версія Light.ex5 одночасно виводить 4 сортування. Тут додані можливості вибору кількості елементів і методів сортування в кожному вікні. Крім того, є можливість вибрати спосіб перетасовки масиву: випадковий, по висхідній (тобто вже відсортоване), по низхідній (відсортоване в зворотному порядку) і масив, де багато однакових елементів (step array). Наприклад, швидке сортування деградує до O (n ^ 2) на масиві, відсортованому в зворотному порядку, а пірамідальна завжди сортує за n * log (n). На жаль, в індикаторах функція Sleep () не підтримується, так що швидкість залежить тільки від системи. Крім того, кількість ресурсів, що виділяються кожному потоку, також довільно. Якщо в кожному вікні запустити одну і ту ж сортування, то вони прийдуть до фінішу все по-різному.

Підбиваючи підсумки:

  • Однопоточні VisualSort - на 100% робоча
  • Четирёхпоточная Light - стабільна
  • Двадцатічетирёхпоточная Sort24 - нестабільна

Можна було б піти по першому варіанту, імітуючи многопоточность. Тоді б ми повністю контролювали процес. Працювали б функції Sleep (), кожна сортування отримувала б строго однаковий час і т.д. Але при цьому втрачалася б сама концепція многопоточного програмування на MQL5.

Остаточний варіант:

Остаточний варіант:

.................................................. .................................................. .................................................. ..............

Список доданих файлів

  • VisaulSort.ex5 - кожна сортування окремо
  • Programs (Sort24.ex5, Light.ex5) - готові програми
  • звукові файли
  • Codes. Вихідні тексти програм - самі сортування, індикатори, що включаються файли, експерти.

Примітка від редакторів статті

Автор статті реалізував цікавий варіант багатопотокової сортування за допомогою одночасного запуску безлічі індикаторів. Дана архітектура дуже сильно навантажує комп'ютер, тому ми трохи допрацювали вихідні коди автора, а саме:

  • в файлі auxiliary.mq заборонили виклик перемальовування графіка з кожного індикатора
    void GBorders (double & a [], int i, int j) {XZ [0] = i; XZ [1] = j; YZ [0] = a [i] + 2; YZ [1] = a [j] + 5; CGreen.Update (XZ, YZ); Graphic.Redraw (false); Graphic.Update (false); }
  • додали функцію randomize (), яка готує для всіх індикаторів одні і ті ж випадкові дані в масиві
  • в файл IndSort2.mq5 додали зовнішні параметри, які задають розмір масиву з випадковими значеннями (у автора воно жорстко дорівнює 24) і инициализирующее число sid для генерації даних
    input uint sid = 0; int N = 64;
  • в файл Sort24.mq5 додали таймер для відтворення графіка за допомогою ChartRedraw ()
    void OnTimer () {double x = 1.0; double y = 0,0; static int start = 0; for (int i = 0; i <methods; i ++) {string str; str = SymbolName (i, 0); x = x * GlobalVariableGet (str); y = y + GlobalVariableGet (str); } If (x && start == 0) {start = 1; GlobalVariableSet ( "ALL", 1); PlaySound ( "Sort.wav"); } If (y == methods * 2) {PlaySound ( "success.wav"); EventKillTimer (); } ChartRedraw (); }
  • звукові файли перенесли в папку <> \ MQL5 \ Sounds щоб можна було включити їх в якості ресурсу
    #resource "\\ Sounds \\ Sort.wav"; #resource "\\ Sounds \\ success.wav"; #resource "\\ Indicators \\ Sort \\ IndSort2.ex5"

Готова для компіляції структура прикладена в архіві moderators_edition.zip, яку досить розпакувати і скопіювати в свій термінал. Якщо у вас не дуже потужний комп'ютер, рекомендуємо у вхідних параметрах встановити methods = 6 або methods = 12.

Якщо у вас не дуже потужний комп'ютер, рекомендуємо у вхідних параметрах встановити methods = 6 або methods = 12



Новости
  • Виртуальный хостинг

    Виртуальный хостинг. Возможности сервера распределяются в равной мере между всеми... 
    Читать полностью

  • Редизайн сайта

    Редизайн сайта – это полное либо частичное обновление дизайна существующего сайта.... 
    Читать полностью

  • Консалтинг, услуги контент-менеджера

    Сопровождение любых интернет ресурсов;- Знание HTML и CSS- Поиск и обновление контента;-... 
    Читать полностью

  • Трафик из соцсетей

    Сравнительно дешевый способ по сравнению с поисковым и контекстным видами раскрутки... 
    Читать полностью

  • Поисковая оптимизация

    Поисковая оптимизация (англ. search engine optimization, SEO) — поднятие позиций сайта в результатах... 
    Читать полностью