I have a question where we need to sort only the even indices of an array using divide and conquer. question

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. output 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;
    }
}

推荐答案

代码中存在多个问题:

  • 循环for (int i = 0; i < n1; i = i + 2) { arr[i] = arr1[i]; }是不正确的,因为您应该使用arr[l + i]而不是arr[i],但即使更正,它仍然是无用的:只需忽略偶数索引处的元素.
  • 还要注意,递归调用中的偶数位索引不一定是原始数组中的偶数位索引,因为计算int mid = si + (ei - si) / 2;可能会产生奇数值.
  • 您可以对长度为3和4的切片进行特殊情况的处理,但问题在于拆分左侧切片长度为奇数的array.
  • 使用具有包含上界的约定会导致复杂的代码,这些代码容易出现错误,调整为+1/-1.在C语言中,使用排除的上界更为简单.

以下是修改后的版本:

#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
}

输出:

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

C++相关问答推荐

从C函数调用asm函数时生成错误的BLX指令(STM32H753上的gcc)

当打印字符串时,为什么在c中没有使用常量限定符时我会收到警告?

如何在Visual Studio代码中关闭此函数名称显示功能?

在C中将通用字符名称转换为UTF-8

ARM64 ASIMD固有的加载uint8_t* 到uint16x8(x3)?

将uintptr_t添加到指针是否对称?

Clang警告称,`ffi_type`与`sizeof`不兼容

获取每个循环迭代结束时的当前时间

如何在GDB中查看MUSL的源代码

编译器如何处理具有更复杂值的枚举?

如何用C语言为CLI应用程序编写按键检测系统?

C将数组传递给函数以修改数组

理解bzip2的BZ2_解压缩函数中的状态重新分配

初始成员、公共初始序列、匿名联合和严格别名如何在C中交互?

用C++高效解析HTTP请求的方法

Linux/C:带有子进程的进程在添加waitid后都挂起

UpDown控制与预期相反

If语句默认为true

根据输入/输出将 C 编译过程分为预处理、编译、汇编和链接步骤

函数的typedef是标准 C 语法吗?它与函数指针的typedef有何不同?