【问题标题】:Count the number of occurrences of each word计算每个单词出现的次数
【发布时间】:2016-07-12 01:52:31
【问题描述】:

我正在尝试计算函数 countWords 中每个单词的出现次数我相信我在函数中正确启动了 for 循环,但是如何将数组中的单词比较在一起并计算它们然后删除重复项?这不是像斐波那契数列还是我弄错了? int n 的值也为 756,因为这就是数组中有多少个单词,wordsArray 是数组中的元素。

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

int *countWords( char **words, int n);
int main(int argc, char *argv[])
{
  char buffer[100];  //Maximum word size is 100 letters
  FILE *textFile;
  int numWords=0;
  int nextWord;
  int i, j, len, lastChar;
  char  *wordPtr;
  char  **wordArray;
  int *countArray;
  int *alphaCountArray;
  char **alphaWordArray;
  int *freqCountArray;
  char **freqWordArray;
  int choice=0;

  //Check to see if command line argument (file name)
  //was properly supplied.  If not, terminate program
  if(argc == 1)
  {
    printf ("Must supply a file name as command line argument\n");
    return (0);
  }

  //Open the input file.  Terminate program if open fails
  textFile=fopen(argv[1], "r");
  if(textFile == NULL)
  {
    printf("Error opening file. Program terminated.\n");
    return (0);
  }

  //Read file to count the number of words
  fscanf(textFile, "%s", buffer);
  while(!feof(textFile))
  {
    numWords++;
    fscanf(textFile, "%s", buffer);
  }

  printf("The total number of words is: %d\n", numWords);
  //Create array to hold pointers to words
  wordArray = (char **) malloc(numWords*sizeof(char *));
  if (wordArray == NULL)
  {
     printf("malloc of word Array failed.  Terminating program.\n");
     return (0);
  }
  //Rewind file pointer and read file again to create
  //wordArray
  rewind(textFile);
  for(nextWord=0; nextWord < numWords; nextWord++)
  {
    //read next word from file into buffer.
    fscanf(textFile, "%s", buffer);

    //Remove any punctuation at beginning of word
    i=0;
    while(!isalpha(buffer[i]))
    {
      i++;
    }
    if(i>0)
    {
      len = strlen(buffer);
      for(j=i; j<=len; j++)
      {
        buffer[j-i] = buffer[j];
      }
    }

    //Remove any punctuation at end of word
    len  = strlen(buffer);
    lastChar = len -1;
    while(!isalpha(buffer[lastChar]))
    {
      lastChar--;
    }
    buffer[lastChar+1] = '\0';

    //make sure all characters are lower case
    for(i=0; i < strlen(buffer); i++)
    {
      buffer[i] = tolower(buffer[i]);
    }

    //Now add the word to the wordArray.
    //Need to malloc an array of chars to hold the word.
    //Then copy the word from buffer into this array.
    //Place pointer to array holding the word into next
    //position of wordArray
    wordPtr = (char *) malloc((strlen(buffer)+1)*sizeof(char));
    if(wordPtr == NULL)
    {
      printf("malloc failure.  Terminating program\n");
      return (0);
    }
    strcpy(wordPtr, buffer);
    wordArray[nextWord] = wordPtr;
  }

  //Call countWords() to create countArray and replace
  //duplicate words in wordArray with NULL
  countArray = countWords(wordArray, numWords);
  if(countArray == NULL)
  {
    printf("countWords() function returned NULL; Terminating program\n");
    return (0);
  }

  //Now call compress to remove NULL entries from wordArray
  compress(&wordArray, &countArray, &numWords);
  if(wordArray == NULL)
  {
    printf("compress() function failed; Terminating program.\n");
    return(0);
  }
  printf("Number of words in wordArray after eliminating duplicates and compressing is: %d\n", numWords);

  //Create copy of compressed countArray and wordArray and then sort them alphabetically
  alphaCountArray = copyCountArray(countArray, numWords);
  freqCountArray = copyCountArray(alphaCountArray, numWords);
int *countWords( char **wordArray, int n)
{
  return NULL;
  int i=0;
  int n=0;

  for(i=0;i<n;i++)
  {
      for(n=0;n<wordArray[i];n++)
      {

      }
   }

}

【问题讨论】:

  • while(!feof(textFile)) { numWords++; fscanf(textFile, "%s", buffer); } 是错误的。使用fscanf() 的返回值来确定何时退出循环。

标签: c arrays string


【解决方案1】:

假设您希望countWords 的返回值是一个整数数组,每个唯一单词都有字数,您需要有一个双循环。一个循环遍历整个数组,第二个循环遍历数组的其余部分(在当前单词之后),寻找重复项。

你可以做这样的伪代码:

Allocate the return array countArray (n integers) 
Loop over all words (as you currently do in your `for i` loop)
   If the word at `i` is not null // Check we haven't already deleted this word
      // Found a new word
      Set countArray[i] to 1
      Loop through the rest of the words e.g. for (j = i + 1; j < n; j++)
         If the word at j is not NULL and matches the word at i (using strcmp)
            // Found a duplicate word
            Increment countArray[i] (the original word's count)
            // We don't want wordArray[j] anymore, so 
            Free wordArray[j]
            Set wordArray[j] to NULL
   Else
      // A null indicates this was a duplicate, set the count to 0 for consistency.
      Set countArray[i] to 0
Return wordArray

【讨论】:

    【解决方案2】:

    我要在这里给你扔一个曲线球。

    我决定从头开始编写一个示例,而不是修复您的代码,因为它本身非常好,但很容易修复,但不完整。

    无需读取文件两次 [第一次只是为了获得最大计数]。这可以由动态数组和realloc 处理。

    我想,主要的一点是,在 创建 时确保单词列表有 no 重复项要比在最后删除重复项要容易得多。

    我选择了一些东西。

    我创建了一个“文字控制”结构。您有几个以相同方式索引的单独数组。这有点像“呼喊”一个结构。也就是说,不是 [say] 5 个单独的数组,而是拥有一个包含 5 个元素的结构的单个数组。

    单词列表是这些结构的链表。它可能是堆上的一个动态数组,取而代之的是realloced,但对于这种特殊用途,链表实际上更容易维护。

    每个结构都有 [cleaned up] 单词文本和出现次数(相对于您单独的 wordArraycountArray)。

    添加单词时,会扫描列表中的现有匹配项。如果找到一个,则增加计数,而不是创建新的单词列表元素。这是消除重复的关键[即不要一开始就创建它们]。

    不管怎样,这里是:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
    #include <errno.h>
    
    #define sysfault(_fmt...) \
        do { \
            printf(_fmt); \
            exit(1); \
        } while (0)
    
    // word control
    typedef struct word {
        struct word *next;              // linked list pointer
        char *str;                      // pointer to word string
        int count;                      // word frequency count
    } word_t;
    
    word_t wordlist;                    // list of words
    
    // cleanword -- strip chaff and clean up word
    void
    cleanword(char *dst,const char *src)
    {
        int chr;
    
        // NOTE: using _two_ buffers in much easier than trying to clean one
        // buffer in-place
        for (chr = *src++;  chr != 0;  chr = *src++) {
            if (! isalpha(chr))
                continue;
            chr = tolower(chr);
            *dst++ = chr;
        }
    
        *dst = 0;
    }
    
    // addword -- add unique word to list and keep count of number of words
    void
    addword(const char *str)
    {
        word_t *cur;
        word_t *prev;
        char word[1000];
    
        // get the cleaned up word
        cleanword(word,str);
    
        // find a match to a previous word [if it exists]
        prev = NULL;
        for (cur = wordlist.next;  cur != NULL;  cur = cur->next) {
            if (strcmp(cur->str,word) == 0)
                break;
            prev = cur;
        }
    
        // found a match -- just increment the count (i.e. do _not_ create a
        // duplicate that has to be removed later)
        if (cur != NULL) {
            cur->count += 1;
            return;
        }
    
        // new unique word
        cur = malloc(sizeof(word_t));
        if (cur == NULL)
            sysfault("addword: malloc failure -- %s\n",strerror(errno));
    
        cur->count = 1;
        cur->next = NULL;
    
        // save off the word string
        cur->str = strdup(word);
        if (cur->str == NULL)
            sysfault("addword: strdup failure -- %s\n",strerror(errno));
    
        // add the new word to the end of the list
        if (prev != NULL)
            prev->next = cur;
    
        // add the first word
        else
            wordlist.next = cur;
    }
    
    int
    main(int argc,char **argv)
    {
        FILE *xf;
        char buf[1000];
        char *cp;
        char *bp;
        word_t *cur;
    
        --argc;
        ++argv;
    
        xf = fopen(*argv,"r");
        if (xf == NULL)
            sysfault("main: unable to open '%s' -- %s\n",*argv,strerror(errno));
    
        while (1) {
            // get next line
            cp = fgets(buf,sizeof(buf),xf);
            if (cp == NULL)
                break;
    
            // loop through all words on a line
            bp = buf;
            while (1) {
                cp = strtok(bp," \t\n");
                bp = NULL;
    
                if (cp == NULL)
                    break;
    
                // add this word to the list [avoiding duplicates]
                addword(cp);
            }
        }
    
        fclose(xf);
    
        // print the words and their counts
        for (cur = wordlist.next;  cur != NULL;  cur = cur->next)
            printf("%s %d\n",cur->str,cur->count);
    
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2021-04-19
      • 1970-01-01
      • 1970-01-01
      • 2018-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-05
      • 1970-01-01
      相关资源
      最近更新 更多