首先要实现的功能:对英文文档中的单词进行统计,计算词频;
构造了一个Token类,
//Token private: char *token; //存储每个单词 int count; //存储单词出现的次数 public: Token *next; //构造Token链表,指向下一个Token对象 Token(char *t) //构造函数给Token对象附初值; { strcpy(token, t); count = 1; next = NULL; } void addcount() { count += 1; } bool equname(char *t) //判断是否属于同一个单词 { if (strlen(t) != strlen(token)) return 0; for (int i = 0;i < strlen(t);i++) { if (t[i] != token[i]) { return 0; break; } } return 1; } int get_count() //返回单词数; { return count; } void print_t() //打印token对象; { std::printf("the token:"); std::cout << token; std::cout << "\t\t"; std::cout << "the count:"; std::cout << count << std::endl; } };
根据Token类构造链表,对输入的字符串进行分割,每个单词作为一个Token对象存储,计算词频;
从第一个句子开始,将head指针指向第一个单词的Token对象,此后head指针保持不变,随后每次分割出一个单词都要从链表头开始进行检测,如果有相同的单词存在,则单词数加一,如果不存在,则构造新的Token对象存储。对于这种检测方法,如果文档长且重复词少,则越到后面所需时间越长,以后可以用新的算法代替。
void Analy(char * s1) //对输入的字符串进行分割,每个单词作为一个Token对象存储,计算词频; { char* c = strtok(s1, d); while (c) { Token *temp = new Token(c); //Token temp(c); if (head == NULL) { head = temp; curr = temp; } else { if (!search(head, c)) //search函数检查单词c是否已存在链表中; { curr->next = temp; curr = temp; } } c = strtok(NULL, d); } }
打下划线的那一行代码,一开始犯了个小错误,直接声明了temp的Token对象,然后head和curr指针是对temp的引用(head=&temp,curr=&temp),这样head和curr直接指向了temp的地址空间,curr发生了移动,head也跟着动;
Token *temp = new Token(c); 这种方式则是生成一个Token对象再将地址存在temp中,指针之间可以赋值,对象和指针之间只能引用。
内存图如下:
到目前为止,一切都是很顺利的,之前的函数都是直接定义一个字符数组进行测试的,结果符合预想,接下来是将直接定义的字符数组换成从一个文档中读取一行数据进行分析,但是此处有bug,对于多行文档,结果总是出错,最后一行的数据会覆盖前面几行的单词,但是单词的数目是正确的,今天的工作到此为止,总结一下今天所学:
1.类对象和类指针的使用,也就是上面所提到的是直接生成类对象,还是用指针来使用类对象,这个要视情况而定,两个都有固定的存储空间;
2.strlen()函数返回数组中元素个数;
Sizeof()函数返回字符数组中所有元素所占的总字节数;
Sizeof(string)返回的是一个string对象所占的字节数,是一个固定值;
3.字符串切割函数
char *c=strtok(s,d)
C=strtok(null,d);
2016/3/12
用了一天调试程序,终于解决了bug;
问题主要是token的存储方式不对,
private:
char *token; //存储每个单词 改为char token[20];
int count; //存储单词出现的次数
在循环中定义一个字符数组s[80]存储每次从文档中getline的一行数据,再将这一行数据以指针形式传给Anlay函数处理,Token对象中的token指针指向切割后的字符串;每次循环s[]数组都会被重新生成和回收,所以token指针指向的数据区就发生了变化,因此作为存储还是要有自己的空间才好。