2010-10-21 13 views
15

Questo è un K & R esercizio (1-13) ...Stampare un istogramma in base a lunghezze di parola (C)

"Scrivere un programma per stampare un istogramma della lunghezza delle parole nella sua input È facile disegnare l'istogramma con le barre orizzontali, un orientamento verticale è più impegnativo. "

La sezione riguardava gli array e, ad essere onesti, non sono sicuro di averlo compreso appieno. Tutto fino a questo punto era abbastanza facile da capire, non lo era.

Ad ogni modo sto provando a eseguire un istogramma con barre orizzontali prima. Una volta capito, proverò in verticale, ma al momento non sono nemmeno sicuro da dove cominciare con la versione facile. (. Ho dormito su di esso, sono svegliato, e ancora non riusciva a farlo)

ho disegnato un esempio di ciò che il programma sarebbe uscita:

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

e ha cercato di romperlo (il programma) verso il basso in sezioni. Questo è ciò che mi si avvicinò con:

  1. STAMPA bordo superiore
  2. Stampa Categoria, STAMPA X OGNI VOLTA condizione è vera, PRINT NEWLINE, REPEAT.
  3. STAMPA bordo inferiore

Ma più ci penso e meno penso che sia come avrebbe funzionato (perché getchar() passa attraverso un carattere alla volta, e non sarebbe in grado di andare back up per inserire una X nella giusta categoria.) Oppure ...

... Sono solo molto confuso su come risolverei questo problema. Ecco quanto sono stato in grado di ottenere codice saggio:

#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; 
} 

Qualcuno potrebbe aiutarmi a illuminarmi? Non necessariamente con il codice, forse solo con lo pseudo codice, o con alcune "parole dal saggio" su ciò che devo fare, o pensare, o qualcosa del genere. Questo è stato solo un grosso ostacolo e mi piacerebbe superarlo: /.

(Vado a controllare di nuovo in 30 minuti)

+0

Non proprio un duplicato, ma si può trovare aiuto in [come tracciare un istogramma in c] (http://stackoverflow.com/questions/3836987/) e [Istogramma frequenza in C] (http://stackoverflow.com/questions/1413644/). – dmckee

+0

Mi piace il tuo modo di pensare! Ti manca qualcosa, tuttavia. Vedi la mia risposta qui sotto. – slezica

+3

Questo tipo di problema mi ha fatto impazzire quando ho imparato a programmare (cosa che ho fatto in C). La lezione, che Kernighan ripete spesso negli altri suoi libri, è: pensa in termini di dati, non di codice. –

risposta

7

Ho adorato lo pseudo-codice! Alcuni ci pensano bene, ma non stai ancora ordinando il tuo programma.

Come hai detto tu stesso, non puoi leggere il testo, tornare indietro e stampare una X in una riga particolare. Se stabiliamo che non può essere fatto, non c'è altra scelta che conoscere tutti i valori dell'istogramma in anticipo.

Quindi dovresti pensare al tuo programma come se avesse due parti (e questo tipo di divisione dividerà praticamente in ogni programma che scrivi): in primo luogo, una parte che effettuerà i calcoli; e quindi una parte che li stamperà in un determinato formato (l'istogramma).

Questo consiglio dovrebbe iniziare! Se hai bisogno di ulteriore aiuto, commenta qui sotto.

+0

+1 Questo è il miglior punto di partenza.Sottodivisione del compito nelle sue parti logiche e affrontarle una alla volta. – bta

+0

Sono d'accordo bta. Devo ammettere che non mi aspettavo così tante informazioni da tutti (grazie!), Ma è un po 'opprimente, quindi per ora rimarrò con questo (leggerò tutti alla fine però :-)) @Santiago Lezica: ora ho completato il codice con i tuoi consigli, come appare? http://fpaste.org/7ELL/ - Sono sulla buona strada? – Matt2012

+0

Sì, lo sei! Sembra bello, buona struttura. Due cose: prima, pensa a cosa devi fare quando STATE == IN, e cosa devi fare quando lo stato cambia da IN a OUT. In secondo luogo, tieni presente che il tuo testo potrebbe non terminare con uno spazio (spazio, tab, newline) e che devi considerare anche l'ultima parola quando trovi l'EOF. – slezica

1

Per istogramma la parola lunghezze, si sta andando ad avere bisogno di conoscere la parola lunghezze.

  • Come si definisce una parola?
  • Come si può misurare la lunghezza di una parola? Puoi farlo un carattere alla volta mentre leggi lo stream, o dovresti bufferizzare l'input usando strtok o qualcosa di simile?

È necessario accumulare dati sul numero di occorrenze di ciascuna lunghezza.

  • Come pensate di memorizzare questi dati?

Sarà necessario produrre i risultati in una forma piacevole. Questo è poco ma non difficile.

3

Suggerisco di semplificare il problema risolvendolo per il caso di una parola per riga, quindi è possibile utilizzare fgets. Ecco come fare "eat up" lines that are too long.

Quindi, come spesso, la struttura dati centrale è la chiave per risolvere il problema. La struttura dei dati è necessario è una matrice utilizzata come tabella di frequenza:

int freq[11]; 

In freq[1], memorizzare il numero di parole/linee di lunghezza 1, in freq[2] quelli di lunghezza 2, ecc, e in quelle di lunghezza freq[0] > 10. Non è necessario memorizzare le parole poiché il resto del programma ha solo bisogno della loro lunghezza. Scrivere l'istogramma dovrebbe essere facile ora.

Spero che questo non sia troppo spoiler.

1

io collegare la risposta qui sotto, ma dal momento che lei ha chiesto per i dettagli la chiave sembra essere questo

utilizzare un array di lunghezze cioè hanno una matrice con ogni elemento inizializzato a zero assumere MAX wordlength essere di circa 30 .. .

* hanno una bandiera mentre nella parola e incrementare un contatore ogni volta che una spaziatura non è rilevato

* una volta fuori della bandiera di parola è impostato su "out" e la parola corrispondente voce dell'indice lunghezza nella la matrice viene incrementata, ovvero se il contatore della lunghezza della parola è w_ctr

* utilizzare la matrice come tabella di riferimento per ogni linea in un ciclo per stampare ogni riga nell'istogramma in modo da poter utilizzare la matrice e ora sarà in grado di determinare il tempo che la 'X' nell'istogramma è da inserire o meno

MODIFICA: scusa non ho letto la domanda giusta ma l'idea è più semplice per gli istogrammi verticali e la stessa cosa può essere utilizzata.

dopo l'ultimo passo basta stampare l'istogramma orizzontale fino contatore supera wordlength corrente essendo stampato

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

End


l'originale è qui http://users.powernet.co.uk/eton/kandr2/krx113.html

CLC-wiki è anche un posto vedere i commenti per i dettagli.

+0

Quel sito è obsoleto/non mantenuto, vedere la stessa pagina su [CLC-wiki] (http://clc-wiki.net/wiki/K%26R2_solutions:Chapter_1:Exercise_13). – schot

+0

@schot Sì, è così che ho aggiunto il tuo link stavo dando credito alla fonte da dove ho imparato questo tempo fa :) :) – Siamore

