Advertisement
chevengur

СПРИНТ № 5 | Стек, очередь, дек | Урок 4: Очередь запросов

Mar 7th, 2024
742
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 16.22 KB | Source Code | 0 0
  1. #include <algorithm>
  2. #include <cmath>
  3. #include <iostream>
  4. #include <map>
  5. #include <set>
  6. #include <stdexcept>
  7. #include <string>
  8. #include <utility>
  9. #include <vector>
  10. #include <deque>
  11.  
  12. using namespace std;
  13.  
  14. const int MAX_RESULT_DOCUMENT_COUNT = 5;
  15.  
  16. string ReadLine() {
  17.     string s;
  18.     getline(cin, s);
  19.     return s;
  20. }
  21.  
  22. int ReadLineWithNumber() {
  23.     int result;
  24.     cin >> result;
  25.     ReadLine();
  26.     return result;
  27. }
  28.  
  29. vector<string> SplitIntoWords(const string& text) {
  30.     vector<string> words;
  31.     string word;
  32.     for (const char c : text) {
  33.         if (c == ' ') {
  34.             if (!word.empty()) {
  35.                 words.push_back(word);
  36.                 word.clear();
  37.             }
  38.         }
  39.         else {
  40.             word += c;
  41.         }
  42.     }
  43.     if (!word.empty()) {
  44.         words.push_back(word);
  45.     }
  46.  
  47.     return words;
  48. }
  49.  
  50. struct Document {
  51.     Document() = default;
  52.  
  53.     Document(int id, double relevance, int rating)
  54.         : id(id)
  55.         , relevance(relevance)
  56.         , rating(rating) {
  57.     }
  58.  
  59.     int id = 0;
  60.     double relevance = 0.0;
  61.     int rating = 0;
  62. };
  63.  
  64. ostream& operator<<(ostream& out, const Document& document) {
  65.     out << "{ "s
  66.         << "document_id = "s << document.id << ", "s
  67.         << "relevance = "s << document.relevance << ", "s
  68.         << "rating = "s << document.rating << " }"s;
  69.     return out;
  70. }
  71.  
  72. template <typename StringContainer>
  73. set<string> MakeUniqueNonEmptyStrings(const StringContainer& strings) {
  74.     set<string> non_empty_strings;
  75.     for (const string& str : strings) {
  76.         if (!str.empty()) {
  77.             non_empty_strings.insert(str);
  78.         }
  79.     }
  80.     return non_empty_strings;
  81. }
  82.  
  83. enum class DocumentStatus {
  84.     ACTUAL,
  85.     IRRELEVANT,
  86.     BANNED,
  87.     REMOVED,
  88. };
  89.  
  90. class SearchServer {
  91. public:
  92.     template <typename StringContainer>
  93.     explicit SearchServer(const StringContainer& stop_words)
  94.         : stop_words_(MakeUniqueNonEmptyStrings(stop_words))  // Extract non-empty stop words
  95.     {
  96.         if (!all_of(stop_words_.begin(), stop_words_.end(), IsValidWord)) {
  97.             throw invalid_argument("Some of stop words are invalid"s);
  98.         }
  99.     }
  100.  
  101.     explicit SearchServer(const string& stop_words_text)
  102.         : SearchServer(SplitIntoWords(stop_words_text))  // Invoke delegating constructor
  103.         // from string container
  104.     {
  105.     }
  106.  
  107.     void AddDocument(int document_id, const string& document, DocumentStatus status, const vector<int>& ratings) {
  108.         if ((document_id < 0) || (documents_.count(document_id) > 0)) {
  109.             throw invalid_argument("Invalid document_id"s);
  110.         }
  111.         const auto words = SplitIntoWordsNoStop(document);
  112.  
  113.         const double inv_word_count = 1.0 / words.size();
  114.         for (const string& word : words) {
  115.             word_to_document_freqs_[word][document_id] += inv_word_count;
  116.         }
  117.         documents_.emplace(document_id, DocumentData{ ComputeAverageRating(ratings), status });
  118.         document_ids_.push_back(document_id);
  119.     }
  120.  
  121.     template <typename DocumentPredicate>
  122.     vector<Document> FindTopDocuments(const string& raw_query, DocumentPredicate document_predicate) const {
  123.         const auto query = ParseQuery(raw_query);
  124.  
  125.         auto matched_documents = FindAllDocuments(query, document_predicate);
  126.  
  127.         sort(matched_documents.begin(), matched_documents.end(), [](const Document& lhs, const Document& rhs) {
  128.             if (abs(lhs.relevance - rhs.relevance) < 1e-6) {
  129.                 return lhs.rating > rhs.rating;
  130.             }
  131.             else {
  132.                 return lhs.relevance > rhs.relevance;
  133.             }
  134.             });
  135.         if (matched_documents.size() > MAX_RESULT_DOCUMENT_COUNT) {
  136.             matched_documents.resize(MAX_RESULT_DOCUMENT_COUNT);
  137.         }
  138.  
  139.         return matched_documents;
  140.     }
  141.  
  142.     vector<Document> FindTopDocuments(const string& raw_query, DocumentStatus status) const {
  143.         return FindTopDocuments(raw_query, [status](int document_id, DocumentStatus document_status, int rating) {
  144.             return document_status == status;
  145.             });
  146.     }
  147.  
  148.     vector<Document> FindTopDocuments(const string& raw_query) const {
  149.         return FindTopDocuments(raw_query, DocumentStatus::ACTUAL);
  150.     }
  151.  
  152.     int GetDocumentCount() const {
  153.         return documents_.size();
  154.     }
  155.  
  156.     int GetDocumentId(int index) const {
  157.         return document_ids_.at(index);
  158.     }
  159.  
  160.     tuple<vector<string>, DocumentStatus> MatchDocument(const string& raw_query, int document_id) const {
  161.         const auto query = ParseQuery(raw_query);
  162.  
  163.         vector<string> matched_words;
  164.         for (const string& word : query.plus_words) {
  165.             if (word_to_document_freqs_.count(word) == 0) {
  166.                 continue;
  167.             }
  168.             if (word_to_document_freqs_.at(word).count(document_id)) {
  169.                 matched_words.push_back(word);
  170.             }
  171.         }
  172.         for (const string& word : query.minus_words) {
  173.             if (word_to_document_freqs_.count(word) == 0) {
  174.                 continue;
  175.             }
  176.             if (word_to_document_freqs_.at(word).count(document_id)) {
  177.                 matched_words.clear();
  178.                 break;
  179.             }
  180.         }
  181.         return { matched_words, documents_.at(document_id).status };
  182.     }
  183.  
  184. private:
  185.     struct DocumentData {
  186.         int rating;
  187.         DocumentStatus status;
  188.     };
  189.     const set<string> stop_words_;
  190.     map<string, map<int, double>> word_to_document_freqs_;
  191.     map<int, DocumentData> documents_;
  192.     vector<int> document_ids_;
  193.  
  194.     bool IsStopWord(const string& word) const {
  195.         return stop_words_.count(word) > 0;
  196.     }
  197.  
  198.     static bool IsValidWord(const string& word) {
  199.         // A valid word must not contain special characters
  200.         return none_of(word.begin(), word.end(), [](char c) {
  201.             return c >= '\0' && c < ' ';
  202.             });
  203.     }
  204.  
  205.     vector<string> SplitIntoWordsNoStop(const string& text) const {
  206.         vector<string> words;
  207.         for (const string& word : SplitIntoWords(text)) {
  208.             if (!IsValidWord(word)) {
  209.                 throw invalid_argument("Word "s + word + " is invalid"s);
  210.             }
  211.             if (!IsStopWord(word)) {
  212.                 words.push_back(word);
  213.             }
  214.         }
  215.         return words;
  216.     }
  217.  
  218.     static int ComputeAverageRating(const vector<int>& ratings) {
  219.         if (ratings.empty()) {
  220.             return 0;
  221.         }
  222.         int rating_sum = 0;
  223.         for (const int rating : ratings) {
  224.             rating_sum += rating;
  225.         }
  226.         return rating_sum / static_cast<int>(ratings.size());
  227.     }
  228.  
  229.     struct QueryWord {
  230.         string data;
  231.         bool is_minus;
  232.         bool is_stop;
  233.     };
  234.  
  235.     QueryWord ParseQueryWord(const string& text) const {
  236.         if (text.empty()) {
  237.             throw invalid_argument("Query word is empty"s);
  238.         }
  239.         string word = text;
  240.         bool is_minus = false;
  241.         if (word[0] == '-') {
  242.             is_minus = true;
  243.             word = word.substr(1);
  244.         }
  245.         if (word.empty() || word[0] == '-' || !IsValidWord(word)) {
  246.             throw invalid_argument("Query word "s + text + " is invalid");
  247.         }
  248.  
  249.         return { word, is_minus, IsStopWord(word) };
  250.     }
  251.  
  252.     struct Query {
  253.         set<string> plus_words;
  254.         set<string> minus_words;
  255.     };
  256.  
  257.     Query ParseQuery(const string& text) const {
  258.         Query result;
  259.         for (const string& word : SplitIntoWords(text)) {
  260.             const auto query_word = ParseQueryWord(word);
  261.             if (!query_word.is_stop) {
  262.                 if (query_word.is_minus) {
  263.                     result.minus_words.insert(query_word.data);
  264.                 }
  265.                 else {
  266.                     result.plus_words.insert(query_word.data);
  267.                 }
  268.             }
  269.         }
  270.         return result;
  271.     }
  272.  
  273.     // Existence required
  274.     double ComputeWordInverseDocumentFreq(const string& word) const {
  275.         return log(GetDocumentCount() * 1.0 / word_to_document_freqs_.at(word).size());
  276.     }
  277.  
  278.     template <typename DocumentPredicate>
  279.     vector<Document> FindAllDocuments(const Query& query, DocumentPredicate document_predicate) const {
  280.         map<int, double> document_to_relevance;
  281.         for (const string& word : query.plus_words) {
  282.             if (word_to_document_freqs_.count(word) == 0) {
  283.                 continue;
  284.             }
  285.             const double inverse_document_freq = ComputeWordInverseDocumentFreq(word);
  286.             for (const auto& [document_id, term_freq] : word_to_document_freqs_.at(word)) {
  287.                 const auto& document_data = documents_.at(document_id);
  288.                 if (document_predicate(document_id, document_data.status, document_data.rating)) {
  289.                     document_to_relevance[document_id] += term_freq * inverse_document_freq;
  290.                 }
  291.             }
  292.         }
  293.  
  294.         for (const string& word : query.minus_words) {
  295.             if (word_to_document_freqs_.count(word) == 0) {
  296.                 continue;
  297.             }
  298.             for (const auto& [document_id, _] : word_to_document_freqs_.at(word)) {
  299.                 document_to_relevance.erase(document_id);
  300.             }
  301.         }
  302.  
  303.         vector<Document> matched_documents;
  304.         for (const auto& [document_id, relevance] : document_to_relevance) {
  305.             matched_documents.push_back({ document_id, relevance, documents_.at(document_id).rating });
  306.         }
  307.         return matched_documents;
  308.     }
  309. };
  310.  
  311. void PrintDocument(const Document& document) {
  312.     cout << "{ "s
  313.         << "document_id = "s << document.id << ", "s
  314.         << "relevance = "s << document.relevance << ", "s
  315.         << "rating = "s << document.rating << " }"s << endl;
  316. }
  317.  
  318. void PrintMatchDocumentResult(int document_id, const vector<string>& words, DocumentStatus status) {
  319.     cout << "{ "s
  320.         << "document_id = "s << document_id << ", "s
  321.         << "status = "s << static_cast<int>(status) << ", "s
  322.         << "words ="s;
  323.     for (const string& word : words) {
  324.         cout << ' ' << word;
  325.     }
  326.     cout << "}"s << endl;
  327. }
  328.  
  329. void AddDocument(SearchServer& search_server, int document_id, const string& document, DocumentStatus status,
  330.     const vector<int>& ratings) {
  331.     try {
  332.         search_server.AddDocument(document_id, document, status, ratings);
  333.     }
  334.     catch (const invalid_argument& e) {
  335.         cout << "Ошибка добавления документа "s << document_id << ": "s << e.what() << endl;
  336.     }
  337. }
  338.  
  339. void FindTopDocuments(const SearchServer& search_server, const string& raw_query) {
  340.     cout << "Результаты поиска по запросу: "s << raw_query << endl;
  341.     try {
  342.         for (const Document& document : search_server.FindTopDocuments(raw_query)) {
  343.             PrintDocument(document);
  344.         }
  345.     }
  346.     catch (const invalid_argument& e) {
  347.         cout << "Ошибка поиска: "s << e.what() << endl;
  348.     }
  349. }
  350.  
  351. void MatchDocuments(const SearchServer& search_server, const string& query) {
  352.     try {
  353.         cout << "Матчинг документов по запросу: "s << query << endl;
  354.         const int document_count = search_server.GetDocumentCount();
  355.         for (int index = 0; index < document_count; ++index) {
  356.             const int document_id = search_server.GetDocumentId(index);
  357.             const auto [words, status] = search_server.MatchDocument(query, document_id);
  358.             PrintMatchDocumentResult(document_id, words, status);
  359.         }
  360.     }
  361.     catch (const invalid_argument& e) {
  362.         cout << "Ошибка матчинга документов на запрос "s << query << ": "s << e.what() << endl;
  363.     }
  364. }
  365.  
  366. template <typename Iterator>
  367. class IteratorRange {
  368. public:
  369.     IteratorRange(Iterator begin, Iterator end)
  370.         : first_(begin)
  371.         , last_(end)
  372.         , size_(distance(first_, last_)) {
  373.     }
  374.  
  375.     Iterator begin() const {
  376.         return first_;
  377.     }
  378.  
  379.     Iterator end() const {
  380.         return last_;
  381.     }
  382.  
  383.     size_t size() const {
  384.         return size_;
  385.     }
  386.  
  387. private:
  388.     Iterator first_, last_;
  389.     size_t size_;
  390. };
  391.  
  392. template <typename Iterator>
  393. ostream& operator<<(ostream& out, const IteratorRange<Iterator>& range) {
  394.     for (Iterator it = range.begin(); it != range.end(); ++it) {
  395.         out << *it;
  396.     }
  397.     return out;
  398. }
  399.  
  400. template <typename Iterator>
  401. class Paginator {
  402. public:
  403.     Paginator(Iterator begin, Iterator end, size_t page_size) {
  404.         for (size_t left = distance(begin, end); left > 0;) {
  405.             const size_t current_page_size = min(page_size, left);
  406.             auto current_page_end = next(begin, current_page_size);
  407.             pages_.push_back({ begin, current_page_end });
  408.  
  409.             left -= current_page_size;
  410.             begin = current_page_end;
  411.         }
  412.     }
  413.  
  414.     auto begin() const {
  415.         return pages_.begin();
  416.     }
  417.  
  418.     auto end() const {
  419.         return pages_.end();
  420.     }
  421.  
  422.     size_t size() const {
  423.         return pages_.size();
  424.     }
  425.  
  426. private:
  427.     vector<IteratorRange<Iterator>> pages_;
  428. };
  429.  
  430. template <typename Container>
  431. auto Paginate(const Container& c, size_t page_size) {
  432.     return Paginator(begin(c), end(c), page_size);
  433. }
  434.  
  435. class RequestQueue {
  436. public:
  437.     explicit RequestQueue(const SearchServer& search_server)
  438.         : search_server_(search_server), count_request_(0) {
  439.     }
  440.  
  441.     // сделаем "обертки" для всех методов поиска, чтобы сохранять результаты для нашей статистики
  442.     template <typename DocumentPredicate>
  443.     vector<Document> AddFindRequest(const string& raw_query, DocumentPredicate document_predicate) {
  444.         const auto result = search_server_.FindTopDocuments(raw_query, document_predicate);
  445.         AddRequest(result.size());
  446.         return result;
  447.     }
  448.  
  449.     vector<Document> AddFindRequest(const string& raw_query, DocumentStatus status) {
  450.  
  451.         const auto result = search_server_.FindTopDocuments(raw_query, status);
  452.         AddRequest(result.size());
  453.         return result;
  454.     }
  455.  
  456.     vector<Document> AddFindRequest(const string& raw_query) {
  457.  
  458.         const auto result = search_server_.FindTopDocuments(raw_query);
  459.         AddRequest(result.size());
  460.         return result;
  461.     }
  462.      
  463.     int GetNoResultRequests() const {
  464.         return min_in_day_ - count_request_;
  465.     }
  466.  
  467. private:
  468.     struct QueryResult {
  469.         int req;
  470.         uint64_t timestamp;
  471.     };
  472.     deque<QueryResult> requests_;
  473.     const SearchServer& search_server_;
  474.     int count_request_ = 0;
  475.     uint64_t current_time_ = 0;
  476.     const static int min_in_day_ = 1440;
  477.    
  478.  
  479.     void AddRequest(int num_request) {
  480.         if (num_request != 0)
  481.         {
  482.             ++current_time_;
  483.             ++count_request_;
  484.             requests_.push_back({num_request, current_time_});
  485.         }  
  486.     }
  487. };
  488.  
  489. int main() {
  490.     setlocale(0, "");
  491.     SearchServer search_server("and in at"s);
  492.     RequestQueue request_queue(search_server);
  493.     search_server.AddDocument(1, "curly cat curly tail"s, DocumentStatus::ACTUAL, { 7, 2, 7 });
  494.     search_server.AddDocument(2, "curly dog and fancy collar"s, DocumentStatus::ACTUAL, { 1, 2, 3 });
  495.     search_server.AddDocument(3, "big cat fancy collar "s, DocumentStatus::ACTUAL, { 1, 2, 8 });
  496.     search_server.AddDocument(4, "big dog sparrow Eugene"s, DocumentStatus::ACTUAL, { 1, 3, 2 });
  497.     search_server.AddDocument(5, "big dog sparrow Vasiliy"s, DocumentStatus::ACTUAL, { 1, 1, 1 });
  498.     // 1439 запросов с нулевым результатом
  499.     for (int i = 0; i < 1439; ++i) {
  500.         request_queue.AddFindRequest("empty request"s);
  501.     }
  502.     // все еще 1439 запросов с нулевым результатом
  503.     request_queue.AddFindRequest("curly dog"s);
  504.     // новые сутки, первый запрос удален, 1438 запросов с нулевым результатом
  505.     request_queue.AddFindRequest("big collar"s);
  506.     // первый запрос удален, 1437 запросов с нулевым результатом
  507.     request_queue.AddFindRequest("sparrow"s);
  508.     cout << "Total empty requests: "s << request_queue.GetNoResultRequests() << endl;
  509.     return 0;
  510. }
  511.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement