Печать гистограммы на основе длины слова (C)

Это упражнение K & R (1-13)...

"Напишите программу для печати гистограммы длины слов на входе. Гистограмму легко нарисовать с помощью бары горизонтальные; вертикальная ориентация более сложная".

В разделе речь шла о массивах, и, честно говоря, я не уверен, что полностью это понял. Все до этого момента было довольно легко понять, это было не так.

В любом случае я сначала пытаюсь сделать гистограмму с горизонтальными барами. Как только я это улажу, я попробую по вертикали, но сейчас я даже не знаю, с чего начать с простой версии. (Я спал на нем, проснулся и все равно не смог его получить.)

Я привел пример вывода программы:

----------------------------------------------------------------
001|XX
002|XXXX
003|X
004|XXXXXXXXXX
005|XXXXXXXXXXXXXXXXXXXXXXXXX
006|XXXX
007|X
008|
009|XXXXXXXXX
010|XXX
>10|XXXX
----------------------------------------------------------------

И попытался сломать его (программу) в разделах. Вот что я придумал:

  • PRINT TOP BORDER
  • ПЕЧАТНАЯ КАТЕГОРИЯ, ПЕЧАТЬ X КАЖДОЕ ВРЕМЯ СОСТОЯНИЕ ИСТИНА, ПЕЧАТЬ NEWLINE, REPEAT.
  • ПЕЧАТНАЯ НОМЕРНАЯ ГРАНИЦА

Но чем больше я думаю об этом, тем меньше я думаю, что он будет работать (потому что getchar() проходит через одного персонажа за раз, и он не сможет вернуться, чтобы поставить X вправо категория.) Или...

... Я просто очень смущен тем, как бы я решил эту проблему. Здесь, насколько мне удалось получить код:

#include <stdio.h>

#define MAXWORDLENGTH 10

// print a histogram of the length of words in input. horizontal bar version

int main(void)
{
  int c;
  while ((c = getchar()) != EOF) {

  }

  return 0;
}

Может кто-нибудь помочь просветить меня? Не обязательно с кодом, может быть, просто псевдокодом или с некоторыми "словами из мудрых" относительно того, что мне нужно делать, или думать, или что-то еще. Это был действительно большой камень на дороге, и я хотел бы пройти мимо него:/.

(я вернусь через 30 минут)

Ответы

Ответ 1

Мне понравился псевдокод! Некоторые хорошие мысли там, но вы по-прежнему не заказываете свою программу правильно.

Как вы сами сказали, вы не можете прочитать текст, вернуться и распечатать X в определенной строке. Если мы установим, что это невозможно сделать, тогда нет выбора, кроме как заранее знать все значения гистограммы.

Итак, вы должны подумать, что ваша программа состоит из двух частей (и вы будете делать такое разделение практически во всех написанных вами программах): во-первых, часть, которая будет выполнять вычисления; а затем часть, которая будет выводить их в определенном формате (гистограмма).

Этот совет должен вас начать! Если вам нужна дополнительная помощь, прокомментируйте ниже.

Ответ 2

Я предлагаю вам упростить задачу, разрешив ее для случая одного слова в строке, поэтому вы можете использовать fgets. Вот как "съесть" слишком длинные строки.

Затем, как часто, центральная структура данных является ключом к решению проблемы. Необходимая структура данных - это массив, используемый в качестве таблицы частот:

int freq[11];

В freq[1], сохраните количество слов/строк длиной 1, в freq[2] с длиной 2 и т.д., а в freq[0] с длиной > 10. Вам не нужно хранить слова, так как остальная часть программы нуждается только в их длине. Списание гистограммы должно быть простым.

Надеюсь, это не слишком много спойлера.

Ответ 3

Приведенный ниже код печатает горизонтальную гистограмму, используя только базовый набор инструментов, предоставленный книгой:

#include<stdio.h>

/* Prints a horizontal histogram of the lengths of words */

#define MAX_WORDS 100
#define IN 1
#define OUT 0

main()
{
 int c, length, wordn, i, j, state, lengths[MAX_WORDS];
 wordn = length = 0;
 state = OUT;
 for (i = 0; i < MAX_WORDS; ++i) lengths[i] = 0;

 while ((c = getchar()) != EOF && wordn < MAX_WORDS)
 {
    if (c == ' ' || c == '\t' || c == '\n')
        state = OUT;

    else if (wordn == 0) 
        {
         state = IN;
         ++wordn;
         ++length;
        }

    else if (state == IN)
         ++length;

    else if (state == OUT)
        {
         lengths[wordn] = length;
         ++wordn;
         length = 1;
         state = IN;
        }
 }    

 lengths[wordn] = length;

 for (i = 1; i <= wordn; ++i)
    {
     printf("%3d: ",i);
     for (j = 0; j < lengths[i]; j++)
        putchar('-');
    putchar('\n');
    }
}

