Advertisement
yarin0600

All o'One Data Structure

Nov 18th, 2023
1,093
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.53 KB | None | 0 0
  1. #include <iostream>
  2. #include <string>
  3. #include <unordered_map>
  4. #include <unordered_set>
  5. #include <list>
  6.  
  7. struct Node
  8. {
  9.    int frequency;
  10.    std::unordered_set<std::string> keys;
  11. };
  12.  
  13. class AllOne
  14. {
  15. public:
  16.    AllOne()
  17.    {
  18.    }
  19.  
  20.    void inc(std::string key)
  21.    {
  22.       // two cases:
  23.       // Case A1: key is not in our data structure
  24.       if (_stringToNode.count(key) == 0)
  25.       {
  26.          // we need to insert it to the first node.
  27.          // two cases:
  28.          // Case A2: node with freq = 1 is not present:
  29.          if (_listOfRecords.empty() || _listOfRecords.front().frequency > 1)
  30.             _listOfRecords.push_front({.frequency = 1, .keys = {key}});
  31.          // Case B2: node with freq = 1 is present:
  32.  
  33.          else
  34.             _listOfRecords.front().keys.insert(key);
  35.  
  36.          // update map that maps this key to the iterator
  37.          _stringToNode[key] = _listOfRecords.begin();
  38.       }
  39.       // Case B1: key is in our data structure
  40.       else
  41.       {
  42.          // obtain the key:
  43.          auto it = _stringToNode[key];
  44.          int currentFrequency = it->frequency;
  45.          // add to the new list one next to it
  46.          auto itNext = std::next(it);
  47.          // Insertion two cases:
  48.          // Case A3: the next node does not exist yet
  49.          if (itNext == _listOfRecords.end())
  50.          {
  51.             _listOfRecords.push_back({.frequency = currentFrequency + 1, .keys = {key}});
  52.             itNext = std::next(it); // update the itNext
  53.          }
  54.  
  55.          // Case B3: next node exists
  56.          else
  57.             itNext->keys.insert(key);
  58.  
  59.          // remove from current unordered_set the key
  60.          it->keys.erase(key);
  61.          // update the unordered_map about where the key is right now
  62.          _stringToNode[key] = itNext;
  63.          // Removal two cases:
  64.          // Case A4: it's not the only key in the unordered_set:
  65.          if (it->keys.size() == 0)
  66.          {
  67.             _listOfRecords.erase(it);
  68.          }
  69.          // Case B4: it's the only key in the unordered_set: do nothing
  70.       }
  71.    }
  72.  
  73.    void dec(std::string key)
  74.    {
  75.       // Assumption - we know that it is guaranteed that key exists in the data structure before the decrement!
  76.       // first obtain the node that contains unordered_set that contains key:
  77.       auto it = _stringToNode[key];
  78.       auto itPrev = (it != _listOfRecords.begin()) ? std::prev(it) : _listOfRecords.end();
  79.  
  80.       int currentFrequency = it->frequency;
  81.  
  82.       // case A1: need to remove that key
  83.       if (currentFrequency == 1)
  84.       {
  85.          _stringToNode.erase(key);
  86.       }
  87.       // case B1: no need to remove that node but move it one node left
  88.       else
  89.       {
  90.          // Case A3: Need to add new node before current Node
  91.          if (itPrev == _listOfRecords.end() ||
  92.              itPrev->frequency != currentFrequency - 1)
  93.          {
  94.             _listOfRecords.insert(it, {.frequency = currentFrequency - 1, .keys = {key}});
  95.             itPrev = std::prev(it); // update itPrev
  96.          }
  97.          // Case B3: No need to add new node BEFORE current node
  98.          else
  99.          {
  100.             itPrev->keys.insert(key);
  101.          }
  102.          // on both cases, update the unordered_map to keep track of where is the key at
  103.          _stringToNode[key] = itPrev;
  104.       }
  105.       // removal from old node:
  106.  
  107.       it->keys.erase(key);
  108.       // Case A2: need to remove that node
  109.       if (it->keys.size() == 0)
  110.          _listOfRecords.erase(it);
  111.  
  112.       // Case B2: no need to remove that node
  113.       // do nothing
  114.    }
  115.  
  116.    std::string getMaxKey()
  117.    {
  118.       if (_listOfRecords.size() == 0)
  119.          return "";
  120.       return *(_listOfRecords.rbegin()->keys.begin());
  121.    }
  122.  
  123.    std::string getMinKey()
  124.    {
  125.       if (_listOfRecords.size() == 0)
  126.          return "";
  127.       return *(_listOfRecords.begin()->keys.begin());
  128.    }
  129.  
  130. private:
  131.    std::unordered_map<std::string, std::list<Node>::iterator> _stringToNode;
  132.    std::list<Node> _listOfRecords;
  133. };
  134.  
  135. int main()
  136. {
  137.    AllOne allOne;
  138.    allOne.inc("a");
  139.    allOne.inc("b");
  140.    allOne.inc("b");
  141.    allOne.inc("b");
  142.    allOne.inc("b");
  143.  
  144.    allOne.dec("b");
  145.    allOne.dec("b");
  146.    std::cout << "allOne.getMaxKey() = " << allOne.getMaxKey() << std::endl; // return "b"
  147.    std::cout << "allOne.getMinKey() = " << allOne.getMinKey() << std::endl; // return "a"
  148.    allOne.dec("b");
  149.    allOne.dec("b");
  150.    std::cout << "allOne.getMaxKey() = " << allOne.getMaxKey() << std::endl; // return "b"
  151.    std::cout << "allOne.getMinKey() = " << allOne.getMinKey() << std::endl; // return "a"
  152. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement