【问题标题】:Sort ints from a txt file对 txt 文件中的整数进行排序
【发布时间】:2020-08-04 16:48:04
【问题描述】:

我需要按升序对文件中的整数进行排序并将它们打印到标准输出。我无法修改文件的结构。

txt 文件如下所示:

41
65
68
35
51

...(连续一个数字)

我的程序适用于小文件,但我必须使用 malloc 为较大的文件(如 300 万个数字)优化它,但不知道确切的位置和方式。我想在这方面寻求帮助。 (我是初学者)

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

#define BUFFER 100000

int sort(int size, int arr[])
{
    for (int i = 0; i < size - 1; i++)
    {
        for (int j = 0; j < size - i - 1; j++)
        {
            if (arr[j] > arr[j + 1]) 
            {
                int swap = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = swap;
            }
        }
    }
}

int main(int argc, char *argv[])
{
    char *filename = argv[1];

    char s[20];

    if (argc == 1)
    {
        fprintf(stderr, "Error! Input then name of a .txt file\n");
        exit(1);
    }

    FILE *fp = fopen(filename, "r");

    if (fp == NULL)
    {
        fprintf(stderr, "Error! Can't open %s\n", filename);
        exit(1);
    }
    int arr[BUFFER];

    int i = 0;
    int size = 0;

    while ((fgets(s, BUFFER, fp)) != NULL)
    {

        s[strlen(s) - 1] = '\0';

        arr[i] = atoi(s);
        ++i;
        ++size;
    }
    fclose(fp);
    sort(size, arr);

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

    return 0;
}

【问题讨论】:

  • 如果您要对 300 万个数字进行冒泡排序,您需要担心的不仅仅是如何存储它们,同时对它们进行排序。菜单上可能有更好的排序算法。无论如何,让arr 动态,理想地匹配项目的数量,如果你真的想变得花哨,随着你阅读越来越多的数字而变得广阔。请参阅有关动态内存管理的课程文本。
  • 使用基数排序而不是冒泡排序

标签: c file sorting malloc


【解决方案1】:

您的程序可能如下所示:

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

static int numcompar(const void *a, const void *b) {
    const int *x = a;
    const int *y = b;
    // it is tempting to return *x - *y; but undefined behavior lurks
    return *x < *y ? -1 : *x == *y ? 0 : 1;
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
         // TODO: handle error
         abort();
    }
    char *filename = argv[1];
    // open the file
    FILE *fp = fopen(filename, "r");
    if (fp == NULL) {
        abort();
    }

    // this will be our array
    // note realloc(NULL is equal to malloc()
    int *arr = NULL;
    size_t arrcnt = 0;

    // note - I am using fscanf for simplicity
    int temp = 0;
    while (fscanf(fp, "%d", &temp) == 1) {
        // note - reallocating the space each number for the next number
        void *tmp = realloc(arr, sizeof(*arr) * (arrcnt + 1));
        if (tmp == NULL) {
            free(arr);
            fclose(fp);
            abort();
        }
        arr = tmp;
        // finally assignment
        arr[arrcnt] = temp;
        arrcnt++;
    }

    fclose(fp);

    // writing sorting algorithms is boring
    qsort(arr, arrcnt, sizeof(*arr), numcompar);

    for (size_t i = 0; i < arrcnt; ++i) {
       printf("%d\n", arr[i]);
    }

    free(arr);
}

请注意,一次重新分配一个 int 效率低下 - realloc 通常是一个代价高昂的函数。下一步是分别保留数组大小和“已使用”(分配给)数组元素的数量,并以大于 1 的比率重新分配数组。有些声音更喜欢使用黄金比例数字在这种情况下。

【讨论】:

  • 重新分配数组 300 万次可能效率低下 :)
  • 哦,忘了改成argv[1]。它效率低下,但我通常相信无论如何都会过度分配的实现。
  • 实现过度分配,但不一定以几何方式。关于效率,只有仔细的基准测试才能说明问题,而且仅限于特定系统。
  • 1.625 已经足够接近黄金比例了 :)
【解决方案2】:

要从输入文件中读取未确定数量的条目,您可以在读取更多条目时使用realloc() 分配和重新分配数组。为了获得更好的性能,建议将分配的大小增加一个倍数而不是线性增加,尤其是一次一个条目。

您的排序例程不适用于大型数组:插入排序具有二次时间复杂度,因此对于 300 万个项目可能需要很长时间,除非它们已经排序。使用带有简单比较功能的qsort()

这是一个修改后的程序:

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

static int compare_int(const void *pa, const void *pb) {
    int a = *(const int *)pa;
    int b = *(const int *)pb;
    // return -1 if a < b, 0 if a == b and +1 if a > b
    return (a > b) - (a < b);
}

int main(int argc, char *argv[]) {
    if (argc == 1) {
        fprintf(stderr, "Error! Input then name of a .txt file\n");
        exit(1);
    }

    char *filename = argv[1];
    FILE *fp = fopen(filename, "r");
    if (fp == NULL) {
        fprintf(stderr, "Error! Can't open %s\n", filename);
        exit(1);
    }

    char buf[80];
    size_t n = 0, size = 0;
    int *array = NULL;

    /* read the numbers */
    while (fgets(buf, sizeof buf, fp)) {
        if (n == size) {
            /* increase size by at least 1.625 */
            size_t newsize = size + size / 2 + size / 8 + 32;
            int *newarray = realloc(array, newsize * sizeof(*array));
            if (newarray == NULL) {
                printf("cannot allocate space for %zu numbers\n", newsize);
                free(array);
                fclose(fp);
                exit(1);
            }
            array = newarray;
            size = newsize;
        }
        array[n++] = strtol(buf, NULL, 10);
    }
    fclose(fp);

    /* sort the array */
    qsort(array, n, sizeof(*array), compare_int);

    for (size_t i = 0; i < n; i++) {
       printf("%d\n", array[i]);
    }
    free(array);
    return 0;
}

【讨论】:

  • 谢谢,对我理解有很大帮助!
猜你喜欢
  • 2017-07-16
  • 2019-11-19
  • 2012-05-23
  • 2020-09-12
  • 2014-01-06
  • 2018-11-20
  • 1970-01-01
  • 2015-05-24
  • 2022-10-09
相关资源
最近更新 更多