Ответ 4

#include<stdio.h>
#define RESET 0
#define ON 1

main()
{
  int i,wnum=0,c,wc[50];
  int count=0,state;
  state=RESET;
  for(i=0;i<50;++i)
    wc[i]=0;
  /*Populating the array with character counts of the typed words*/
  while((c=getchar())!=EOF)
    {
      if(c=='\n'||c=='\t'||c==' '||c=='"')
    {
      if(state!=RESET)
        state=RESET;
    }
      else if((c>=65&&c<=90)||(c>=97&&c<=122))
    {
      if(state==RESET)
        {
          count=RESET;
          ++wnum;
          state=ON;
        }
      ++count;
      wc[wnum-1]=count;
    }
    }
  c=RESET;

  /*Finding the character count of the longest word*/
  for(i=0;i<wnum;++i)
    {
      if(c<wc[i])
    c=wc[i];
    }

  /*Printing the Histogram Finally*/ 
 for(i=c;i>0;--i)
    {
      for(count=0;count<wnum;++count)
    {
      if(wc[count]-i<0)
        printf("  ");
      else printf("x ");
    }
      printf("\n");
    }
}

ВЕРТИКАЛЬНАЯ ОРИЕНТАЦИЯ: Использование только тех инструментов, которые мы изучили до сих пор в книге. И вы можете изменить размер массива, wc [50]. Я сохранил код действительным для 50 слов. Горизонтальная ориентация должна быть более простой. Я не пробовал, хотя.

Ответ 5

Чтобы гистограмма длины слова, вам нужно знать длины слов.

  • Как вы определяете слово?
  • Как вы можете измерить длину слова? Можете ли вы сделать это по одному символу за раз, когда вы читаете поток, или если вы буферизируете ввод, используйте strtok или что-то подобное?

Вам нужно будет накапливать данные о количестве вхождений каждой длины.

  • Как вы сохраните эти данные?

Вам нужно будет вывести результаты в приятной форме. Это неудобно, но не сложно.

Ответ 6

Я свяжусь с нижеприведенным ответом, но, поскольку вы запросили подробности, ключ, похоже, выглядит следующим образом:

Используйте ARRAY длин. i.e есть массив с каждым инициализированным нулем элементом, предположим, что длина слова MAX составляет около 30...

* имеют флаг во время слова и увеличивают счетчик каждый раз, когда пробел НЕ встречается

* после того, как из флага слова установлено значение "out", и соответствующий индексный элемент длины слова в массиве увеличивается. Если счетчик длины слова w_ctr использует

array[w_ctr]++

* используйте массив в качестве справочной таблицы для каждой строки в цикле, чтобы напечатать каждую строку на гистограмме, чтобы вы могли использовать массив, и теперь сможете определить погоду, в которую должна быть вставлена ​​ "X" на гистограмме или не

EDIT: извините, я не прочитал вопрос правильно, но идея проще для вертикальных гистограмм, и то же самое можно использовать.

после последнего шага просто распечатайте горизонтальную гистограмму до тех пор, пока счетчик не выведет текущую длину слова

for(ctr=0;ctr<array[current_wordlength];ctr++)
     printf('X');    

End


оригинал здесь http://users.powernet.co.uk/eton/kandr2/krx113.html

CLC-wiki - это также место, где подробности см. в комментариях.

Ответ 7

//This is for horizontal histogram.
//It works for any number of lines of words where total words <= MAX
#include <stdio.h>
#define MAX 100 //Change MAX to any value.But dont give words more than MAX.

void main()
{
    int w, nwords[MAX] = {0}, i = 0;   //nwords is an array for storing length of each word.Length of all words initialized to 0.

    while ((w = getchar()) != EOF)
    {
        if (w == ' ' || w == '\t' || w == '\n')
            ++i;            //if space or tab or newline is encountered, then index of array is advanced indicating new word
        else
            ++nwords[i];        //increment the count of number of characters in each word
    }       //After this step,we will have array with each word length.

    for (i = 0; i < MAX; i++)   //iterating through array
    {
        printf("\n");
        for (; nwords[i] > 0; nwords[i]--)  
            printf("$");        //if length of word > 0 , print $ and decrement the length.This is in loop.
        if (nwords[i+1] == 0)   //as MAX is 100, to avoid printing blank new lines in histogram,we check the length of next word.
            break;              //If it is 0, then break the loop
        printf("\n");   //After each word bar in histogram, new line.
    }
    printf("\n");
} //main

Ответ 8

Вы должны отделить свои 2 проблемы от функций, например:

