【问题标题】:Program that takes a users inputted characters and displays them in descending order of occurrence获取用户输入的字符并按出现的降序显示它们的程序
【发布时间】:2018-06-25 20:21:26
【问题描述】:

“编写一个程序,读取用户输入并以句点 ('.') 终止的字符序列。您的程序应允许用户通过按回车键输入多行输入每行的结尾。程序应该打印出一个频率表,按出现次数降序排列,列出出现的每个字母及其出现的次数。必须忽略所有非字母字符。输入的任何字符在句点 ('.') 之后应留在输入流中未处理。不能对输入的长度设置任何限制。"

我不知道从哪里开始。到目前为止,这是我想出的:

#include<iostream>
using namespace std;



  int main(){


        int count=0;
    char ch[count];
    int i=0;

    cout<<"Enter a sequence of characters (end with '.'): ";
    cin>>ch[count];
    while(ch[count]!='.')
    {
        count++;
        cin>>ch[count];


    }

    cout<<"There were "<<count<<" characters in the string"<<endl;
    return 0;
 }

现在程序接受用户输入并显示其中的字符数,但我无法让它显示任何字符,更不用说按降序排列了。排序不是我的问题,我完全理解如何编程,但我无法显示存储在输入流中的字符。

我的导师建议我们使用结构,但现在我只需要一些指导。输出格式应如下:

Enter a sequence of characters (end with '.'): do be Do bo. xyz


Letter:    Number of Occurrences

o     3
d     2
b     2
e     1

我不是要求任何人为我编写代码,我只是需要帮助了解从哪里开始,以及如何让字符显示。我们不能使用字符串类,因此不能使用除strlen()之外的任何字符串函数。

【问题讨论】:

  • 有人可以批准编辑吗
  • 如果它编译,那么ch的长度为0。访问这个数组总是会导致未定义的行为。
  • 听起来你想将输入读入容器(如std::vector),然后std::sort 容器。然后遍历已排序的容器并将其内容打印到std::cout。或类似的。
  • 如果你不能使用std::sort那么也许只是实现冒泡排序?它非常效率低下,但实施起来很简单。
  • @Sharad Khanna 和我大体上同意。大多数家庭作业问题只是作为作业的转储和我们实施解决方案的请求发布。我反对并投票结束这些问题。但这是不同的,因为 OP 实际上已经进行了尝试。这比大多数人都多。

标签: c++ struct find-occurrences


【解决方案1】:

如果输入是从文本文件加载或由在线法官或其他机构检查,您可以一次读取一个字符(这是您将使用的)或读取整个块(更快的解决方案)类似于一次加载整个输入,但这是一个旁注。

首先,我将在您的 main 开头添加这一行到您的代码中

ios::sync_with_stdio(false);

这一行将使您的代码显着加快,因为 C++ 的 I/O 不再与 C 的 I/O 同步,因此它消除了显着的开销,但请记住,如果混合使用这两个 I/,您将得到无意义的垃圾。该行之后的 O 库。

一旦 I/O 准备就绪,我将添加读取输入并计算出现次数的代码。为此,您应该对一个特定功能感兴趣 - get。现在您只需要一个大于 0 的整数数组(必须适合任何可能作为输入出现的字符,应在某处指定字符集,但对于 ASCII 而言,安全数字为 256)、一个循环、一个条件终止循环(输入中的字符 == '.'),您几乎完成了阅读和计数(不需要任何函数!)。

毕竟排序没那么可怕。在大多数情况下,冒泡排序可能不是要走的路,但是有多少个字符呢? 40多岁? 50左右? 100左右?除非您超过 300-500 个字符,否则不值得实现有史以来最好的未知 O(lgn) 时间、O(1) 空间、稳定排序算法,因为它的平均性能可能比更简单的算法更差。如果您想要重型算法,请寻找合并排序或快速排序,或者寻找更简单的替代方案,例如冒泡排序(最简单也最慢)或插入排序。

【讨论】:

    【解决方案2】:

    有两个部分需要解决。首先,逐个读取字符,忽略任何非字母字符,并计算其他字符;其次,按降序打印分数。

    第一部分可以通过简单地将字符视为 0 到 255 之间的 ASCII 值(即在 unsigned char 范围内)并为每个这些值设置一个计数数组来解决。

    其次,您可以简单地遍历计数,找到最大值,然后打印出来。继续此操作,直到考虑了所有 > 0 的值。

    请参阅以下说明此方法的代码:

    #include <sstream>
    
    int main() {
    
        stringstream ss("do be Do bo. xyz");
        unsigned char c;
        unsigned int counts[256] = {0};
        while (ss >> c && c != '.') {
            if (! isalpha(c)) {
                continue;
            }
            c = tolower(c);
            counts[c]++;
        }
    
        while (1) {
            // find next maximum
            int max = 0;
            int maxPos = -1;
            for (int i=0; i<256; i++) {
                if (counts[i] > max) {
                    max = counts[i];
                    maxPos = i;
                }
            }
            if (max == 0) {
                break;
            }
            else {
                cout << (char)maxPos << ":" << max << endl;
                counts[maxPos] = 0; // don't consider this pos in next run
            }
        }
    }
    

    输出:

    o:3
    b:2
    d:2
    e:1
    

    【讨论】:

    • 你刚刚解决了别人的作业。你剥夺了他们学习和探索的机会。你为自己感到骄傲吗?
    • @Whatever 如果 OP 使用这个答案,它将被视为抄袭。大多数 CS 课程禁止您从网络上复制和粘贴其他人的代码。
    • @Whatever:我认为这个问题对于 C++ 初学者来说太复杂了;虽然是一个可行的解决方案,但它包含足够的东西来详细说明,所以我相信它会帮助 OP。而且 - 如果我能把某人带到前面,我很自豪,是的。
    • @SharadKhanna 我不是在谈论复制代码。看到这段代码后,OP 不太可能学到一些东西,因为解决方案已经在这里了。他们不必再寻找它,因为他们可以重新输入它,在这里和那里改变一些东西,他们的功课就完成了。他们学习与他们的任务不严格相关的东西的机会较小。此外,他们不必设计程序的逻辑。其他人为他们做了这件事。
    • @StephanLechner 提供指导比提供解决方案要好得多,因为它让人们思考、探究和创造。
    猜你喜欢
    • 1970-01-01
    • 2011-10-07
    • 1970-01-01
    • 2021-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多