Issues writing merge sort with pointers in c [closed]

左心房为你撑大大i 提交于 2019-12-11 19:38:20

问题


I'm trying to write a merge sort program with pointers, and it is near to working good, but there is the problem that in the output there are some '0' instead of some of the numbers of the sorted array.

For testing the code you have to write a txt file prova.txt in which there is the array, one number for line. For example:

prova.txt:

4
7
2
9
1
45
87

When running the code, I expect the output

0: 1 
1: 2
2: 4 
3: 7 
4: 9 
5: 45 
6: 87

but I get

0: 1 
1: 0 
2: 0 
3: 0 
4: 0 
5: 0 
6: 2 

Moreover, are there any advice that you can give me for improving my code?

    #include <stdio.h>

int *merge(int left[], int right[], int n){
      int *ordinato, i=0, j=0;
      ordinato = malloc(sizeof(int)*n);
      while(i+j < n){
          if(left[i] < right[j]){
              *(ordinato+i+j) = left[i];
              i++;
          }else{
              *(ordinato+i+j) = right[j];
              j++;
          }
      }
      return ordinato;      
}

int *mergeSort(int *daOrd, int n){
      int k = 0, *left, *right, *ordinato;
      ordinato = malloc(sizeof(int)*n);
      left = malloc(sizeof(int)*(n/2));
      right = malloc(sizeof(int)*(n-(n/2)));
      if (n<2){
         ordinato = daOrd;     
      }else{
         for(k=0; k<n/2; k++)
             *(left + k) = *(daOrd + k);
         for(k=n/2; k<n; k++)
             *(right + k -(n/2)) = *(daOrd + k);

         left = mergeSort(left, n/2);
         right = mergeSort(right, n-(n/2));
         ordinato = merge(left, right, n);
      }      
      return ordinato;
}

main(){
     FILE *input;
     input = fopen("prova.txt", "r");
     if(!input) printf("Errore");

     int tot = 100000;//is the maximum n

     int *array;
     array = malloc(sizeof(int)*tot);
     int indice = 0;
     while(fscanf(input,"%d", (array + indice)) != EOF) indice++;

     int *ord = mergeSort(array, indice);

     int k;
     for(k=0; k<indice; k++) printf("%d: %d \n",k,  *(ord+k));


     getch();
     fclose(input);     
}

回答1:


First of all, your program only compiles/links when you ignore errors. Add #include <stdlib.h> for malloc, and remove the getch invocation as it's not needed for this example. Also, your main function is 1. implicitely returning int and 2. missing that return.

Your program fails in the merge step - you don't consider what happens when one of the arrays runs out before the other. The current progam just keeps on reading and grabs whatever is behind the left or right array, which is most often a zero.

What you want is to compare only while neither left or right is exhausted, and then just add the remaining values, like this:

#include <stdlib.h>
#include <stdio.h>

void merge(const int* left, const int* right, int* res, int n) {
    int i=0, j=0;
    while ((i < n/2) && (j < n - (n/2))) {
        if (left[i] < right[j]) {
            res[i+j] = left[i];
            i++;
        } else {
            res[i+j] = right[j];
            j++;
        }
    }
    while (i < n/2) {
        res[i+j] = left[i];
        i++;
    }
    while (j < n-(n/2)) {
        res[i+j] = right[j];
        j++;
    }

    return res;
}

void _mergeSort(int* values, int* aside, int n) {
    if (n < 2) {
        return;
    }
    _mergeSort(values, aside, n/2);
    _mergeSort(values+n/2, aside+n/2, n-(n/2));
    merge(values, values + n/2, aside, n);
    memcpy(values, aside, n * sizeof(int));
}

void mergeSort(int* values, int n) {
    int* aside = malloc(sizeof(int) * n);
    _mergeSort(values, aside, n);
    free(aside);
}

int main() {
    FILE *input;
    input = fopen("prova.txt", "r");
    if (!input) {
        fprintf(stderr, "Could not open file");
        return 1;
    }

    int maximum_n = 100000;
    int *array = malloc(sizeof(int)*maximum_n);
    int count;
    for (count = 0;count < maximum_n;count++) {
        if (fscanf(input, "%d", (array + count)) == EOF) {
            break;
        }
    }
    mergeSort(array, count);

    for(int k=0; k < count; k++) {
        printf("%d: %d \n", k, array[k]);
    }
    return 0;
}

Note that there is only one malloc call inside mergeSort now.




回答2:


Advice regarding optimization of memory used:
1. If you want to allocate memory at every step (although this is is not necessary) make sure you free all the memory used when the temporary buffers are no longer needed.
2. There is no need to create buffers at every step. You can allocate a buffer at the beginning and use pointers within that array at every step of the algorithm.

And the problem is with the merge function. When you were reaching the end of one of your arrays (right or left) you were pointing to memory that you did not allocate. There, it found the value 0 which was always smaller than the values in the array that was left. So, you have to stop merging when one of your buffers is copied completely in the result and then copy what is left of the other.

You should change it to this:

int *merge(int left[], int right[], int n){
  int *ordinato, i=0, j=0, k;
  ordinato = malloc(sizeof(int)*n);
  while((i<n/2) && (j<n-n/2)){
      if(left[i] < right[j]){
          *(ordinato+i+j) = left[i];
          i++;
      }else{
          *(ordinato+i+j) = right[j];
          j++;
      }
  }
  while(i!=n/2){
       *(ordinato+i+j) = left[i];
       i++; 
  }
  while(j!=n-n/2){
       *(ordinato+i+j) = right[j];
       j++; 
  }
  return ordinato;      
}


来源:https://stackoverflow.com/questions/17513582/issues-writing-merge-sort-with-pointers-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!