void gethist(char *s, int *hist, int len)
{ /* words here breaks on spaces (' ') */
  char *t;
  for( t=strtok(s," ");t;t=strtok(0," ") )
    if(*t)
      hist[ strlen(t)>len-1?len-1:strlen(t)-1 ]++;
}

void outhist(int *hist, int len)
{
  int i;
  for( i=1; i<=len; ++i )
  {
    char *s = calloc(1,5+hist[i-1]);
    sprintf(s,"%03d|", i);
    memset( s+4, 'X', hist[i-1]);
    puts(s);
    free(s);
  }
}

тогда его легко в вашем основном:

int main(void)
{
  int c, hist[11] = {};

  char *s = calloc(1,1);
  while ((c = getchar()) != EOF) {
    s = realloc( s, 2+strlen(s) );
    s[ strlen(s)+1 ] = 0;
    s[ strlen(s) ] = c;
  }

  gethist(s,hist,11); free(s);
  outhist(hist,11);

  return 0;
}

Ответ 9

Вертикальная гистограмма может быть напечатана по одной строке за раз, пройдя массив длин слов и уменьшая длину слова на каждой итерации. A # печатается, если длина слова все еще выше нуля, и пространство печатается, когда оно достигает 0. Новая строка печатается после каждой итерации.

Если lengths [i] содержит количество символов для слова i, а слово n - общее количество слов, то следующее будет печатать вертикальную гистограмму:

#define YES 1
#define NO 0


 more_lines = YES;
 while (more_lines)
 {
  more_lines = NO; 
  for (i = 1; i <= wordn; ++i)
          {
        if (lengths[i] > 0 ) 
                {
                  more_lines = YES;
                  printf("#\t");
                  --lengths[i];
                }
        else 
                 printf(" \t"); 
      }
  putchar('\n');
 }

Полный код приведен ниже:

#include<stdio.h>
/* Prints a histogram of the lenghts of words */

#define MAX_WORDS 100
#define IN 1
#define OUT 0

#define YES 1
#define NO 0

main()
{
 int c, length, wordn, i, j, state, more_lines, lengths[MAX_WORDS];
 wordn = length = 0;
 state = OUT;
 for (i = 0; i < MAX_WORDS; ++i) lengths[i] = 0;

 while ((c = getchar()) != EOF && wordn < MAX_WORDS)
 {
    if (c == ' ' || c == '\t' || c == '\n')
        state = OUT;

    else if (wordn == 0) 
        {
         state = IN;
         ++wordn;
         ++length;
        }

    else if (state == IN)
         ++length;

    else if (state == OUT)
        {
         lengths[wordn] = length;
         ++wordn;
         length = 1;
         state = IN;
        }
 }    

 lengths[wordn] = length;

/* Print histogram header */
  for (i = 1; i <= wordn; ++i)    
printf ("%d\t", i);
  putchar('\n');

 more_lines = YES;
 while (more_lines)
 {
  more_lines = NO; 
  for (i = 1; i <= wordn; ++i)
      {
    if (lengths[i] > 0 ) 
        {
          more_lines = YES;
          printf("#\t");
          --lengths[i];
        }
    else 
         printf(" \t"); 
      }
  putchar('\n');
 }
}

Ответ 10

Хотя упражнение основано на массивах, я попытался написать его, используя базовый цикл while и оператор if. На данный момент я не очень хорошо разбираюсь в массивах, поэтому подумал об этом. Я не тестировал его на наличие ошибок, но, похоже, он работает нормально для большинства входов.

    #include<stdio.h>   
    main() {
    long int c;         

    while((c=getchar())!=EOF) { 
        if(c!=' '&&c!='\n'&&c!='\t') {
            putchar("*");
        }

        if(c==' '||c=='\n'||c=='\t') {   
            putchar('\n');   
        } 

    }
    return 0;
    }

Обратите внимание, что это очень простой фрагмент кода для его печати по горизонтали, просто для базового понимания структуры.

Ответ 11

// Histogram to print the length of words in its input
#include <stdio.h>
main()
{
    int wordcount[10],c,token=0;
    int word=0, count =0;
    for (int i=0; i<10; i++)
    {
        wordcount[i]=0;
    }

    while((c=getchar())!=EOF)
    {
     if(c== ' ' || c == '\n' || c== '\t')
     {
         // add the length of word in the appropriate array number 
         switch(word)
         {
            case 1:
            ++wordcount[0];break;
            case 2:
            ++wordcount[1];break;
            case 3:
            ++wordcount[2];break;
            case 4:
            ++wordcount[3];break;
            case 5:
            ++wordcount[4];break;
            case 6:
            ++wordcount[5];break;
            case 7:
            ++wordcount[6];break;
            case 8:
            ++wordcount[7];break;
            case 9:
            ++wordcount[8];break;
            case 10:
            ++wordcount[9];break;
         }
         word =0;
     }
     else if (c != ' ' || c != '\n' || c!= '\t')
     {
         word++;
     }

}
    for (int j=0; j<10; j++)
    {
        if(wordcount[j]==0)
        {
            printf("- ");
        }
        for (int k=0;k<wordcount[j];k++)
        printf("X", wordcount[j]);
        printf("\n");
    }


}

