【问题标题】:Merge sorting a struct合并排序结构
【发布时间】:2015-05-16 09:17:17
【问题描述】:
#include<stdio.h>
#include<stdlib.h>
typedef struct points{
        float axis[2];
        int id;
}Points;

typedef enum{
        SortById,
        SortByXAxis
}SortType;

Points* fill_Array(char* filename, int* length);
void Print_set(Points* set, int number_of_points);
void mergesort(Points* set, int low, int high, int number_of_points,SortType sort);
void merge(Points* set, int low, int middle, int high, int number_of_points,SortType sort);

int main(int argc, char* argv[])
{
    int length;
    Points *array;
    array=fill_Array(argv[1],&length);
    Print_set(array,length);
    printf("\n\n");
    mergesort(array,0,length,length,SortById);
    Print_set(array,length);
    return 0;
}
Points* fill_Array(char* filename,int* length)
{
    int i;
    Points* array;
    FILE* file=fopen(filename,"r");

    if(file == NULL)
    {
        return NULL;
    }

    fscanf(file,"%d",length);
    array=malloc(sizeof(Points)* *length);

    for(i = 0; i < *length; i++)
    {
        fscanf(file,"%d %f %f", &(array+i)->id,&(array+i)->axis[0],&(array+i)->axis[1]);
    }
    fclose(file);

    return array;
}

void Print_set(Points *set, int number_of_points)
{
    int i;

    for(i = 0; i < number_of_points; i++)
    {
        printf("%d %f %f\n",(set+i)->id,(set+i)->axis[0],(set+i)->axis[1]);
    }
}

void mergesort(Points* set,int low,int high,int number_of_points, SortType sort)
{
    int mid1;

    if((high-low)>=1)
    {
        mid1 = (low+high)/2;

        mergesort(set, low, mid1, number_of_points, sort);
        mergesort(set, mid1+1, high, number_of_points, sort);
        merge(set, low, mid1, high, number_of_points, sort);

    }

}
void merge(Points* set, int low, int middle, int high, int number_of_points, SortType sort)
{
        int leftIndex=low;
        int rightIndex=middle;
        int combinedIndex = low;
        Points tempArray[number_of_points];
        int i;

        while(leftIndex <= middle && rightIndex<= high)
        {
            if(set[leftIndex].id <= set[rightIndex].id)
            {
                tempArray[combinedIndex++] = set[leftIndex++];
            }
            else
                tempArray[combinedIndex++] = set[rightIndex++];
        }

        if(leftIndex == middle+1)
        {
            while(rightIndex <= high)
            {
                tempArray[combinedIndex++] = set[rightIndex++];
            }
        }
        else
        {
            while(leftIndex <= middle)
            {
                tempArray[combinedIndex++] = set[leftIndex++];
            }
        }

        for( i = low; i < high; i++)
        {
            set[i] = tempArray[i];
        }
}

我正在尝试使用自定义合并排序功能对输入文件执行合并排序。然而,合并排序函数不起作用并在下面打印出来,第一个块是打印出来的实际输入文件,以确保 fscanf 正确读取所有内容,第二个块是运行合并函数后的打印。这些函数复制了一些值,也没有对它们进行排序,我在代码中找不到错误。请注意,枚举将用于对 id 或第一个浮点值进行排序,我只是想让合并排序工作,然后再使用它对 id 或那些值进行排序。

1 13.000000 7.000000
13 14.000000 6.000000
95 7.000000 13.000000
39 0.000000 20.000000
78 10.000000 10.000000
68 3.000000 17.000000
32 6.000000 14.000000
10 19.000000 1.000000
0 18.000000 2.000000
45 17.000000 3.000000
92 4.000000 16.000000
29 5.000000 15.000000
85 8.000000 12.000000
79 15.000000 5.000000
12 16.000000 4.000000
32 1.000000 19.000000
77 9.000000 11.000000
52 12.000000 8.000000
80 11.000000 9.000000
31 2.000000 18.000000


1 13.000000 7.000000
13 14.000000 6.000000
68 3.000000 17.000000
0 18.000000 2.000000
10 19.000000 1.000000
0 18.000000 2.000000
0 18.000000 2.000000
92 4.000000 16.000000
92 4.000000 16.000000
29 5.000000 15.000000
32 1.000000 19.000000
52 12.000000 8.000000
77 9.000000 11.000000
79 15.000000 5.000000
12 16.000000 4.000000
32 1.000000 19.000000
32 1.000000 19.000000
80 11.000000 9.000000
95 7.000000 13.000000
95 7.000000 13.000000

【问题讨论】:

  • 你让自己非常很难受。 Mergesort 分区漂亮地 适合C 语言,部分原因在于指针算术的好处。如果操作正确,&lt;= 运算符需要从不出现在算法中,从而非常更容易理解。 See example live.

