giGii

ранжирование1.0

Aug 21st, 2022
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.77 KB | None | 0 0
  1. #include <algorithm>
  2. #include <iostream>
  3. #include <set>
  4. #include <map>
  5. #include <string>
  6. #include <utility>
  7. #include <vector>
  8. #include <cmath>
  9.  
  10. using namespace std;
  11.  
  12. const int MAX_RESULT_DOCUMENT_COUNT = 5;
  13.  
  14. string ReadLine() {
  15.     string s;
  16.     getline(cin, s);
  17.     return s;
  18. }
  19.  
  20. int ReadLineWithNumber() {
  21.     int result = 0;
  22.     cin >> result;
  23.     ReadLine();
  24.     return result;
  25. }
  26.  
  27. vector<string> SplitIntoWords(const string& text) {
  28.     vector<string> words;
  29.     string word;
  30.     for (const char c : text) {
  31.         if (c == ' ') {
  32.             if (!word.empty()) {
  33.                 words.push_back(word);
  34.                 word.clear();
  35.             }
  36.         } else {
  37.             word += c;
  38.         }
  39.     }
  40.     if (!word.empty()) {
  41.         words.push_back(word);
  42.     }
  43.  
  44.     return words;
  45. }
  46.  
  47. struct Document {
  48.     int id;
  49.     double relevance;
  50. };
  51.  
  52. class SearchServer {
  53. public:
  54.     void SetStopWords(const string& text) {
  55.         for (const string& word : SplitIntoWords(text)) {
  56.             stop_words_.insert(word);
  57.         }
  58.     }
  59.  
  60.     void AddDocument(int document_id, const string& document) {
  61.  
  62.         // наполняем счетчик документов -- он пригодится для подсчета IDF-TF.
  63.         ++document_count_;
  64.  
  65.         /* так как для подсчета доли слова в документе (TF) важны также повторения слова,
  66.         то индекс должен содержать не только документы, в которых есть слово, но также
  67.         и количесвто этого слова в документе;
  68.         то есть была структура map<string, set<int>> index_,
  69.         станет структура map<string, map<int, int>> index_.
  70.         */
  71.         const vector<string> words = SplitIntoWordsNoStop(document);
  72.  
  73.         // каждому документу надо сопоставить его длину -- пригодится при подсчете TF, стоп-слова в длину документа не входят, их уже отфильтровало к этому моменту.
  74.         documents_length_[document_id] = words.size();
  75.  
  76.         /* for (string word : words) { // ругалось на скорость наверное потому что ссылку забыл.
  77.             if (stop_words_.count(word) == 0) { // плюс зачем же я еще раз проверяю на стоп-слово, если с учетом их уже все вернулось из SplitIntoWordsNoStop.
  78.                 ++index_[word][document_id];
  79.             }
  80.         } */
  81.  
  82.         for (const string& word : words) { // сделал ссылку.
  83.             ++index_[word][document_id]; // убрал лишнюю проверку, не в стоп ли словах слово -- это же многочисленный подсчет хэша.
  84.         }
  85.     }
  86.  
  87.     vector<Document> FindTopDocuments(const string& raw_query) const {
  88.         const PlusMinusWords query_words = ParseQuery(raw_query);
  89.  
  90.         auto matched_documents = FindAllDocuments(query_words);
  91.  
  92.         sort(matched_documents.begin(), matched_documents.end(),
  93.              [](const Document& lhs, const Document& rhs) {
  94.                  return lhs.relevance > rhs.relevance;
  95.              });
  96.         if (matched_documents.size() > MAX_RESULT_DOCUMENT_COUNT) {
  97.             matched_documents.resize(MAX_RESULT_DOCUMENT_COUNT);
  98.         }
  99.         return matched_documents;
  100.     }
  101.  
  102. private:
  103.  
  104.     struct PlusMinusWords {
  105.         set<string> plus_words;
  106.         set<string> minus_words;
  107.     };
  108.  
  109.     int document_count_ = 0;
  110.  
  111.     map<int, int> documents_length_;
  112.  
  113.     map<string, map<int, int>> index_;
  114.  
  115.     set<string> stop_words_;
  116.  
  117.     bool IsStopWord(const string& word) const {
  118.         return stop_words_.count(word) > 0;
  119.     }
  120.  
  121.     vector<string> SplitIntoWordsNoStop(const string& text) const {
  122.         vector<string> words;
  123.         for (const string& word : SplitIntoWords(text)) {
  124.             if (!IsStopWord(word)) {
  125.                 words.push_back(word);
  126.             }
  127.         }
  128.         return words;
  129.     }
  130.  
  131.     PlusMinusWords ParseQuery(const string& text) const {
  132.         PlusMinusWords query_words;
  133.         for (const string& word : SplitIntoWordsNoStop(text)) {
  134.             if (word[0] == '-') {
  135.                 query_words.minus_words.insert(word.substr(1, word.size()));
  136.             } else {
  137.                 if (query_words.minus_words.count(word) == 0) {
  138.                     query_words.plus_words.insert(word);
  139.                 }
  140.             }
  141.         }
  142.         return query_words;
  143.     }
  144.  
  145.     vector<Document> FindAllDocuments(const PlusMinusWords& query_words) const {
  146.  
  147.         /* Рассчитываем IDF каждого слова в запросе:
  148.         1) количество документов document_count_ делим на количество документов,
  149.             где это слово встречается index_.at(word).size();
  150.         2) берем от полученного значения log.
  151.  
  152.         Функция AddDocument построила index_, им удобно воспользоваться.
  153.         */
  154.  
  155.         map<string, double> idf; // в результате получим слово из запроса и его посчитанный IDF (не факт, что все слова из запроса обрели IDF, ведь слова может не быть в индексе, а значит знаменателя нет).
  156.         for (const string& word : query_words.plus_words) {
  157.             if (index_.count(word) != 0) { // если слово есть в индексе, значит можно быстро понять, в скольких документах оно есть -- index_.at(word).size().
  158.                 idf[word] = log(static_cast<double>(document_count_) / index_.at(word).size());
  159.             }
  160.         }
  161.  
  162.         /* Рассчитываем TF каждого слова в запросе в каждом документе документах:
  163.         1) берем word из запроса;
  164.         2) из index_ получаем по этому word словарь, где номеру документа document_id
  165.             соответствует количество этого word -- word_amount;
  166.         3) делим word_amount на количество слов в документе, которые еще при добавлении
  167.             документов в index_ записали для каждого документа -- это есть TF этого слова
  168.             в этом документе.
  169.        
  170.         Функция AddDocument построила index_, им снова удобно воспользоваться.
  171.         */
  172.  
  173.         map<string, map<int, double>> tf; // в результате получим слово из запроса, которое есть в индексе, и документы, в которых у него посчитан TF.
  174.         for (const string& word : query_words.plus_words) {
  175.             if (index_.count(word) != 0) { // слово есть в индексе, значит есть документы, в которых обозначаено количество этого слова.
  176.                 for (const auto& [document_id, word_amount] : index_.at(word)) {
  177.                     tf[word][document_id] = static_cast<double>(word_amount) / documents_length_.at(document_id);
  178.                 }
  179.             }
  180.         }
  181.  
  182.         /* условие  (index_.count(word) != 0) есть и при подсчете IDF, и при подсчете TF, значит
  183.         в словарях idf и tf одинаковые ключи, можно идти по idf, имея слово и сам idf, получать по слову
  184.         номер документа и tf этого слова в этом документе и плюсовать по ключу-номеру документа
  185.         произведение idf * tf.
  186.         */
  187.  
  188.         map<int, double> matched_documents;
  189.  
  190.         for (const auto& [word, idf] : idf) {
  191.             for (const auto& [document_id, tf] : tf.at(word)) {
  192.                 matched_documents[document_id] += idf * tf;
  193.             }
  194.         }
  195.  
  196.         /* теперь надо пройтись по минус словам посмотреть при помощи индекса,
  197.         какие документы есть по этому слову, и вычеркнуть их из выдачи.
  198.         */
  199.  
  200.         for (const string& word : query_words.minus_words) {
  201.             if (index_.count(word) != 0) {
  202.                 for (const auto& [documents_id, word_amount] : index_.at(word)) {
  203.                     if (matched_documents.count(documents_id) != 0) {
  204.                         matched_documents.erase(documents_id);
  205.                     }
  206.  
  207.                 }
  208.             }
  209.         }
  210.  
  211.         /* скопируем ответ в правильную структуру (не тут ли проблема со временем? может
  212.         только 5 документов надо копировать?).
  213.         */
  214.         vector<Document> result;
  215.  
  216.         for (const auto& [key, value] : matched_documents) {
  217.             Document doc_rel;
  218.             doc_rel.id = key;
  219.             doc_rel.relevance = value;
  220.             result.push_back(doc_rel);
  221.         }
  222.  
  223.         return result;
  224.     }
  225. };
  226.  
  227. SearchServer CreateSearchServer() {
  228.     SearchServer search_server;
  229.     search_server.SetStopWords(ReadLine());
  230.  
  231.     const int document_count = ReadLineWithNumber();
  232.     for (int document_id = 0; document_id < document_count; ++document_id) {
  233.         search_server.AddDocument(document_id, ReadLine());
  234.     }
  235.  
  236.     return search_server;
  237. }
  238.  
  239. int main() {
  240.  
  241.     const SearchServer search_server = CreateSearchServer();
  242.  
  243.     const string query = ReadLine();
  244.  
  245.     for (const auto& [document_id, relevance] : search_server.FindTopDocuments(query)) {
  246.         cout << "{ document_id = "s << document_id << ", "
  247.              << "relevance = "s << relevance << " }"s << endl;
  248.     }
  249. }
  250.  
  251. /*
  252. с в на вы около без
  253. 14
  254. очень красивый прям очень красивый пёс найден в лесу около дом книги
  255. голубая канарейка плавает в озере в утками кто потерял идите в парк победы
  256. белый кот ходит вокруг дом быт
  257. кот красивый без ошейника с дырявым ухом с стриженными ногтями
  258. дог с красивыми стриженными волосами убежал в районе ломоносовская
  259. найден домашний таракан с усами
  260. собака потеряшка ломоносовская
  261. грязный кот ошивается около телебашни
  262. ухоженный ребенок породы хаски временно живет на жд станции буратино
  263. голубая канарейка и таракан нашли друг в друге хозяев на станции парнас
  264. красивый африканский морж скоро приедет в зоопарк
  265. ухоженный заяц с дырявым ухом ищет хозяев
  266. родители вы в своем уме найден ребенок внимание найден ребенок родители отзовитесь
  267. хороший мультфильм ремейк буратино выходит на наших радиостанциях
  268. пропал ребенок помогите найти где он ошивается он наш друг с дырявым пальцем -кот
  269.  
  270. s v na vy okolo bez
  271. 14
  272. ochen krasivyj pryam ochen krasivyj pes najden v lesu okolo dom knigi
  273. golubaya kanarejka plavaet v ozere v utkami kto poteryal idite v park pobedy
  274. belyj kot hodit vokrug dom byt
  275. kot krasivyj bez oshejnika s dyryavym uhom s strizhennymi nogtyami
  276. dog s krasivymi strizhennymi volosami ubezhal v rajone lomonosovskaya
  277. najden domashnij tarakan s usami
  278. sobaka poteryashka lomonosovskaya
  279. gryaznyj kot oshivaetsya okolo telebashni
  280. uhozhennyj rebenok porody haski vremenno zhivet na zhd stancii buratino
  281. golubaya kanarejka i tarakan nashli drug v druge hozyaev na stancii parnas
  282. krasivyj afrikanskij morzh skoro priedet v zoopark
  283. uhozhennyj zayac s dyryavym uhom ishchet hozyaev
  284. roditeli vy v svoem ume najden rebenok vnimanie najden rebenok roditeli otzovites
  285. horoshij multfilm remejk buratino vyhodit na nashih radiostanciyah
  286. propal rebenok pomogite najti gde on oshivaetsya on nash drug s dyryavym palcem -kot
  287. */
Advertisement
Add Comment
Please, Sign In to add comment