为什么我的merge函数输出一个没有排序的数组?

时间:2017-11-13 14:40:01

标签: c arrays

我构建了一个简单的函数,给定两个数组aa[5] = {5, 4, 9, -1, 3}bb[2] = {16, -11},在第三个数组cc[7]中对它们进行排序。

#include<stdio.h>
void merge(int *, int *, int *, int, int);

int main(){
    int aa[5] = {5, 4, 9, -1, 3};
    int bb[2] = {16, -11};
    int cc[7];

    merge(aa, bb, cc, 5, 2);

    return 0;
}

void merge(int *aa, int *bb, int *cc, int m, int n){

    int i = 0, j = 0, k = 0;

    while(i < m && j < n){
        if(aa[i] < bb[j])
            cc[k++] = aa[i++];    /*Smallest value should be assigned to cc*/
        else
            cc[k++] = bb[j++];
    }

    while(i < m)              /*Transfer the remaining part of longest array*/
        cc[k++] = aa[i++];


    while(j < n)
        cc[k++] = bb[j++];
}    

cc数组已正确填充,但未对这些值进行排序。而不是预期的cc = {-11, -1, 3, 4, 5, 9, 16},它返回cc = {5, 4, 9, -1, 3, 16, 11}。 就像分配cc[k++] = aa[i++]cc[k++] = bb[j++]不起作用一样,或者逻辑测试if aa[i] < bb[j]被忽略。

我假设运营商优先考虑问题,因此我用两种不同的标准进行了测试,没有差异:

gcc main.c -o main.x -Wall
gcc main.c -o main.x -Wall -std=c89

我多次检查代码,无法找到任何相关错误。在这一点上的任何建议将不胜感激。

4 个答案:

答案 0 :(得分:2)

你需要正确地思考你的算法。它没有明显的错误。问题是你的期望。明确这一点的一种方法是考虑如果一个数组是空的会发生什么。函数merge会改变任何顺序吗?它不会。事实上,如果两个元素ab来自相同的数组 - 无论是aa还是bb - 还是a在该数组中b之前,a也会出现在b中的cc之前。

该函数在排序数组上执行您所期望的操作,因此请确保它们之前已排序。您可以使用qsort

除此之外,当您使用指向阵列的指针时,您不想更改,请使用const限定符。

void merge(const int *aa, const int *bb, int *cc, int m, int n)

答案 1 :(得分:2)

你的实现中没有错误(至少我没有看到任何错误,imho)问题是你所做的合并不是针对两个排序的数组(它是针对几个排序的数字串)。如果你已经输入了两个已排序的数组,你就可以正确地排序结果了。

merge排序算法首先将输入拆分为排序数组的两部分。这是通过在检测到元素不按顺序时切换数组来完成的(它不是最后一个数字)你得到第一个有序集来填充一个数组(初始列表的第一个a元素恰好是按顺序放入数组A,然后将第二组元素放入数组B。这会产生两个可以合并的数组(因为它们已经按顺序排列)并且这个合并使得结果是一个更大的数组(这个事实保证算法会在每次传递时产生越来越大的数组,并保证它会在某些传递中完成。你不需要按数组操作数组,因为在每次传递时列表的数量较少在你的情况下,减去更多的大量已排序元素:

1st pass input (the switching points are where the input 
is not in order, you don't see them, but you switch arrays 
when the next input number is less than the last input one):
  {5}, {4, 9}, {-1, 3}, {16}, {-11}  (See note 2)
after first split:
  {5}, {-1, 3}, {-11}
  {4, 9}, {16}
after first merge result:
  {4, 5, 9}, {-1, 3, 16}, {-11}
after second pass split:
  {4, 5, 9}, {-11}
  {-1, 3, 16}
  result:
  {-1, 3, 4, 5, 9, 16}, {-11}
third pass split:
  {-1, 3, 4, 5, 9, 16}
  {-11}
third pass result:
  {-11, -1, 3, 4, 5, 9, 16}

当你没有得到两串有序流(你没有切换数组)时算法结束,你不能再划分数据流。

您的实现只执行一次合并排序算法,您需要完全实现它才能获得排序输出。该算法被设计成当输入不可能放入数组时可以进行多次传递(正如您所做的那样,因此它没有完全说明数组的事情)。如果您从文件中读取它,您会更好地看到这个想法。

为大量数据排序程序使用合并算法,首先是quicksort'的数据束,所以我们从数据桶中开始,这些数据不能同时放在一个数组中。

注2

数字16之后的数字3应该与之前的数量相同,使它成为{-1, 3, 16},但是因为它们最初位于不同的数组中,而我还没有发现任何方法将它们放入一个分成这种排列的列表中,我强制桶就像16 < 3一样,在分割输入时人为地切换数组。这可能会影响额外传递数据的最终结果,但不会影响最终结果,这是一个排序的数字列表。我是故意这样做的,这不是一个错误(它与解释算法是如何工作无关)无论如何,算法切换列表(我不喜欢在描述这个算法时使用数组,因为通常合并算法不要对数组进行操作,因为数组是随机访问,而列表必须通过一些迭代器从头到尾访问,这是合并排序算法的要求)第一次拆分后{4, 9}, {16}也会发生同样的情况。想象一下比较的结果是显示的,因为在第一次合并之后一切都是正确的。

答案 2 :(得分:1)

如果您的程序运行正常,则可以通过比较对O(N)进行排序。由于@Karzes在评论中不可能并提及,您的程序仅适用于已排序的子数组。因此,如果要为合并排序实现合并功能,则应该尝试使用这两个输入的程序:

int aa[5] = {-1, 3, 4, 5, 9};
int bb[2] = {-11, 16};

答案 3 :(得分:0)

不是最有效的原因,因为它的崩溃......

    #include<stdio.h>
    void merge(int *, int *, int *, int, int);
    void sortarray(int array[], int arraySize)
    {
        int c,d,temp;

        for (c = 0 ; c < arraySize-1; c++)
      {
        for (d = 0 ; d < arraySize - c - 1; d++)
        {
          if (array[d] > array[d+1]) /* For decreasing order use < */
          {
            temp       = array[d];
            array[d]   = array[d+1];
            array[d+1] = temp;
          }
        }
      }
    }
    int main(){
        int aa[5] = {5, 4, 9, -1, 3};
        int bb[2] = {16, -11};
        int cc[7];
        int i;
        sortarray(aa,sizeof(aa)/sizeof(aa[0]));

        sortarray(bb,sizeof(bb)/sizeof(bb[0]));

        merge(aa, bb, cc, 5, 2);

         for(i=0;i<sizeof(cc)/sizeof(cc[0]);i++)
         {
            printf("%d,",cc[i]);
         }
        return 0;
    }

    void merge(int *aa, int *bb, int *cc, int m, int n){

        int i = 0, j = 0, k = 0;

        while(i < m && j < n)
        {
            if(aa[i] < bb[j])
                cc[k++] = aa[i++];    /*Smallest value should be assigned to cc*/
            else
                cc[k++] = bb[j++];
        }

        while(i < m)              /*Transfer the remaining part of longest array*/
            cc[k++] = aa[i++];


        while(j < n)
            cc[k++] = bb[j++];
    }