216 lines
7.8 KiB
MQL5
216 lines
7.8 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| 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<typename TValue, typename TBase>
|
|
static void InternalSort(TValue& arr[], int lo, int hi, int depthLimit);
|
|
template<typename TValue, typename TBase>
|
|
static int partition(TValue &arr[], int lo, int hi, TValue& pivot);
|
|
template<typename TValue, typename TBase>
|
|
static void InsertionSort(TValue &arr[], int lo, int hi);
|
|
template<typename TValue, typename TBase>
|
|
static void HeapSort(TValue &arr[], int lo, int hi);
|
|
template<typename TValue, typename TBase>
|
|
static void Heapify(TValue &arr[], int parent, int heap_size, int lo);
|
|
template<typename TValue, typename TBase>
|
|
static void Median3(TValue &arr[], int lo, int hi, TValue& pivot);
|
|
template<typename TValue, typename TBase>
|
|
static void Sort3(TValue &xs[], int a, int b, int c);
|
|
template<typename TValue, typename TBase>
|
|
static void Sort2(TValue &xs[], int a, int b);
|
|
|
|
public:
|
|
CTsnSort(void) {}
|
|
~CTsnSort(void) {}
|
|
|
|
//---
|
|
template<typename TValue, typename TBase>
|
|
static void Sort(TValue& arr[], int lo, int hi);
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
template<typename TValue, typename TBase>
|
|
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<TValue, TBase>(arr, lo, hi, depthLimit);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
template<typename TValue, typename TBase>
|
|
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<TValue, TBase>(arr, lo, hi);
|
|
return;
|
|
}
|
|
//--- If recursion depth exceeds limit, switch to heapsort to guarantee O(n log n).
|
|
if(--depthLimit == 0)
|
|
{
|
|
HeapSort<TValue, TBase>(arr, lo, hi);
|
|
return;
|
|
}
|
|
|
|
//--- Pick pivot as the median-of-three.
|
|
TValue pivot;
|
|
Median3<TValue, TBase>(arr, lo, hi, pivot);
|
|
|
|
//--- Hoare’s partitioning scheme.
|
|
const int p = partition<TValue, TBase>(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<TValue, TBase>(arr, lo, p - 1, depthLimit);
|
|
lo = p;
|
|
}
|
|
else
|
|
{
|
|
InternalSort<TValue, TBase>(arr, p, hi, depthLimit);
|
|
hi = p - 1;
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
template<typename TValue, typename TBase>
|
|
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<typename TValue, typename TBase>
|
|
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<typename TValue, typename TBase>
|
|
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<TValue, TBase>(arr, i, size, lo);
|
|
}
|
|
for(int i = size - 1; i > 0; i--)
|
|
{
|
|
TBase::Swap(arr[lo], arr[lo + i]);
|
|
Heapify<TValue, TBase>(arr, 0, i, lo);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Rebuilds the heap. |
|
|
//+------------------------------------------------------------------+
|
|
template<typename TValue, typename TBase>
|
|
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<typename TValue, typename TBase>
|
|
static void CTsnSort::Median3(TValue &arr[], int lo, int hi, TValue& pivot)
|
|
{
|
|
const int mid = lo + ((hi - lo) >> 1);
|
|
Sort3<TValue, TBase>(arr, lo, mid, hi);
|
|
pivot = arr[mid];
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Sorts the elements a, b and c using comparison function less. |
|
|
//+------------------------------------------------------------------+
|
|
template<typename TValue, typename TBase>
|
|
static void CTsnSort::Sort3(TValue &xs[], int a, int b, int c)
|
|
{
|
|
Sort2<TValue, TBase>(xs, a, b);
|
|
Sort2<TValue, TBase>(xs, b, c);
|
|
Sort2<TValue, TBase>(xs, a, b);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Sorts the elements a and b using comparison function less. |
|
|
//+------------------------------------------------------------------+
|
|
template<typename TValue, typename TBase>
|
|
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
|