Zakan
Zakan

Reputation: 51

Print histogram with "*" representing relative frequencies in C++

I'm trying to convert an histogram with absolute values to an histogram showing the relative frequency of letters in a string, written by the user. The letters frequency should be represented by *. So, if the letter "A" is 1% of a string, there should be two *. 1% = two *.

When trying to calculate the frequency, the output is zero. I don't really understand why.

I've tried to search the internet, but I can't really find something that helps me. I guess I'm stuck, both in my head and coding.

This is the code for my three functions:

void berakna_histogram_abs(const string inm, int arr[ANTAL_BOKSTAVER]){

    int i, j = 0;

    while (inm[i] != '\0'){
        if (inm[i] >= 'a' && inm[i] <= 'z'){
            j = inm[i] - 'a';
            ++arr[j];
        }
        if (inm[i] >= 'A' && inm[i] <= 'Z'){
            j = inm[i] - 'A';
            ++arr[j];
        }
        i++;
    }
}
void abs_till_rel(int arr[ANTAL_BOKSTAVER], int (&ree)[ANTAL_BOKSTAVER]){

        for(int i = 0; i < ANTAL_BOKSTAVER; i++) {
            ree[i] = arr[i] / 26;
            printf("%c %lf \n", i + 'a', ree[i]);
        }

        for (int x = 0; x < ANTAL_BOKSTAVER; x++){

        }

    }

void plotta_histogram_rel(int (&ree)[ANTAL_BOKSTAVER]){

    cout << "Frekvensen av bokstäver i texten är: " << endl;
    for (int i = 0; i < ANTAL_BOKSTAVER; i++){
        cout << char(i + 'a') << " : " << ree[i] << endl;

         }
    }

I'm not allowed to do any calculations in the third function, that is only for writing the histogram. The whole program is pretty big, if you'd like, I'll provide all the code.

Any help forward is much appreciated.

Thanks!

Upvotes: 0

Views: 385

Answers (2)

Zakan
Zakan

Reputation: 51

void abs_till_rel(int arr[ANTAL_BOKSTAVER], int langd, double frekArr[ANTAL_BOKSTAVER]){
//Function to calculate the relative frequency of letters in a string.
    for (int i = 0; i < ANTAL_BOKSTAVER; i++){

    frekArr[i] = arr[i]; //Writes over the input from the user to a new array.

    frekArr[i] = frekArr[i] * 200 / langd; //Calculates the relative frequency
    //*200 since 1% should be represented by two (2) *.
    }
}
void plotta_histogram_rel(double frekArr[ANTAL_BOKSTAVER], int langd){

    int j = 0;
    for (int i = 0; i < ANTAL_BOKSTAVER; i++){
    cout << char(i + 'A') << " : ";
//Creates a histograg, horizontal, with A-Z.

        if(frekArr[i] > 0){
        for ( j = 0; j < frekArr[i]; j++){ 
        cout << "*";
        }
        cout << endl;
        }
//If the index in frekArr is NOT empty, loop through the index [i] times and 
//write double the amount of *. 
        else {
            cout << " " << endl;
//Else, leave it empty.
        }
}
}

I've solved the issue. See the working code above.

Upvotes: 0

A M
A M

Reputation: 15277

So, you have some errors that need to be corrected. You do not pass the array as reference in the first function. You pass it by value. So all modifications that will be done to that arra in the first function berakna_histogram_abs will not be visible to the outside world.

You need to do the same as in you other functions -->

void berakna_histogram_abs(const std::string inm, int (&arr)[ANTAL_BOKSTAVER]) {

By the way, the string should also be passed as reference. Anyway. Not so important.

Next problem. You forgot to initialize variable i to 0 in your first function. So, it will have some random value and the program will fail, becuase you access some random index with inm[i].

In your calculation function abs_till_rel you are using the wrong formular. You need to multiply with 100 to get integer results between 0 and 100 for the percentage. And you divide by 26, which makes the result relative to the amount of the number of letters in an alphabet. My guess is that you want to have the relations to the number of letters in the string.

For that, you first need to calculate all counts of letters to get the overall count. Like for example with:

int sum = 0;
    for (int i = 0; i < ANTAL_BOKSTAVER; i++) sum += arr[i];

and then divide by this sum, like so:

ree[i] = (arr[i] * 100) / sum;

And to output the histogram, you can simply build a string with stars, using the std::string constructor number 2

Your updated program would look like this:

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

constexpr int ANTAL_BOKSTAVER = 26;

void berakna_histogram_abs(const std::string inm, int (&arr)[ANTAL_BOKSTAVER]) {

    int i = 0, j = 0;

    while (inm[i] != '\0') {
        if (inm[i] >= 'a' && inm[i] <= 'z') {
            j = inm[i] - 'a';
            ++arr[j];
        }
        if (inm[i] >= 'A' && inm[i] <= 'Z') {
            j = inm[i] - 'A';
            ++arr[j];
        }
        i++;
    }
}
void abs_till_rel(int arr[ANTAL_BOKSTAVER], int(&ree)[ANTAL_BOKSTAVER]) {
    
    int sum = 0;
    for (int i = 0; i < ANTAL_BOKSTAVER; i++) sum += arr[i];

    if (sum >0) for (int i = 0; i < ANTAL_BOKSTAVER; i++) {
        ree[i] = (arr[i] * 100) / sum;
        std::cout << (char)(i + 'a') << '\t' << ree[i] << '\n';
    }

    for (int x = 0; x < ANTAL_BOKSTAVER; x++) {

    }

}

void plotta_histogram_rel(int(&ree)[ANTAL_BOKSTAVER]) {

    std::cout << "Frekvensen av bokstäver i texten är: " << std::endl;
    for (int i = 0; i < ANTAL_BOKSTAVER; i++) {
        std::cout << char(i + 'a') << " : " << std::string(ree[i]*2,'*') << std::endl;

    }
}
int main() {

    std::string test{"The quick brown fox jumps over the lazy dog"};

    int frequencyArray[ANTAL_BOKSTAVER] = {};
    int frequencyInPercent[ANTAL_BOKSTAVER] = {};

    berakna_histogram_abs(test, frequencyArray);
    abs_till_rel(frequencyArray, frequencyInPercent);
    plotta_histogram_rel(frequencyInPercent);

}

But in C++, we would use the standard approach and write the followin:

#include <iostream>
#include <map>
#include <string>
#include <cctype>

// Our test string. This is a standard test string that contains all letters
std::string test{ "The quick brown fox jumps over the lazy dog" };

int main() {
    // Count all letters
    std::map<char, size_t> counter{};
    for (const auto& c : test) if (std::isalpha(c)) counter[std::tolower(c)]++;

    // Show histogram
    for (const auto& [letter, count] : counter)
        std::cout << letter << '\t' << std::string((count * 200) / test.size(), '*') << '\n';
    return 0;
}

Upvotes: 1

Related Questions