标签: c sorting mergesort


【解决方案1】:

您似乎对边界索引的含义感到困惑。考虑对函数 mergesort() 的初始调用:

    mergesort(array,0,length,length,SortById);

您为参数highnumber_of_points 传递相同的值,这很好,但这意味着high 表示排序范围索引的排他性 上限。然而,mergesort() 实现似乎适合参数 high 来表示 inclusive 界限。

您的merge() 函数继续混淆,这可能是这里的主要罪魁祸首。通过将传递的中点值作为右子数组的起始索引,似乎期望中点作为左子数组的 exclusive 上限,但当前mergesort() 实现通过 inclusive 上限。另一方面,只有当middle 是子数组的包含上限时,merge() 执行的某些索引比较才适用。

简而言之,你有一个混乱。算法的基本轮廓看起来不错,但是您需要决定(并自己记录)您的函数参数代表什么,并与您的实现细节相协调。如果我是你,我会对所有区间采用半开表示,这样下限总是包含的,而上限总是排除的。除其他外,这具有以下优点:每个中点值都可以同样正确地解释为其子数组左半部分的(不包括)上限或右半部分的(包括)下限。

【讨论】:

  • 因此,对于初学者来说,最好将初始合并排序调用更改为
  • 合并排序(array,0,length-1,length,SortById)
  • @BrandonTomblinson 他建议相反,保留最初的归并排序调用并更改代码以从所有循环中排除上限,即根据需要将 &lt;= 更改为 &lt;。并在合并排序中检查(high-low) &gt; 1
  • @BrandonTomblinson,user3386109 正确描述了我的推荐。不过,最后,您可以选择任何表示区间界限的机制——甚至是不同函数中的不同机制——只要您的代码与该选择一致。
  • @BrandonTomblinson,一旦你确定了一个表示,你需要逐行检查你的代码,以确保它在任何地方都与那个选择一致。正如 user3386109 所观察到的,您还没有成功地做到这一点。
【解决方案2】:
    void mergesort(Points* set,int low,int high,int number_of_points, SortType sort)
    {
        int mid1;

        if((high-low)>1)
        {
            mid1 = (low+high)/2;

            mergesort(set, low, mid1, number_of_points, sort);
            mergesort(set, mid1, high, number_of_points, sort);
            merge(set, low, mid1, high, number_of_points, sort);

        }

    }
    void merge(Points* set, int low, int middle, int high, int number_of_points, SortType sort)
    {
            int leftIndex=low;
            int rightIndex=middle;
            int combinedIndex = low;
            Points tempArray[number_of_points];
            int i;

            while(leftIndex <= middle && rightIndex < high)
            {
                if(set[leftIndex].id <= set[rightIndex].id)
                {
                    tempArray[combinedIndex++] = set[leftIndex++];
                }
                else
                    tempArray[combinedIndex++] = set[rightIndex++];
            }

            if(leftIndex == middle+1)
            {
                while(rightIndex < high)
                {
                    tempArray[combinedIndex++] = set[rightIndex++];
                }
            }
            else
            {
                while(leftIndex < middle)
                {
                    tempArray[combinedIndex++] = set[leftIndex++];
                }
            }

            for( i = low; i < high; i++)
            {
                set[i] = tempArray[i];
            }
    }

0 18.000000 2.000000
1 13.000000 7.000000
10 19.000000 1.000000
0 18.000000 2.000000
12 16.000000 4.000000
13 14.000000 6.000000
29 5.000000 15.000000
31 2.000000 18.000000
32 6.000000 14.000000
32 1.000000 19.000000
39 0.000000 20.000000
39 0.000000 20.000000
52 12.000000 8.000000
31 2.000000 18.000000
68 3.000000 17.000000
77 9.000000 11.000000
78 10.000000 10.000000
12 16.000000 4.000000
79 15.000000 5.000000
85 8.000000 12.000000

【讨论】:

  • 我在该代码中看到了很多&lt;=,并确认其中至少有一个是错误的。您需要正确设置所有范围。
  • 那么剩下的所有
  • 我已经更改了一些
  • 此时您只是在猜测。花一些时间来分析代码,在纸上写出一些例子,检查并仔细检查所有的范围,等等。你已经得到了正确的代码的一般结构,但是你面临着可怕的--每个 C 程序员都面临的一个问题。你需要学习如何处理它,如果我只是给你正确的代码,你就学不会。
  • 所以基本上其他一切都是正确的,我只是有一个上限超过 1,但这并不能解释为什么即使我有重复,它也没有对所有东西进行排序
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-27
  • 1970-01-01
相关资源
最近更新 更多