【问题标题】:Find 10 longest words in a file查找文件中最长的 10 个单词
【发布时间】:2018-09-28 03:21:42
【问题描述】:

致力于打印文件中最长的 10 个单词(每行一个单词)。单词可以按任何顺序打印,如果有多个单词并列第 10 长,我们可以决定要做什么。以下打印前 1 个,感谢任何构建循环的建议,该循环可以迭代并打印下一个 9。这里的假设是,文件中最长的单词可以是 200 个字母和 60 个空格。我希望排除这两个假设并使其更加动态地工作。虽然以下是 C 喜欢听到任何用 C++ 编写的,但需要避免使用 STL。

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

#define MAX_WORD_LENGTH 200

int main () {
FILE *fp = fopen("words.txt","r");
char str[60];
char *largest = (char*) malloc (MAX_WORD_LENGTH);
int smallest_len = MAX_WORD_LENGTH, largest_len = 0;

while (fgets (str, 60, fp) != NULL) 
{
    char *temp = strtok(str, "\n");
    while (temp != NULL) 
    {
        if (strlen(temp) > largest_len) 
        {
            strcpy(largest, temp);
            largest_len = strlen(largest);
        }
        temp = strtok(NULL, "\n");
    }
}

printf("The largest word in the file is: %s\n", largest);

fclose(fp);

return 0;
}

【问题讨论】:

  • char words[MAX_WORD_COUNT][MAX_WORD_LENGTH] 是一个很好的起点,MAX_WORD_COUNT 定义为 10。
  • 或者更好的是typedef struct { char word[MAX_WORD_LEN]; int len } wstats;,然后声明一个数组wstats mystats[10] = {{ .word = "" }};,您可以简单地遍历您的数组,检查mystats[i].len并在阅读文件时添加/交换单词。
  • 您的文件结构如何?它只是一个每行一个单词的文件吗?
  • 有一个包含 10 个单词的数组(可以是数组数组,如果不能保证最大大小,也可以是指针数组)和一个包含字符串需要的最小大小的 int允许进入数组(除非数组未满,否则它将比最短的字符串大 1)。然后,每当您遇到较长的字符串时,找到最短的字符串并将其替换为较长的字符串并更新您的 int 变量。如果您按排序顺序维护数组,将很快找到要删除的元素,尽管这可能不是插入新字符串以保持顺序的地方。
  • 还要看堆数据结构。

标签: c++ c string file loops


【解决方案1】:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_WORD_LENGTH 200

int main () {
FILE *fp = fopen("words.txt","r");
char str[60];
char *largest = (char*) malloc (MAX_WORD_LENGTH);
int smallest_len = MAX_WORD_LENGTH, largest_len = 0;
int len_temp = MAX_WORD_LENGTH;  // new added code


for (int cnt = 1; cnt <= 10; cnt ++) // new added code
{

    while (fgets (str, 60, fp) != NULL)
    {
        char *temp = strtok(str, "\n");
        while (temp != NULL)
        {
            if (strlen(temp) > largest_len && strlen(temp) < len_temp)
            { // here len_temp is for remember the last biggest one length
                strcpy(largest, temp);
                largest_len = strlen(largest);
            }
            temp = strtok(NULL, "\n");
        }
    }
    // new added code
    printf("The %dst word in the file is: %s\n, length is %d", cnt, largest, largest_len);
    len_temp = largest_len;  // remember last largest length
    rewind(fp); // new added code
    largest_len = 0; // new added code
}

fclose(fp);

return 0;
}

【讨论】:

  • 这似乎是在打印同一个单词十次。
【解决方案2】:

您没有明确说明,但我会根据您的示例代码假设该文件每行一个字。

首先,这个任务是一个相当简单的 shell 单行代码。

awk '{print length($0), $0}' words.txt | sort -rn | head | awk '{print $2}'

与滚动您自己的程序相比,这将更快地编写并且更健壮。管道打印以长度和空格为前缀的每个单词,以相反的顺序对结果行进行数字排序,取前 10 个,然后打印不带长度的单词。

假设您确实需要编写 C,这里有一些建议:

  • 除非您有充分的理由避免动态分配,否则请学习如何使用getline()。它为您处理动态分配,这使您无需选择数组的大小。

  • 没有理由使用strtok() 删除换行符。换行只会在每个长度上加一个,不会改变结果,而且无论如何您都需要打印换行来报告结果。

  • 将结果保存在数组 char *longwords[10]; 中。每次你得到一个新词时,检查longwords 中的所有内容。如果新词足够长,将longwords中最短的词替换为新词。 strdup() 新词和free() 现有词根据需要。

【讨论】:

  • 您介意用简单的代码用 C/C++ 解释您的建议吗?
  • 虽然效率要低很多,但它必须对整个数组进行排序和存储,而不仅仅是最长的整数。
  • 是的,尝试使用 40 GB 文件的 shell one 行,我们将看到它与最简单的解决方案相比如何,该解决方案只是将每个新行与当前前 10 行进行比较(即使不使用最大值-堆)。
  • 请告诉我更多关于您碰巧放置的 40 GB 文本文件的信息。英语中的单词并不多。但是假设你,我可以将 shell 想法扩展到 40 GB,比你实现“琐碎”的 C 解决方案要快。
猜你喜欢
  • 2022-01-03
  • 1970-01-01
  • 2013-04-28
  • 1970-01-01
  • 1970-01-01
  • 2021-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多