How it works
Chunk-and-merge strategy modeling large-data sorting workflows beyond RAM.
Implementation
function externalMergeSort(arr, stats) { const n = arr.length; if (n < 2) return; const source = [...arr]; const chunkSize = Math.max(8, Math.floor(Math.sqrt(n || 1))); let runs = []; const sortChunk = chunk => { for (let p = 1; p < chunk.length; p++) { const key = chunk[p]; let j = p - 1; while (j >= 0) { if (chunk[j] <= key) break; chunk[j + 1] = chunk[j]; j--; } chunk[j + 1] = key; } return chunk; }; function renderRuns(activeRuns) { let writeIndex = 0; for (let runIndex = 0; runIndex < activeRuns.length; runIndex++) { const run = activeRuns[runIndex]; for (let valueIndex = 0; valueIndex < run.length; valueIndex++) { const value = run[valueIndex]; arr[writeIndex] = value; write(writeIndex, value); writeIndex++; } } } const mergeRuns = (leftRun, rightRun) => { const merged = []; let leftIndex = 0; let rightIndex = 0; while (leftIndex < leftRun.length && rightIndex < rightRun.length) { if (leftRun[leftIndex] <= rightRun[rightIndex]) { merged.push(leftRun[leftIndex++]); } else { merged.push(rightRun[rightIndex++]); } } while (leftIndex < leftRun.length) merged.push(leftRun[leftIndex++]); while (rightIndex < rightRun.length) merged.push(rightRun[rightIndex++]); return merged; }; for (let i = 0; i < n; i += chunkSize) { const chunk = source.slice(i, Math.min(i + chunkSize, n)); runs.push(sortChunk(chunk)); } renderRuns(runs); while (runs.length > 1) { const nextRuns = []; for (let i = 0; i < runs.length; i += 2) { if (i + 1 >= runs.length) { nextRuns.push(runs[i].slice()); continue; } nextRuns.push(mergeRuns(runs[i], runs[i + 1])); } runs = nextRuns; renderRuns(runs); } for (let i = 0; i < n; i++) markSorted(i); }
def externalMergeSort(arr, stats): def sortChunk(chunk): for p in range(1, len(chunk)): key = chunk[p] j = (p - 1) while (j >= 0): if (chunk[j] <= key): break chunk[(j + 1)] = chunk[j] j -= 1 chunk[(j + 1)] = key return chunk def renderRuns(activeRuns): writeIndex = 0 for runIndex in range(len(activeRuns)): run = activeRuns[runIndex] for valueIndex in range(len(run)): value = run[valueIndex] arr[writeIndex] = value write(writeIndex, value) writeIndex += 1 def mergeRuns(leftRun, rightRun): merged = [] leftIndex = 0 rightIndex = 0 while ((leftIndex < len(leftRun)) and (rightIndex < len(rightRun))): if (leftRun[leftIndex] <= rightRun[rightIndex]): merged.append(leftRun[((leftIndex := leftIndex + 1) - 1)]) else: merged.append(rightRun[((rightIndex := rightIndex + 1) - 1)]) while (leftIndex < len(leftRun)): merged.append(leftRun[((leftIndex := leftIndex + 1) - 1)]) while (rightIndex < len(rightRun)): merged.append(rightRun[((rightIndex := rightIndex + 1) - 1)]) return merged if (n < 2): return source = [*arr] chunkSize = (8 if 8 >= int(int((n or 1) ** 0.5)) else int(int((n or 1) ** 0.5))) runs = [] for i in range(0, n, chunkSize): chunk = source[i:((i + chunkSize) if (i + chunkSize) <= n else n)] runs.append(sortChunk(chunk)) renderRuns(runs) while (len(runs) > 1): nextRuns = [] for i in range(0, len(runs), 2): if ((i + 1) >= len(runs)): nextRuns.append(runs[i][:]) continue nextRuns.append(mergeRuns(runs[i], runs[(i + 1)])) runs = nextRuns renderRuns(runs) for i in range(n): markSorted(i)
#include <vector> #include <algorithm> #include <cmath> int sortChunk(int chunk); void renderRuns(int activeRuns); int mergeRuns(int leftRun, int rightRun); int sortChunk(int chunk) { for(int p=1; p<n; p++) { int key = chunk[p]; int j = (p - 1); while((j >= 0)) { if((chunk[j] <= key)) { break; } chunk[(j + 1)] = chunk[j]; j--; } chunk[(j + 1)] = key; } return chunk; } void renderRuns(int activeRuns) { int writeIndex = 0; for(int runIndex=0; runIndex<n; runIndex++) { int run = activeRuns[runIndex]; for(int valueIndex=0; valueIndex<n; valueIndex++) { int value = run[valueIndex]; arr[writeIndex] = value; write(writeIndex, value); writeIndex++; } } } int mergeRuns(int leftRun, int rightRun) { std::vector<int> merged; int leftIndex = 0; int rightIndex = 0; while(((leftIndex < n) && (rightIndex < n))) { if((leftRun[leftIndex] <= rightRun[rightIndex])) { merged.push_back(leftRun[leftIndex++]); } else { merged.push_back(rightRun[rightIndex++]); } } while((leftIndex < n)) { merged.push_back(leftRun[leftIndex++]); } while((rightIndex < n)) { merged.push_back(rightRun[rightIndex++]); } return merged; } void sort(std::vector<int>& arr, int n, int& comparisons, int& swaps) { if((n < 2)) { return; } std::vector<int> source = {arr}; int chunkSize = ((8) > ((int)std::floor((int)std::sqrt(((n) != 0 ? (n) : (1))))) ? (8) : ((int)std::floor((int)std::sqrt(((n) != 0 ? (n) : (1)))))); std::vector<int> runs; for(int i=0; i<n; i+=chunkSize) { int _chunk_len = (((i + chunkSize)) < (n) ? ((i + chunkSize)) : (n)) - (i); std::vector<int> chunk(source.begin() + (i), source.begin() + ((((i + chunkSize)) < (n) ? ((i + chunkSize)) : (n)))); runs.push_back(sortChunk(chunk)); } renderRuns(runs); while(((int)runs.size() > 1)) { std::vector<int> nextRuns; for(int i=0; i<(int)runs.size(); i+=2) { if(((i + 1) >= (int)runs.size())) { nextRuns.push_back(runs[i]_slice); continue; } nextRuns.push_back(mergeRuns(runs[i], runs[(i + 1)])); } runs = nextRuns; renderRuns(runs); } for(int i=0; i<n; i++) { markSorted(i); } }
int sortChunk(int chunk) { for(int p=1; p<n; p++) { int key = chunk[p]; int j = (p - 1); while((j >= 0)) { if((chunk[j] <= key)) { break; } chunk[(j + 1)] = chunk[j]; j--; } chunk[(j + 1)] = key; } return chunk; } void renderRuns(int activeRuns) { int writeIndex = 0; for(int runIndex=0; runIndex<n; runIndex++) { int run = activeRuns[runIndex]; for(int valueIndex=0; valueIndex<n; valueIndex++) { int value = run[valueIndex]; arr[writeIndex] = value; write(writeIndex, value); writeIndex++; } } } int mergeRuns(int leftRun, int rightRun) { var merged = new List<int>(); int leftIndex = 0; int rightIndex = 0; while(((leftIndex < n) && (rightIndex < n))) { if((leftRun[leftIndex] <= rightRun[rightIndex])) { merged.Add(leftRun[leftIndex++]); } else { merged.Add(rightRun[rightIndex++]); } } while((leftIndex < n)) { merged.Add(leftRun[leftIndex++]); } while((rightIndex < n)) { merged.Add(rightRun[rightIndex++]); } return merged; } public void Sort(int[] arr, int n, dynamic stats) { if((n < 2)) { return; } var source = new List<int> { arr }; int chunkSize = Math.Max(8, (int)Math.Floor((double)(int)Math.Sqrt(((n) != 0 ? (n) : (1))))); var runs = new List<int>(); for(int i=0; i<n; i+=chunkSize) { int _chunk_len = Math.Min((i + chunkSize), n) - (i); int[] chunk = new int[_chunk_len]; Array.Copy(source, i, chunk, 0, _chunk_len); runs.Add(sortChunk(chunk)); } renderRuns(runs); while((runs.Count > 1)) { var nextRuns = new List<int>(); for(int i=0; i<runs.Count; i+=2) { if(((i + 1) >= runs.Count)) { nextRuns.Add(runs[i]_slice); continue; } nextRuns.Add(mergeRuns(runs[i], runs[(i + 1)])); } runs = nextRuns; renderRuns(runs); } for(int i=0; i<n; i++) { markSorted(i); } }
#include <stdio.h> #include <math.h> #include <stdlib.h> int sortChunk(int chunk); void renderRuns(int activeRuns); int mergeRuns(int leftRun, int rightRun); int sortChunk(int chunk) { for(int p=1; p<n; p++) { int key = chunk[p]; int j = (p - 1); while((j >= 0)) { if((chunk[j] <= key)) { break; } chunk[(j + 1)] = chunk[j]; j--; } chunk[(j + 1)] = key; } return chunk; } void renderRuns(int activeRuns) { int writeIndex = 0; for(int runIndex=0; runIndex<n; runIndex++) { int run = activeRuns[runIndex]; for(int valueIndex=0; valueIndex<n; valueIndex++) { int value = run[valueIndex]; arr[writeIndex] = value; write(writeIndex, value); writeIndex++; } } } int mergeRuns(int leftRun, int rightRun) { int* merged = (int*)malloc(n * sizeof(int)); int merged_len = 0; int leftIndex = 0; int rightIndex = 0; while(((leftIndex < n) && (rightIndex < n))) { if((leftRun[leftIndex] <= rightRun[rightIndex])) { merged[merged_len++] = leftRun[leftIndex++]; } else { merged[merged_len++] = rightRun[rightIndex++]; } } while((leftIndex < n)) { merged[merged_len++] = leftRun[leftIndex++]; } while((rightIndex < n)) { merged[merged_len++] = rightRun[rightIndex++]; } return merged; } void sort(int arr[], int n, int* comparisons, int* swaps) { if((n < 2)) { return; } int* source = (int*)malloc(n * sizeof(int)); int source_len = 1; source[0] = arr; int chunkSize = ((8) > ((int)floor((int)sqrt(((n) != 0 ? (n) : (1))))) ? (8) : ((int)floor((int)sqrt(((n) != 0 ? (n) : (1)))))); int* runs = (int*)malloc(n * sizeof(int)); int runs_len = 0; for(int i=0; i<n; i+=chunkSize) { int _chunk_len = (((i + chunkSize)) < (n) ? ((i + chunkSize)) : (n)) - (i); int* chunk = (int*)malloc((_chunk_len) * sizeof(int)); for(int _ci=0;_ci<_chunk_len;_ci++) chunk[_ci]=source[(i)+_ci]; runs[runs_len++] = sortChunk(chunk); } renderRuns(runs); while((runs_len > 1)) { int* nextRuns = (int*)malloc(n * sizeof(int)); int nextRuns_len = 0; for(int i=0; i<runs_len; i+=2) { if(((i + 1) >= runs_len)) { nextRuns[nextRuns_len++] = runs[i]_slice; continue; } nextRuns[nextRuns_len++] = mergeRuns(runs[i], runs[(i + 1)]); } runs = nextRuns; renderRuns(runs); } for(int i=0; i<n; i++) { markSorted(i); } }