Ответ 12

На вопрос уже задан вопрос с использованием массива. Приведенный ниже код печатает горизонтальную гистограмму без использования массива. При свободном определении, что слово представляет собой любую последовательность символов, которая не содержит пробела, табуляции или новой строки.

#include<stdio.h>
#define BLANK ' '
#define TAB '\t'
#define NEWLINE '\n'
#define RESET 0

void main()
{
    int c, num_char = 0, num_line = 0;
    while((c = getchar()) != EOF)
    {
        if(c == BLANK || c == TAB || c == NEWLINE)
        {
            printf("%d.: ", num_line);
            for(int i = 0; i < num_char; ++i)
                printf(" *");
            putchar(NEWLINE);
            ++num_line;
            do
            {
                c = getchar();
            }while(c == BLANK || c == TAB || c == NEWLINE);
            num_char = RESET;
        }
        ++num_char;
    }
}

Ответ 13

Вот пример простой вертикальной гистограммы

#include <stdio.h>

int main()
{
    int c, i, j, max;
    int ndigit[10];

    for (i = 0; i < 10; i++)
        ndigit[i] = 0;

    while ((c = getchar()) != EOF)
        if (c >= '0' && c <= '9')
            ++ndigit[c-'0'];

    max = ndigit[0];
    for (i = 1; i < 10; ++i)        /* for Y-axis */
        if (max < ndigit[i])
            max = ndigit[i];

    printf("--------------------------------------------------\n");
    for (i = max; i > 0; --i) {
        printf("%.3d|", i);
        for (j = 0; j < 10; ++j)
            (ndigit[j] >= i) ? printf(" X ") : printf("   ");
        printf("\n");
    }
    printf("   ");
    for (i = 0; i < 10; ++i)        /* for X-axis */
        printf("%3d", i);
    printf("\n--------------------------------------------------\n");
    return 0;
}

Ответ 14

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

int main()
{
    //hold length of string
    unsigned long length;
    // Holds the name input by user upto 50 characters
    char name[50];
    //iterator for generating dash for bar chart
    int i = 0;
    //iterator for generating dash for bar chart
    int j = 0;
    //take user name input
    printf("input your name [without spaces and < 50 characters] : ");
    scanf("%s", &name[0]);
    //find the length of string
    length = strlen(name);
    printf("length of your name is %lu \n", length);
    //generate dashes for bar chart
    while (i < length)
    {
        printf("--");
        ++i;
    }
    printf("| \n");
    // fill the bar chart with []
    while (j < length)
    {
        printf("[]");
        ++j;
    }
    printf("| \n");
    //generate dashes for bar chart
    while (length > 0)
    {
        printf("--");
        --length;
    }
    printf("| \n");
}

введите ваше имя [без пробелов и <50 символов]: ThisIsAtestRun

длина вашего имени 14

----------------------------|
[][][][][][][][][][][][][][]|
----------------------------|

Ответ 15

Я попытался реализовать последнюю часть вопроса (т.е. отображение гистограммы по вертикали) и сумел выполнить большую часть этого. В приведенном ниже коде максимальное количество принятых слов - 20, а максимальная длина - 10. Кроме того, извинения за то, что не получили лучшего графического представления типичной гистограммы, но логика для отображения вертикальных полос, абсолютно точна! Вот мой код,

#define MAXWORDS 20
#define MAXLENGTH 10

int c, nlength = 0, i, nword = 0, j;
    int length_words[20]= {0};

    while((c = getchar()) != EOF && nword <= MAXWORDS)
    {
        if(c != ' ' && c != '\t' && c != '\n')
            ++nlength;
        else
        {
            if(nlength != 0){
                length_words[nword] = nlength;
                ++nword;
               /* for(i = 0; i < nlength; i++)
                printf("O");
                printf("\n");*/
                printf("Word number: %d has length: %d\n", nword - 1, nlength);
            }
            nlength = 0;
        }
    }
    // Displaying the Histogram
    for(i = MAXLENGTH; i > 0; i--)
    {
        for(j = 0; j < nword; j++)
        {
            if(i > length_words[j])
                printf("   ");
            else
                printf(" O ");
        }
        printf("\n");
    }

Не стесняйтесь запустить это и дайте мне знать в случае любого несоответствия или лазеек!