как решить проблему с индексацией и сортировкой - PullRequest
0 голосов
/ 04 ноября 2019

У меня проблема. Есть текстовый файл, вам нужно найти 5 часто встречающихся слов. Программа получает имя файла. Вывод: топ 5 слов в алфавитном порядке. Проблема в том, что индексы не обновляются и сортируются криво. Помоги мне, пожалуйста. заранее спасибо. Это код:

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

const int MAX = 100000;
string words[MAX];
int instances[MAX];
int cast = 0 ;

void insert (string input)
{
    for (int i = 0 ; i < cast; i++ )
    {
        if (input == words[i] )
        {
            instances[i]++;
            return ;
        }
    }
    if (cast < MAX)
    {
        words [cast] = input ;
        instances[cast] = 1;
        cast ++;
    }
    else
    {
        return ;
    }
 return ;
}
int FindTop (string & word)
{
    int TopCast = instances[0];
    int TopIndex = 0;
    for (int i = 1; i<cast; i++ )
    {
        if(instances[i] > TopCast )
        {
            TopCast = instances[i];
            TopIndex = i;
        }
    }
    instances[TopIndex] = 0;
    word = words[TopIndex ];
    return TopCast;
}
int main ()
{
    string word;
    string file;
    cin>>file;
    ifstream data (file);
    while(data >> word)
    {
        insert(word);
    }

    for (int i = 0; i < 5 ; i++)
    {
        cout<<FindTop(word)<<" "<<word<<endl;
    }
}

Ответы [ 4 ]

1 голос
/ 04 ноября 2019

Обновите функцию FindTop () следующим образом

        int FindTop (string & word)
        {
            int TopCast = instances[0];
            int TopIndex = 0;
            for (int i = 1; i<cast; i++ )
            {
                if(instances[i] > TopCast )
                {
                    TopCast = instances[i];
                    TopIndex = i;
                }    
                else if(TopCast == instances[i])  
                {
                     //for making sure you get the smallest word (asc order) first if multiple words   
                     // have same frequency
                    if( words[TopIndex].compare(words[i]) > 0 )
                    {
                      TopCast = instances[i];
                      TopIndex = i;
                    }
                }
            }
            instances[TopIndex] = 0;
            word = words[TopIndex ];
            return TopCast;
        }
0 голосов
/ 04 ноября 2019

Так как ваш пример больше похож на C-ish, я хотел бы показать вам мое понимание проблемы.

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

#include <algorithm> // sort
#include <cstdlib> // EXIT_FAILURE, EXIT_SUCCESS
#include <fstream> // ifstream
#include <iostream> // cin, cout
#include <string> // string
#include <unordered_map> // unordered_map
#include <utility> // pair
#include <vector> // vector

using namespace std;

int main()
{
    cout << "Filename: ";
    string filename;
    cin >> filename;

    ifstream file{filename};
    // Check that the file was opened successfully.
    if (!file) {
        cout << "File cannot be opened for reading: " << filename << '\n';
        return EXIT_FAILURE;
    }

    // Count the words in the file.
    // unordered_map is an associative container that stores key-value pairs
    // with unique keys. We use this to store word-occurrence pairs.
    unordered_map<string, int> words;
    for (string word; file >> word;)
        // By default if 'word' is not contained in 'words' it will be placed
        // there with the default value of 0 (default value of ints). This allow
        // us the eliminate the special case when 'word' is not in 'words' yet.
        ++words[word];

    // Sort the word-occurrence pairs in descending order by occurrence.
    // vector is a dynamic array that we use to sort the word-occurrence pairs
    // because unordered_map cannot be sorted.
    vector<std::pair<string, int>> sorted_words{words.begin(), words.end()};
    // The sort algorithm takes the begining and the end of the interval that we
    // want to sort. As a third argument we pass it a lamda function that tells
    // the algorithm how to order our word-occurrence pairs.
    sort(sorted_words.begin(), sorted_words.end(), [](const auto& a, const auto& b) {
        return a.second > b.second;
    });
    // Sort the first 5 (most frequent) words in alphabetic order.
    sort(sorted_words.begin(), sorted_words.begin() + 5, [](const auto& a, const auto& b) {
        return a.first < b.first;
    });

    for (auto i = 0; i < 5 && i < sorted_words.size(); ++i)
        cout << sorted_words[i].first << '\n';

    return EXIT_SUCCESS;
}
0 голосов
/ 04 ноября 2019

