在C中合并排序会产生错误的结果

时间:2017-02-09 17:54:49

标签: c mergesort

我写了一个合并排序程序,但结果不对。

我已经看过这样的其他节目,但他们不能帮我解决问题。我认为问题出在merge函数中。

#include <stdio.h>
#include "stdafx.h"           

#define Size 5

//this is the array
int arr[Size] = { 5, 4, 3, 2, 1 };
int sr[10];
void mergesort(int a[], int start, int end, int size);
void merge(int a[], int start, int end, int size);

int main(void) {
    mergesort(arr, 0, 4, 5);
    for (int i = 0; i < Size; i++) {
        printf_s("%i", sr[i]);
    }
    printf_s("\n");
    return 0;        
}

void mergesort(int a[], int start, int end, int size) {
    if (size < 2)
        return;

    int s = size / 2;
    mergesort(a, start, (start + end) / 2, s);
    mergesort(a, (start + end) / 2, end, s);
    merge( a,  start,  end,  s);
}

void merge(int a[], int start, int end, int size) {
    int left = start;
    int right = ((start + end) / 2) + 1;

    for (int i = 0; i < size; i++) {
        if (left < (start + end)/2) {
            if (right >= end) {
                sr[i] = arr[left];
                left++;
            } else
            if (arr[left] < arr[right]) {
                sr[i] = arr[left];
                left++;
            } else {
                sr[i] = arr[right];
                right++;
            }
        } else {
            sr[i] = arr[right];
            right++;
        }
    }
}

2 个答案:

答案 0 :(得分:1)

(1) printf_s("%i",sr[i]);应为printf_s("%i ", arr[i]);

(2)

mergesort(a, start, (start + end) / 2, s);//E.g index:{0,1,2,3,4}, start:0, (start + end) / 2 : 2, s: 2, but 0(start),1,2(new end), this length is 3, not 2
mergesort(a, (start + end) / 2, end, s);//Duplicate start position and length should be size - s. E.g size:5, s:2, rest size is 3, not 2.
merge( a,  start,  end,  s);//s should be size

应该像

mergesort(a, start, start + s - 1, s);
mergesort(a, start + s, end, size - s);
merge(a, start, end, size);

(3) 根据(2)改变
int right = ((start + end) / 2) +1;更改为int right = start + size / 2;

(4) 添加int sr[size]; //避免使用全局变量。最好使用malloc。 E.g int *sr = malloc(size*sizeof(int));...free(sr);

(5)

if (left < (start+end)/2)
{
    if (right >= end)

应该是

if (left < start + size / 2)
{
    if (right > end){//Should be >, not >=

(6)回写arr表格sr是必要的

整个代码:

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

void mergesort(int a[], int start, int end, int size);
void merge(int a[], int start, int end, int size);

int main(void){
    int arr[] = {5,4,3,2,1};
    int size = sizeof(arr)/sizeof(*arr);

    mergesort(arr, 0, size - 1, size);
    for (int i = 0; i < size; i++){
        printf_s("%i ", arr[i]);
    }
    printf_s("\n");
    return 0;
}

void mergesort(int a[], int start, int end, int size){
    if (size < 2)
        return;

    int s = size / 2;
    mergesort(a, start, start + s - 1, s);
    mergesort(a, start + s, end, size - s);
    merge(a, start, end, size);
}
void merge(int a[], int start, int end, int size){
    int left = start;
    int right = start + size / 2;
    int right_start = right;

    int *sr = (int*)malloc(size*sizeof(*sr));//Cast(int*) is not necessary in C.

    for (int i = 0; i < size; i++){
        if (left < right_start){
            if (right > end){
               sr[i] = a[left++];
            } else if (a[left] < a[right]) {
                sr[i] = a[left++];
            } else {
                sr[i] = a[right++];
            }
        } else {
            sr[i] = a[right++];
        }
    }
    for(int i = 0; i < size; ++i)//write back.
        a[start + i] = sr[i];
    free(sr);
}

答案 1 :(得分:1)

由于多种原因,您的代码无效:

  • mergesort将范围拆分为大小size / 2的两半,如果size不均匀则不正确。

  • mergesort的参数不正确,只需要指针和大小。

  • merge函数从全局数组arr获取值而不是参数数组,并将值存储到全局临时数组sr中,但不会将其复制回a数组。

以下是更正后的简化版本:

#include <stdio.h>

void mergesort(int a[], int size);

int main(void) {
    int arr[] = { 5, 4, 3, 2, 1 };
    int size = sizeof(arr) / sizeof(arr[0]);

    mergesort(arr, size);
    for (int i = 0; i < size; i++) {
        printf_s("%i ", arr[i]);
    }
    printf_s("\n");
    return 0;        
}

void merge(int a[], int mid, int size) {
    int sr[mid];  // temporary array for the left part

    if (a[mid - 1] <= a[mid]) { // quick check for sorted case
        return;
    }
    for (int i = 0; i < mid; i++) {  // save left part
        sr[i] = a[i];
    }
    // merge into array `a`.    
    for (int i = 0, left = 0, right = mid; left < mid; i++) {
        if (right == size || sr[left] <= a[right]) {
            a[i] = sr[left++];
        } else {
            a[i] = a[right++];
        }
    }
}

void mergesort(int a[], int size) {
    if (size >= 2) {
        int mid = (size + 1) / 2; // make left part no smaller than right part
        mergesort(a, mid);
        mergesort(a + mid, size - mid);
        merge(a, mid, size);
    }
}