问题
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