I have a question where we need to sort only the even indices of an array using divide and conquer.
What I tried was modifying the original mergeSort
function such that it will sort the even elements of subarrays. But in the merge sort function, we won't get every single element as we wouldn't know where to place if we get a single element, thus I made it so that base cases are when the subarray is of size 3 or 4. it will sort the subarray, but in a way that the even index in term of even index of main array only is sorted, thus line x.
The result I got was that the odd elements were untouched, but the even elements were not sorted correctly.
below is my code:
#include <stdio.h>
void merge(int arr[], int l, int m, int r);
void mergeSort(int arr[], int si, int ei);
int main() {
int num;
scanf("%d", &num);
int arr[num];
for (int i = 0; i < num; i++) {
scanf("%d", &arr[i]);
}
mergeSort(arr, 0, num - 1);
for (int i = 0; i < num; i++) {
printf("%d ", arr[i]);
}
return 0;
}
void mergeSort(int arr[], int si, int ei) {
if ((ei - si == 2) && (si % 2 == 0)) {
if (arr[si] > arr[si + 2]) {
int temp = arr[si];
arr[si] = arr[si + 2];
arr[si + 2] = arr[si];
}
} //base case 1
if ((ei - si == 3)) {
int x = (si % 2 == 0) ? si : si + 1; //line x
if (arr[x] > arr[x + 2]) {
int temp = arr[x];
arr[x] = arr[x + 2];
arr[x + 2] = arr[x];
} //base case 2
}
if (si < ei) {
int mid = si + (ei - si) / 2;
mergeSort(arr, si, mid); //calling merge sort on both the halves of array
mergeSort(arr, mid + 1, ei);
merge(arr, si, mid, ei);
}
}
void merge(int arr[], int l, int m, int r) {
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
int arr1[n1], arr2[n2];
for (i = 0; i < n1; i++)
arr1[i] = arr[l + i];
for (j = 0; j < n2; j++)
arr2[j] = arr[m + 1 + j];
for (int i = 0; i < n1; i = i + 2) {
arr[i] = arr1[i];
}
i = (n1 % 2 == 0) ? 0 : 1;
for (;i < n2; i = i + 2) {
arr[i+n1] = arr2[i];
}
i = 0;
j = (n1 % 2 == 0) ? 0 : 1, k = l;
while (i < n1) {
arr[k] = arr1[i];
k = k + 2;
i = i + 2;
}
while (j < n2) {
arr[k++] = arr2[j];
k = k + 2;
j = j + 2;
}
while (i < n1) {
arr[k] = arr1[i];
k = k + 2;
i = i + 2;
}
while (j < n2) {
arr[k] = arr2[j];
k = k + 2;
j = j + 2;
}
}
There are multiple problems in the code:
for (int i = 0; i < n1; i = i + 2) { arr[i] = arr1[i]; }
is incorrect because you should use arr[l + i]
instead of arr[i]
but even corrected, it would still be useless: just ignore the elements at even indices.int mid = si + (ei - si) / 2;
which may produce an odd value.+1
/-1
adjustments. It is simpler in C to use excluded upper bounds.Here is a modified version:
#include <stdio.h>
void merge(int arr[], int lo, int mid, int hi); // hi is excluded
void mergeSort(int arr[], int lo, int hi); // hi is excluded
int main(void) {
int num;
if (scanf("%d", &num) != 1 || num <= 0) {
return 1;
} else {
int arr[num];
for (int i = 0; i < num; i++) {
if (scanf("%d", &arr[i]) != 1)
return 1;
}
mergeSort(arr, 0, num);
for (int i = 0; i < num; i++) {
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
}
void mergeSort(int arr[], int lo, int hi) {
if (hi - lo > 2) {
// split the array with an even length for the left slice
int mid = lo + (hi - lo + 1) / 4 * 2;
mergeSort(arr, lo, mid);
mergeSort(arr, mid, hi);
merge(arr, lo, mid, hi);
}
}
void merge(int arr[], int lo, int mid, int hi) {
int i, j, k;
int n1 = (mid - lo) / 2;
int arr1[n1];
// save the elements at even index values in the left slice
for (i = 0, j = lo; i < n1; i++, j += 2) {
arr1[i] = arr[j];
}
// merge the slices, using only elements at even index values
for (i = 0, j = mid, k = lo; i < n1 && j < hi; k += 2) {
if (arr1[i] <= arr[j]) {
arr[k] = arr1[i];
i += 1;
} else {
arr[k] = arr[j];
j += 2;
}
}
// copy remaining elements from left slice
while (i < n1) {
arr[k] = arr1[i];
k += 2;
i += 1;
}
// remaining elements from right slice are already in their final places
}
Output:
chqrlie$ ./230902-sorteven
11
7 1 3 24 34 53 2 56 7 7 8
2 1 3 24 7 53 7 56 8 7 34