Your code does not compile. To pass with g++ -Wall -Werror
I needed to add the following lines to the start of the file:
#include <iostream>
using namespace std;
Your code only reads from array a
and writes to array b
. Nowhere the "sorted" contents from b
are copied back to a
.
My guess your intention is that that should happen in merge()
, i.e. by adding to the end of the function:
for(int i=low; i<high; i++)
a[i] = b[i];
Furthermore there is an off-by-one error in main()
: mergesort()
expects high
to be the total number of items to be sorted and not the index of the highest item in the array:
mergesort(a,b,0,num);
With those changes the code compiles and prints out the correct result
-78 10 12 23 24 41 43 45 56 90 98 123
EDIT
Passing the array b
around is also unnecessary as it is in reality only needed to perform the merge. Hence the code can be updated to read:
void merge(int*,int,int,int,int);
//mergesort
void mergesort(int *a, int low, int high)
{
...
mergesort(a,low,pivot1);
mergesort(a,pivot1,pivot2);
mergesort(a,pivot2,high);
merge(a,low,pivot1,pivot2,high);
}
//merge
void merge(int *a, int low, int pivot1, int pivot2, int high)
{
int b[high];
...
}
int main()
{
int a[] = {12,10,43,23,-78,45,123,56,98,41,90,24};
int num = sizeof(a) / sizeof(*a);
mergesort(a,0,num);
for(int i=0; i<num; i++)
cout<<a[i]<<" ";
cout<<endl;
}
EDIT 2
The memory consumption of merge()
can be reduced, because in each invocation it only sorts the slice a[low..high-1]
. Hence the code can be updated to read:
//merge
void merge(int *a, int low, int pivot1, int pivot2, int high)
{
int b[high - low]; // slice a[low..high - 1] to be sorted
int i = 0; // running index in b[]
...
// replace slice a[low.. high - 1] with sorted result
for (i = low; i < high; i++)
a[i] = b[i - low];
}
BONUS
Complete code simplified and more readable:
#include <iostream>
using namespace std;
static void merge(int *a,
const unsigned int low, const unsigned int pivot1,
const unsigned int pivot2, const unsigned int high);
// mergesort (recursive)
static void mergesort(int *a, const unsigned int low, const unsigned int high)
{
const unsigned int slice = high - low;
// terminate recursion
if (slice < 2)
return;
if (slice < 3) {
// can't recurse for slice of length 2; just sort using 2 partitions
merge(a, low, low, low + 1, high);
return;
}
const unsigned int third = slice / 3;
const unsigned int pivot1 = low + third;
const unsigned int pivot2 = high - third;
// recurse
mergesort(a, low, pivot1);
mergesort(a, pivot1, pivot2);
mergesort(a, pivot2, high);
// merge
merge(a, low, pivot1, pivot2, high);
}
// merge
static void merge(int *a,
const unsigned int low, const unsigned int pivot1,
const unsigned int pivot2, const unsigned int high)
{
int sorted[high - low]; // slice a[low..high - 1] to be sorted
int *store = sorted; // running pointer into sorted[]
unsigned int partition1 = low; // running index a[low .. pivot1 - 1]
unsigned int partition2 = pivot1; // running index a[pivot1 .. pivot2 - 1]
unsigned int partition3 = pivot2; // running index a[pivot2 .. high - 1]
while ((partition1 < pivot1) &&
(partition2 < pivot2) &&
(partition3 < high)) {
if (a[partition1] < a[partition2])
*store++ = a[partition1] < a[partition3] ? a[partition1++] : a[partition3++];
else
*store++ = a[partition2] < a[partition3] ? a[partition2++] : a[partition3++];
}
while ((partition1 < pivot1) &&
(partition2 < pivot2)) {
*store++ = a[partition1] < a[partition2] ? a[partition1++] : a[partition2++];
}
while ((partition2 < pivot2) &&
(partition3 < high)) {
*store++ = a[partition2] < a[partition3] ? a[partition2++] : a[partition3++];
}
while ((partition1 < pivot1) &&
(partition3 < high)) {
*store++ = a[partition1] < a[partition3] ? a[partition1++] : a[partition3++];
}
while (partition1 < pivot1)
*store++ = a[partition1++];
while (partition2 < pivot2)
*store++ = a[partition2++];
while (partition3 < high)
*store++ = a[partition3++];
// replace slice a[low.. high - 1] with sorted result
for (unsigned int i = low; i < high; i++)
a[i] = sorted[i - low];
}
int main()
{
int a[] = {12,10,43,23,-78,45,123,56,98,41,90,24};
// int a[] = {-78,10,12,23,24,41,43,45,56,90,98,123};
// int a[] = { 4, 3, 2, 1, 0};
// int a[] = { 3, 2, 1, 0};
// int a[] = { 2, 1, 0};
// int a[] = { 1, 0};
// int a[] = { 0};
const unsigned int num = sizeof(a) / sizeof(*a);
mergesort(a, 0, num);
for (unsigned int i = 0; i < num; i++)
cout << a[i] <<" ";
cout << endl;
}
BONUS 2
Reimplemented merge()
function:
static void merge(int *a,
const unsigned int low, const unsigned int pivot1,
const unsigned int pivot2, const unsigned int high)
{
unsigned int slice = high - low;
int sorted[slice]; // slice a[low..high - 1] to be sorted
unsigned int store = 0; // running pointer into sorted[]
unsigned int partition1 = low; // running index a[low .. pivot1 - 1]
unsigned int partition2 = pivot1; // running index a[pivot1 .. pivot2 - 1]
unsigned int partition3 = pivot2; // running index a[pivot2 .. high - 1]
while (store < slice) {
int next;
if (partition1 < pivot1) {
// partition1 is not exhausted yet
next = a[partition1];
if (partition2 < pivot2) {
// partitions 1 & 2 are not exhausted yet
if (partition3 < high) {
// all partitions are not exhausted yet
if (next < a[partition2]) {
if (a[partition2] < a[partition3])
partition1++; // p1 < p2 < p3
else if (next < a[partition3])
partition1++; // p1 < (p3 || p2)
else
next = a[partition3++]; // p3 <= p1 < p2
} else if (a[partition2] < a[partition3])
next = a[partition2++]; // p2 < p3 <= p1
else
next = a[partition3++]; // p3 <= p2 <= p1
} else if (next < a[partition2])
partition1++; // p1 < p2 [p3]
else
next = a[partition2++]; // p2 <= p1 [p3]
} else if (partition3 < high) {
// partition2 is exhausted, compare p1 & p3 only
if (next < a[partition3])
partition1++; // p1 < p3 [p2]
else
next = a[partition3++]; // p3 <= p1 [p2]
} else
// partitions 2 & 3 are exhausted, copy from p1
partition1++; // p1 [p2, p3]
} else if (partition2 < pivot2) {
// partition1 is exhausted, compare p2 & p3 only
next = a[partition2];
if (partition3 < high) {
// partitions 2 & 3 are not exhausted
if (next < a[partition3])
partition2++; // p2 < p3 [p1]
else
next = a[partition3++]; // p3 <= p2 [p1]
} else
// partitions 1 & 3 are exhausted, copy from p2
partition2++; // p2 [p1, p3]
} else {
// partitions 1 & 2 are exhausted, copy from p3
next = a[partition3++]; // p3 [p1, p2]
}
// store smallest entry
sorted[store++] = next;
}
// replace slice a[low.. high - 1] with sorted result
for (unsigned int i = low; i < high; i++)
a[i] = sorted[i - low];
}