//+------------------------------------------------------------------+ //| Sort.mqh | //| Copyright 2026, Niquel Mendoza. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, Niquel Mendoza." #property link "https://www.mql5.com" #property strict #ifndef MQLARTICLES_UTILS_SORT_BASE_SORT_MQH #define MQLARTICLES_UTILS_SORT_BASE_SORT_MQH //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #define MQLARTICLES_INSERTION_SORT_TRSHOLD (16) //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CTsnSort { private: //--- template static void InternalSort(TValue& arr[], int lo, int hi, int depthLimit); template static int partition(TValue &arr[], int lo, int hi, TValue& pivot); template static void InsertionSort(TValue &arr[], int lo, int hi); template static void HeapSort(TValue &arr[], int lo, int hi); template static void Heapify(TValue &arr[], int parent, int heap_size, int lo); template static void Median3(TValue &arr[], int lo, int hi, TValue& pivot); template static void Sort3(TValue &xs[], int a, int b, int c); template static void Sort2(TValue &xs[], int a, int b); public: CTsnSort(void) {} ~CTsnSort(void) {} //--- template static void Sort(TValue& arr[], int lo, int hi); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template static void CTsnSort::Sort(TValue& arr[], int lo, int hi) { const int size = hi - lo + 1; if(size < 2) return; const int depthLimit = int(MathFloor(MathLog(size) / M_LN2)) << 1; InternalSort(arr, lo, hi, depthLimit); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template static void CTsnSort::InternalSort(TValue& arr[], int lo, int hi, int depthLimit) { while(lo < hi) { const int partitionSize = (hi - lo) + 1; //--- Insertion sort is faster for small partitions. if(partitionSize <= MQLARTICLES_INSERTION_SORT_TRSHOLD) { InsertionSort(arr, lo, hi); return; } //--- If recursion depth exceeds limit, switch to heapsort to guarantee O(n log n). if(--depthLimit == 0) { HeapSort(arr, lo, hi); return; } //--- Pick pivot as the median-of-three. TValue pivot; Median3(arr, lo, hi, pivot); //--- Hoare’s partitioning scheme. const int p = partition(arr, lo, hi, pivot); const int leftSize = p - lo; const int rightSize = hi - p + 1; //--- Recurse into the smaller partition and process the larger one //--- iteratively. This guarantees O(log n) recursion depth. if(leftSize < rightSize) { InternalSort(arr, lo, p - 1, depthLimit); lo = p; } else { InternalSort(arr, p, hi, depthLimit); hi = p - 1; } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template static int CTsnSort::partition(TValue &arr[], int lo, int hi, TValue& pivot) { while(lo <= hi) { while(TBase::Less(arr[lo], pivot)) lo++; while(TBase::Less(pivot, arr[hi])) hi--; if(lo > hi) break; TBase::Swap(arr[lo++], arr[hi--]); } return lo; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template static void CTsnSort::InsertionSort(TValue &arr[], int lo, int hi) { for(int i = lo + 1; i <= hi; i++) { if(TBase::Less(arr[i], arr[i - 1])) { TValue curr = arr[i]; arr[i] = arr[i - 1]; int j = i; while(--j > lo && TBase::Less(curr, arr[j - 1])) arr[j] = arr[j - 1]; arr[j] = curr; } } } //+------------------------------------------------------------------+ //| Heap Sort | //+------------------------------------------------------------------+ template static void CTsnSort::HeapSort(TValue &arr[], int lo, int hi) { const int size = hi - lo + 1; for(int i = (size >> 1) - 1; i >= 0; i--) { Heapify(arr, i, size, lo); } for(int i = size - 1; i > 0; i--) { TBase::Swap(arr[lo], arr[lo + i]); Heapify(arr, 0, i, lo); } } //+------------------------------------------------------------------+ //| Rebuilds the heap. | //+------------------------------------------------------------------+ template static void CTsnSort::Heapify(TValue &arr[], int parent, int heap_size, int lo) { TValue temp = arr[lo + parent]; int child = (parent << 1) + 1; while(child < heap_size) { //--- if(child + 1 < heap_size && TBase::Less(arr[lo + child], arr[lo + child + 1])) child++; if(!TBase::Less(temp, arr[lo + child])) break; //--- arr[lo + parent] = arr[lo + child]; parent = child; child = (parent << 1) + 1; } arr[lo + parent] = temp; } //+------------------------------------------------------------------+ //| Get the median of three array elements. | //+------------------------------------------------------------------+ template static void CTsnSort::Median3(TValue &arr[], int lo, int hi, TValue& pivot) { const int mid = lo + ((hi - lo) >> 1); Sort3(arr, lo, mid, hi); pivot = arr[mid]; } //+------------------------------------------------------------------+ //| Sorts the elements a, b and c using comparison function less. | //+------------------------------------------------------------------+ template static void CTsnSort::Sort3(TValue &xs[], int a, int b, int c) { Sort2(xs, a, b); Sort2(xs, b, c); Sort2(xs, a, b); } //+------------------------------------------------------------------+ //| Sorts the elements a and b using comparison function less. | //+------------------------------------------------------------------+ template static void CTsnSort::Sort2(TValue &xs[], int a, int b) { if(TBase::Less(xs[b], xs[a])) TBase::Swap(xs[a], xs[b]); } //+------------------------------------------------------------------+ #endif // MQLARTICLES_UTILS_SORT_BASE_SORT_MQH