-
-
Notifications
You must be signed in to change notification settings - Fork 7.3k
/
non_recursive_merge_sort.cpp
109 lines (105 loc) · 4.1 KB
/
non_recursive_merge_sort.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/**
* Copyright 2020 @author Albirair
* @file
*
* A generic implementation of non-recursive merge sort.
*/
#include <cstddef> // for size_t
#include <iostream>
#include <utility> // for std::move & std::remove_reference_t
namespace sorting {
template <class Iterator>
void merge(Iterator, Iterator, const Iterator, char[]);
/// bottom-up merge sort which sorts elements in a non-decreasing order
/**
* sorts elements non-recursively by breaking them into small segments,
* merging adjacent segments into larger sorted segments, then increasing
* the sizes of segments by factors of 2 and repeating the same process.
* best-case = worst-case = O(n log(n))
* @param first points to the first element
* @param last points to 1-step past the last element
* @param n the number of elements
*/
template <class Iterator>
void non_recursive_merge_sort(const Iterator first, const Iterator last,
const size_t n) {
// create a buffer large enough to store all elements
// dynamically allocated to comply with cpplint
char* buffer = new char[n * sizeof(*first)];
// buffer size can be optimized to largest power of 2 less than n
// elements divide the container into equally-sized segments whose
// length start at 1 and keeps increasing by factors of 2
for (size_t length(1); length < n; length <<= 1) {
// merge adjacent segments whose number is n / (length * 2)
Iterator left(first);
for (size_t counter(n / (length << 1)); counter; --counter) {
Iterator right(left + length), end(right + length);
merge(left, right, end, buffer);
left = end;
}
// if the number of remaining elements (n * 2 % length) is longer
// than a segment, merge the remaining elements
if ((n & ((length << 1) - 1)) > length)
merge(left, left + length, last, buffer);
}
delete[] buffer;
}
/// merges 2 sorted adjacent segments into a larger sorted segment
/**
* best-case = worst-case = O(n)
* @param l points to the left part
* @param r points to the right part, end of left part
* @param e points to end of right part
* @param b points at the buffer
*/
template <class Iterator>
void merge(Iterator l, Iterator r, const Iterator e, char b[]) {
// create 2 pointers to point at the buffer
auto p(reinterpret_cast<std::remove_reference_t<decltype(*l)>*>(b)), c(p);
// move the left part of the segment
for (Iterator t(l); r != t; ++t) *p++ = std::move(*t);
// while neither the buffer nor the right part has been exhausted
// move the smallest element of the two back to the container
while (e != r && c != p) *l++ = std::move(*r < *c ? *r++ : *c++);
// notice only one of the two following loops will be executed
// while the right part hasn't bee exhausted, move it back
while (e != r) *l++ = std::move(*r++);
// while the buffer hasn't bee exhausted, move it back
while (c != p) *l++ = std::move(*c++);
}
/// bottom-up merge sort which sorts elements in a non-decreasing order
/**
* @param first points to the first element
* @param n the number of elements
*/
template <class Iterator>
void non_recursive_merge_sort(const Iterator first, const size_t n) {
non_recursive_merge_sort(first, first + n, n);
}
/// bottom-up merge sort which sorts elements in a non-decreasing order
/**
* @param first points to the first element
* @param last points to 1-step past the last element
*/
template <class Iterator>
void non_recursive_merge_sort(const Iterator first, const Iterator last) {
non_recursive_merge_sort(first, last, last - first);
}
} // namespace sorting
using sorting::non_recursive_merge_sort;
int main(int argc, char** argv) {
int size;
std::cout << "Enter the number of elements : ";
std::cin >> size;
int* arr = new int[size];
for (int i = 0; i < size; ++i) {
std::cout << "arr[" << i << "] = ";
std::cin >> arr[i];
}
non_recursive_merge_sort(arr, size);
std::cout << "Sorted array\n";
for (int i = 0; i < size; ++i)
std::cout << "arr[" << i << "] = " << arr[i] << '\n';
delete[] arr;
return 0;
}