如何在多个排序列表上创建迭代器?

时间:2017-10-28 19:04:42

标签: c++ stl iterator

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

您将获得多个排序列表,构建某些,允许我们从最小元素到最大元素迭代所有这些列表。

示例:

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


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

更新

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

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

此问题的理由

在线查找干净简约的自定义迭代器实现并不常见。我相信这个问题可能是其他人加强对迭代器和最佳实践的理解的良好起点。

2 个答案:

答案 0 :(得分:1)

我认为SortedListsIter::iterator应该包含所有项目的副本,而不是引用,这样您就可以ForwardIterator而不是InputIterator。你也避免了在最终迭代器中的悬空引用(它可以是一个默认的构造迭代器,如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); }

答案 1 :(得分:0)

这不是一个完整的答案

我已经实现了一个部分解决方案,它的工作原理。对于具有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;
}