0

Si dovrebbe separare i 2 problemi nelle funzioni, come:

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); 
    } 
} 

poi la sua facile nel vostro principale:

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; 
} 
2

Il codice di seguito stampa un istogramma orizzontale utilizzando solo il toolkit di base fornita da il libro fino ad ora:

#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'); 
    } 
} 
+0

L'istogramma verticale può essere stampato una riga alla volta, passando attraverso l'array di parole lunghezze e diminuendo la lunghezza della parola ad ogni iterazione. Viene stampato un # se la lunghezza della parola è ancora maggiore di zero e viene stampato uno spazio se ha raggiunto lo zero. Dopo ogni corsa, viene stampata una nuova riga. – edrik

0

L'istogramma verticale può essere stampato una riga alla volta e, passando attraverso la serie di lunghezze delle parole e diminuendo la lunghezza della parola ad ogni iterazione. Viene stampato un # se la lunghezza della parola è ancora sopra lo zero e uno spazio viene stampato quando raggiunge 0. La nuova riga viene stampata dopo ogni iterazione.

Se lunghezze [i] contiene il numero di caratteri per parola i, e WORDn è il numero totale di parole, allora la segue stampa l'istogramma verticale:

#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'); 
} 

il codice completo è qui sotto:

#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'); 
} 
} 
2
#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"); 
    } 
} 

Orientamento verticale: Usando solo gli strumenti che abbiamo imparato finora nel libro. E puoi cambiare la dimensione dell'array, wc [50]. Ho mantenuto il codice valido per 50 parole. L'orientamento orizzontale dovrebbe essere molto più semplice. Non l'ho provato però.

0

Sebbene l'esercizio sia basato su Array, ho provato a scriverlo utilizzando il ciclo while di base e un'istruzione if. Finora non sono molto bravo con gli array, quindi ho pensato di provarlo. Non l'ho ancora testato per i bug, ma sembra funzionare bene per la maggior parte degli input.

#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; 
    } 

prega di notare che questo è un pezzo di base di codice per stampare in orizzontale, solo per la comprensione di base della struttura.

0
// 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"); 
    } 


} 
1
//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