Я пишу программу, которая читает слова из текстового файла и помещает все эти слова в связанный список. В файле нет знаков препинания, только слова. Я также хочу сравнить связанный список с предварительно загруженным черным списком, который также является связанным списком.
Что я сделал, так это то, что я могу загрузить список ссылок из файла, распечатать список ссылок, проверить размер, посчитать частоту появления слова в файле, не распечатать слова, которые ниже указанной частоты, и Я также смог отформатировать все слова в нижний регистр для лучшей обработки.
У меня проблема с получением правильного кода, чтобы он печатал вхождение слова только один раз с несколькими частотами. Так что, если слово «the» появляется 20 раз, я не хочу, чтобы оно печатало <1> «тогда» <2> «в следующий раз, когда он появится, ясно» <20> «Я просто хочу напечатать один раз» <20>»
Я публикую свою функцию загрузки файла, функции печати и вставки функций слова, все части class wordCloud()
,
Ниже приведен код:
void wordCloud::insertWord(string aWord){
wordNode *newWord = new wordNode(aWord);
//old code
if (head == NULL)
head = newWord;
else{
newWord->next = head;
head = newWord;
}
//revised code
//newWord->next = head;
//head = newWord;
size++;
}
void wordCloud::insertWordDistinct(string word){
for (wordNode *temp = head; temp != NULL; temp = temp->next){
if (word == temp->myWord){
temp->freq_count++;
//cout << temp->freq_count; //for debugging
}
}
insertWord(word);
}
void wordCloud::printWordCloud(int freq){
wordNode *temp, *previous;
int listSize = 0;
if (head == NULL) //determines if there are any words in the list
cout << "No Word Cloud" << endl;
else{
temp = head;
while (temp->next != NULL){ //prints each word until the list is NULL
if (temp->freq_count >= freq){
cout << temp->myWord << " <" << temp->freq_count << ">" << endl;
temp = temp->next;
listSize++;
}
else{
previous = temp;
temp = temp->next;
previous = NULL;
free(previous);
}
}
}
cout << "\nThere are " << size << " words in the file.\n"; //print file size - for debugging - works
cout << "\nThere are " << listSize << " words in the list\n\n"; //print list size - for debugging - works
system("pause");
}
void wordCloud::printBlacklist(){
wordNode *temp;
if (head == NULL) //determines if there is a list
cout << "No Words in the blacklist" << endl;
else{
temp = head;
while (temp != NULL){ //prints each word until the list is NULL
cout << temp->myWord << endl;
temp = temp->next;
}
}
cout << "\nThere are " << size << " words in the file.\n\n"; //print size - for debugging - works
system("pause");
}
void wordCloud::loadWordCloud(string fileName){
ifstream file; //variable for fileName
string word; //string to hold each word
file.open(fileName); //open file
if (!file) { //error handling
cout << "Error: Can't open the file. File may not exist.\n";
exit(1);
}
while (!file.eof()){
file >> word; //grab a word from the file one at a time
insertWordDistinct(changeToLowerCase(word));
//insertWord(word); //for debugging
//cout << word <<'\n'; //print word - for debugging
}
//printWordCloud(); //print word cloud - for debugging - works
file.close(); //always make sure to close file after read
}
void wordCloud::loadBlacklist(string fileName){
ifstream file; //variable for fileName
string bannedWord; //string to hold each word
file.open(fileName); //open file
if (!file) { //error handling if file does not load
cout << "Error: Can't open the file. File may not exist.\n";
exit(1);
}
while (!file.eof()){
file >> bannedWord; //grab a word from the file one at a time
if (bannedWord.empty()){ //error handling if file is empty
cout << "File is empty!!\n";
exit(1);
}
insertWord(changeToLowerCase(bannedWord));
//cout << bannedWord << '\n'; //print blacklist words - for debugging
}
//printBlacklist(); //print blacklist - for debugging - works
file.close(); //always make sure to close file after read
}
Я замечаю, что если я поставлю previous = NULL
до free()
, что моя программа не падает, и я не получаю никаких ошибок обработки памяти DLL. На самом деле, я могу взять free()
полностью и, кажется, работает просто отлично. Я просто не знаю, является ли это правильным способом сделать это вообще. Мне кажется, что если я просто укажу узел на NULL< что он не обязательно удалит данные в памяти. Я просто беспокоюсь, не используя free()
или же delete()
завершить узел. Поправь меня, если я ошибаюсь, или, пожалуйста, прямо укажи мне право.
Довольно много, что не так с этим:
wordNode *previous, *temp = head;
while (temp != NULL){
if (word == temp->myWord){
temp->freq_count++;
previous = temp;
temp = temp->next;
delete(previous);
}
}
Возможно, я ошибаюсь, но в основном мне просто нужно найти частоту каждого слова, вставляемого в список, а затем удалить несколько узлов, содержащих это слово, до тех пор, пока для печати не останется только узел с наибольшим количеством частот. Я пытаюсь сделать это в insertWordDistinct(string word)
чтобы сделать это. Просто не уверен, как это сделать.
Ваш цикл печати не оказывает вам никакой пользы. Это должна быть простая перечислительная фильтрация на минимальной частоте. не должно быть никакого удаления, освобождения или иного управления памятью. Просто пройдитесь по списку:
void wordCloud::printWordCloud(int freq)
{
int listSize = 0;
int uniqSize = 0;
for (wordNode *temp = head; temp; temp = temp->next)
{
if (temp->freq_count >= freq)
{
cout << temp->myWord << " <" << temp->freq_count << ">" << endl;
listSize += temp->freq_count;
++uniqSize;
}
}
cout << "\nThere are " << size << " words in the file.\n";
cout << "\nThere are " << listSize << " words in the filtered list\n\n";
cout << "\nThere are " << uniqSize << " unique words in the filtered list\n\n";
system("pause");
}
Это также должно вернуть вас к правильному управлению списками в wordCloud::~wordCloud()
деструктор, чтобы еще раз правильно удалить узлы. Есть много других вещей, которые я бы сделал по-другому, но это процесс обучения, поэтому я не собираюсь портить вашу вечеринку.
Обновить
В соответствии с запросом от OP ниже приведена примерная функция вставки связанного списка, которая сортирует вставку при построении списка. Приспосабливая это, он идентифицировал существенные различия и проблемы с оригинальной реализацией. Надеюсь, это поможет кому-то еще.
void wordCloud::insert(const std::string& aWord, unsigned int freq)
{
// manufacture lower-case version of word;
std::string lcaseWord = make_lower(aWord);
// search for the word by walking a pointer-to-pointer
// through the pointers in the linked list.
wordNode** pp = &head;
while (*pp && ((*pp)->myWord < lcaseWord)
pp = &(*pp)->next;
if (*pp && !(lcaseWord < (*pp)->myWord))
{
(*pp)->freq_count++;
}
else
{ // insert the node
wordNode *node = new wordNode(lcaseWord);
node->freq_count = freq;
node->next = *pp;
*pp = node;
++size;
}
}
Я думаю, что для печати только одного раза каждое слово вы должны составить уникальный список, в котором будут слова из вашего исходного списка с количеством появлений из них. Для этого вам просто нужно две петли. Один для получения каждого слова из исходного списка, а второй — для проверки наличия слова в уникальном списке. Для этого вы должны составить второй список и скопировать каждое слово один раз, если слово встречается более одного раза, вы просто увеличиваете частоту.