【问题标题】:How to make an iterator over several sorted lists?如何在多个排序列表上创建迭代器?
【发布时间】:2017-10-28 19:04:42
【问题描述】:

好的,所以这是我得到的一个面试问题,当时只表现平庸。我想知道最佳解决方案是什么以及如何最好地实施。

给你多个排序列表,构造一些东西,让我们从最小到最大的元素遍历所有这些列表。

例子:

{ -2, 5, 10}
{ 2, 9, 11}
{ -5, 9}


-> -5, -2, 2, 5, 9, 9, 10, 11

更新:

在 SO 聊天 #c-questions-and-answers 和 @Nican 的帮助下,我已经让这艘船以某种方式飞行。我已经发布了我的工作代码作为答案,以允许其他解决方案。

我在下面发布的答案仍然很混乱,特别是我没有正确实现 == 和 != 。我仍然需要这些方面的帮助。

这个问题的理由

在网上找到干净简约的自定义迭代器实现并不常见。我相信这个问题可以作为一个很好的起点,让其他人加深对迭代器和最佳实践的理解。

【问题讨论】:

  • 不太清楚你所说的 “实现 end() 以检查哪个底层端点最大。” 我看不出这对你有什么帮助。只需让end() 返回一个带有标识符的迭代器对象,该标识符告诉您您处于序列的末尾。然后确保您的 == 操作员处理它。对于前向迭代器,请编写 ++、赋值运算符等。然后重构以创建 const_iterator

标签: c++ stl iterator


【解决方案1】:

我认为SortedListsIter::iterator 应该包含所有项目的副本,而不是引用,这样您就可以使用ForwardIterator 而不是InputIterator。您还可以避免 end 迭代器中的悬空引用(可以是默认构造的迭代器,如 iterator::iterator(std::vector<SortedListIterItem<Iter> > _items = {}) : m_items(_items){};

两个堆的元素顺序可能不同,所以我们使用std::is_permutation来判断是否相等

bool SortedListsIter::iterator::operator==(iterator other) 
{ return std::is_permutation(m_items.begin(), m_items.end(), other.m_items.begin(), other.m_items.end()); } 

C++11 替代方案(检查距离的 4 个迭代器版本不可用):

bool SortedListsIter::iterator::operator==(iterator other) 
{ return (std::distance(m_items.begin(), m_items.end()) == std::distance(other.m_items.begin(), other.m_items.end())) 
      && std::is_permutation(m_items.begin(), m_items.end(), other.m_items.begin()); } 

项目相等很简单:

bool SortedListIterItem::operator==(SortedListIterItem other) 
{ return (it_beg == other.it_beg) && (it_end == other.it_end); }

【讨论】:

    【解决方案2】:

    这不是一个完整的答案

    我已经实现了一个部分解决方案,它可以工作。这不是一个完整的,也不是符合 input_iterator 要求的正确实现。这说明了这一点,剩下的工作取决于谁感觉到了电话。

    --

    我刚刚从昨天的笔记和努力中再次发现了这一点。我从 Nican 那里得到了一些非常好的帮助。

    我正在使用堆将列表保存在我的结构中。 (其中有我正在重新发明priority_queue的有效批评)。除其他外,这里还缺少几件事:

    • 复制构造函数
    • 后缀 ++ 运算符
    • 正确的 == 和 != 实现,我只是在比较大小。
    • 这很容易成为 forward_iterator。

    我已经建立了对迭代器的理解。这就是我这次要采取的措施。

    #include <algorithm>
    #include <forward_list>
    #include <iostream>
    #include <iterator>
    #include <string>
    #include <vector>
    
    template <typename Iter>
    struct SortedListIterItem {
      Iter it_beg;
      Iter it_end;
      /* Used by the heap to sort ascending */
      bool operator<(const SortedListIterItem<Iter>& other) {
        return *it_beg > *other.it_beg;
      }
      bool operator==(const SortedListIterItem<Iter>& other) {
        return it_beg == other.it_begin && it_end == *other.it_beg;
      }
      SortedListIterItem<Iter>(Iter _begin, Iter _end)
          : it_beg(_begin), it_end(_end){};
    };
    
    template <typename Iter>
    class SortedListsIter {
      // member typedefs provided through inheriting from std::iterator
      class iterator {
        std::vector<SortedListIterItem<Iter> > m_items;
    
       public:
        iterator(std::vector<SortedListIterItem<Iter> > _items = {})
            : m_items(_items){};
        iterator& operator++() {
          std::pop_heap(m_items.begin(), m_items.end());
          SortedListIterItem<Iter>& largest = m_items.back();
    
          if (++largest.it_beg == largest.it_end) {
            m_items.pop_back();
          } else {
            std::push_heap(m_items.begin(), m_items.end());
          }
          return *this;
        }
        // iterator traits
        using value_type = typename Iter::value_type;
        using pointer = typename Iter::pointer;
        using reference = typename Iter::reference;
        using iterator_category = std::input_iterator_tag;
        /** A simplified comparator, which is not a correct implementation.
         *  While it does work for regular for loops. */
        bool operator!=(iterator other) { 
          return (m_items.size() != other.m_items.size());
        }
        value_type operator*() const { 
          return *(m_items.front().it_beg); 
        };
      };
      std::vector<SortedListIterItem<Iter> > m_items;
    
     public:
      void add_list(Iter it_begin, Iter it_end) {
        if (it_begin != it_end) {
          m_items.push_back(SortedListIterItem<Iter>(it_begin, it_end));
          std::push_heap(m_items.begin(), m_items.end());
        }
        // Ignore empty lists.
      }
      iterator begin() { return iterator(m_items); };
      iterator end() {
        std::vector<SortedListIterItem<Iter> > _items;
        return iterator(_items);
      };
    };
    
    int main(int argc, char** argv) {
      std::forward_list<std::string> animals = {"Cat", "Dog", "Horse"};
      std::forward_list<std::string> fish = {"Dolphin", "Mermaid", "Shark"};
      std::forward_list<std::string> birds = {"Crow", "Duck", "Eagle"};
      SortedListsIter<std::forward_list<std::string>::iterator> my_string_iter;
      my_string_iter.add_list(fish.begin(), fish.end());
      my_string_iter.add_list(animals.begin(), animals.end());
      my_string_iter.add_list(birds.begin(), birds.end());
    
      for (auto i : my_string_iter) {
        std::cout << " " << i << ",";
      }
      std::cout << std::endl;
      for (auto i : my_string_iter) {
        std::cout << " " << i << ",";
      }
      std::cout << std::endl;
    
      std::vector<int> l4 = {1, 2, 99};
      std::vector<int> l5 = {-11, -4, 3};
      std::vector<int> l6 = {-5, 1};
    
      SortedListsIter<std::vector<int>::iterator> my_iter2;
      my_iter2.add_list(l4.begin(), l4.end());
      my_iter2.add_list(l5.begin(), l5.end());
      my_iter2.add_list(l6.begin(), l6.end());
    
      for (auto i : my_iter2) {
        std::cout << " " << i << ",";
      }
      std::cout << std::endl;
    
      return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-27
      • 2017-04-19
      • 2012-04-19
      • 2018-10-20
      • 1970-01-01
      • 1970-01-01
      • 2012-10-29
      • 2019-10-01
      相关资源
      最近更新 更多