【问题标题】:How to correctly call this merge sort function?如何正确调用此归并排序函数?
【发布时间】:2020-01-11 02:33:31
【问题描述】:

我正在尝试实现这个合并排序函数来对 c 中的结构数组进行排序。当我调用该函数时,我的程序提前退出,我认为这是因为我正在排序的数组是 row_t* 类型并且需要是 row_t**,我不确定如何正确地分配我的数据以实现这一点。

//I have copied relevant bits of my code below

//this is the struct i am trying to sort by the value S
typedef struct 
{ 
    double rho, u, v, x, y, flux_u, flux_v, S;
} row_t;

//This is where i allocate the array i want to sort
row_t* linear_row_arr = (row_t*)malloc(sizeof(row_t)*100);

//this is where i try to call the function,
//linear_row_arr is an array of row_t, with 100 elements
merge_sort((void**)linear_row_arr, 99, row_array_s_comp);

//This is the function i am trying to call.
void merge(void** array, int n, int mid, int cmp(const void*, const void*))
{
    // (0) need extra space for merging
    void** tmp = malloc(n * sizeof(void*));
    void** left = array;
    void** right = array + mid;
    int i = 0;
    int j = 0;
    int left_size = mid;
    int right_size = n - mid;
    // (1) perform the merge
    for (int k = 0; k < n; k++) {
        if (j == right_size)
            tmp[k] = left[i++];
        else if (i == left_size)
            tmp[k] = right[j++];
        else if (cmp(left[i], right[j]) < 1)
            tmp[k] = left[i++];
        else
            tmp[k] = right[j++];
    }
    // (2) copy the merged array
    for (int i = 0; i < n; i++) {
        array[i] = tmp[i];
    }
    // (3) clean up
    free(tmp);
}

void merge_sort(void** array, int n, int cmp(const void*, const void*))
{
    if (n > 1) {
        int mid = n / 2;
        merge_sort(array, mid, cmp);
        merge_sort(array + mid, n - mid, cmp);
        merge(array, n, mid, cmp);
    }
}

int row_array_s_comp(const void* a, const void* b)
{
    row_t* ra = (row_t*)a;
    row_t* rb = (row_t*)b;
    // with int data we can just subtract to get the right behaviour
    return ra->S - rb->S;
}



当我运行此代码时,代码会提前退出且没有错误消息。

编辑:

我尝试使用@Ian Abbott 的解决方案,但它在我的比较函数中产生了段错误。难道是我使用 malloc 而不是 calloc 来为我的数据分配内存?

// This is my function call
//100 elements of row_t*
merge_sort(linear_row_arr, 100, sizeof(row_t*), row_array_s_comp);


编辑 2: 谢谢伊恩,我已经修复了我的错误,现在有一个方便的合并排序功能可供我使用。我对您的答案投了赞成票,但它说它将公开显示,因为我的代表少于 15 个。如果有人需要,这里是我使用的最终比较函数是


int row_array_s_comp(const void* a, const void* b)
{
    row_t* ra = (row_t*)a;
    row_t* rb = (row_t*)b;
    // with double data we can just subtract to get the right behaviour
    return (ra->S > rb->S) - (ra->S < ra->S);
}


and i called the function with

merge_sort(linear_row_arr, 100, sizeof(row_t), row_array_s_comp);

如果有人觉得这个有用,请随时支持@Ians Abotts 的回答,因为它是正确的,但我不能。 再次感谢您的宝贵时间!

【问题讨论】:

  • 您将指向row_t 数组的第一个元素的指针传递给需要指向void * 数组的第一个元素的指针。难怪它不起作用。我建议将 merge_sort 参数更改为类似于标准库 qsort 函数,将元素大小传递给函数并将要排序的元素视为字节数组(使用 memcpy 复制它们)。跨度>
  • 感谢您的回复。你能指出我从哪里开始吗?我没有编写此合并排序,并且对如何实现您上面所说的没有信心。
  • 顺便说一下,您的 row_array_s_comp 函数没有正确按 S 值排序。它减去double 并将结果隐式转换为int。如果绝对差值小于 1,则函数将返回 0。我建议使用 return (ra-&gt;S &gt; rb-&gt;S) - (ra-&gt;S &lt; ra-&gt;S);。这将返回 -1、0 或 1。
  • 我担心您将比较函数的返回类型更改为double,因为这与我的merge_sort 函数中的比较函数指针不匹配。比较函数返回int 更为常规。
  • 啊,我返回了实际差异,然后决定在比较函数之外哪个更大,我现在将我的代码更新为约定,然后更新帖子。

标签: c sorting struct


【解决方案1】:

这是一个数组自顶向下合并排序的简单实现,使用类似于qsort 的参数。时间复杂度为 O(n log n)。它使用与输入数组大小相似的临时存储。

/* Subroutine to merge two input arrays into an output array. */
static void merge(void *out, const void *pa, size_t na,
                  const void *pb, size_t nb, size_t elemsize,
                  int (*cmp)(const void *, const void *))
{
    while (na != 0 || nb != 0) {
        if (na == 0 || nb != 0 && cmp(pa, pb) > 0) {
            memcpy(out, pb, elemsize);
            pb = (const char *)pb + elemsize;
            nb--;
        } else {
            memcpy(out, pa, elemsize);
            pa = (const char *)pa + elemsize;
            na--;
        }
        out = (char *)out + elemsize;
    }
}

/* Merge sort an array. */
void merge_sort(void *base, size_t nmemb, size_t elemsize,
                int (*cmp)(const void *, const void *))
{
    size_t nbottom;
    size_t ntop;
    void *midp;
    void *bottom;
    void *top;

    if (nmemb <= 1) {
        /* Too small to sort. */
        return;
    }
    /* Sort the bottom half and the top half. */
    nbottom = nmemb / 2;
    ntop = nmemb - nbottom;
    midp = (char *)base + (nbottom * elemsize);
    merge_sort(base, nbottom, elemsize, cmp);
    merge_sort(midp, ntop, elemsize, cmp);
    /* Make temporary copies of the sorted bottom half and top half. */
    bottom = malloc(nbottom * elemsize);
    top = malloc(ntop * elemsize);
    memcpy(bottom, base, nbottom * elemsize);
    memcpy(top, midp, ntop * elemsize);
    /* Do a sorted merge of the copies into the original. */
    merge(base, bottom, nbottom, top, ntop, elemsize, cmp);
    /* Free temporary copies. */
    free(bottom);
    free(top);
}

【讨论】:

  • 谢谢您,我尝试实现此功能,但我的比较功能再次出现段错误,我将编辑我在帖子中尝试的内容。
  • @eyedea_ability 我认为这是因为您使用了sizeof(row_t*) 作为elemsize 参数。应该是sizeof(row_t)sizeof(linear_row_arr[0])
猜你喜欢
  • 1970-01-01
  • 2021-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多