Я хотел бы предоставить дополнительное решение.

Это не на основе вашего первоначального черновика, а с более современным решением на C ++, использующим контейнеры и алгоритмы STL.

Я бы хотелНастоятельно рекомендуем НЕ использовать массивы C-Style вообще. Пожалуйста, используйте контейнеры STL.

Тогда вернемся к вашей проблеме. Мы разделим задачу в основном на 3 задачи.

  • Чтение файла
  • Подсчет слов
  • Сортировка

Чтение файла в словаэто ультра просто. Просто используйте оператор экстрактора и получите слова как std:string из текста. Слова могут содержать не буквенные символы. Это мы исключим с помощью std::regex_replace.

Подсчет также очень прост. Мы используем оператор индекса std::map []. Это создаст слово в std::map, если оно еще не существует````, и увеличит счетчик. Если слово уже существует, то будет просто увеличение счетчика для этого слова.

Поскольку std::map по умолчанию отсортировано по ключевому значению (слову), мы копируем количество словв std::vector, затем отсортируйте его и покажите результат.

См.

#include <iostream>
#include <sstream>
#include <iterator>
#include <string>
#include <array>
#include <algorithm>
#include <regex>
#include <map>
#include <iomanip>
#include <utility>

std::istringstream sourceFile{R"(Lorem ipsum dolor sit amet, 
consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt
ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero
eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum
dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod 
tempor invidunt ut labore et dolore magna aliquyam erat, sed diam 
voluptua. At vero eos et accusam et justo duo dolores et ea rebum. 
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum 
dolor sit amet.)"
};


int main() {

    std::string word{};
    std::map<std::string, size_t> counter;

    // Read complete file into words
    while(sourceFile >> word) {
        // Replace special characters
        word = std::regex_replace(word,std::regex(R"([\.\,\;\:\!\?])"),"");
        // Count the occurence of each word
        counter[word]++;
    }

    // We need to sort and will copy the word-counts into a vector
    std::vector<std::pair<size_t, std::string>> countedWords;
    for( auto const& [key, val] : counter ) {
        countedWords.emplace_back(std::pair<size_t, std::string>(val,key));
    }

    // Do the sort, with a lambda, for the specific request
    std::sort(countedWords.begin(), countedWords.end(), 
         [](std::pair<size_t, std::string> &l, std::pair<size_t, std::string> &r){
        return ((r.first == l.first) ? (l.second < r.second) : (r.first < l.first));});



    // Show result on screen
    int outputCounter{ 5 };
    for (const auto& [word, count] : countedWords) {
        std::cout << std::setw(20) << word << " --> " << count << "\n";
        if (0 >= --outputCounter) break;
    }

    // Output all words
    std::cout << "\n\nAll different word in alphabetical order:\n\n";

    // Write all words on screen.
    for (const auto& [word, count] : counter)   std::cout << word << "\n";

    return 0;
}

РЕДАКТИРОВАТЬ:

В конце я добавил вывод для всех слов вв алфавитном порядке.

Дополнительно: Обратите внимание: std::istringstream - это std::istream. Нет разницы в файловом потоке. Таким образом, «sourceFile» может быть открытым std::ifstream или std::cin или любым другим std::istream. Нет никакой разницы. Итак, откройте файл, используя std::ifstream sourceFile("c:\\temp\nameOfFile") - Вот и все.

0 голосов
/ 04 ноября 2019

Функция вставки работает как задумано. Однако, если спрос на самом деле составляет первые 5 слов, в соответствии с вхождением, отсортированными в алфавитном порядке, вы можете сохранить слова в векторе и отсортировать их в алфавитном порядке, используя функцию сравнения строк, созданную самим собой.

Если каким-то образом вы не получаете первые 5 слов, проверьте, находится ли ваш текстовый файл в правильном каталоге и записали ли вы правильное имя файла в консоль.

Пожалуйста, предоставьте короткий текстовый файл и вывод для консоли.

...