【问题标题】:Iterator for jumping between container C++用于在容器 C++ 之间跳转的迭代器
【发布时间】:2014-12-29 11:21:34
【问题描述】:

我有一个整数容器容器。可以说deque< deque<int> >deque<int> 中的所有数字都按升序排序。所以容器中的信息看起来像这样:

deque<deque<int>> // main container
  5 11 22 44      // deque<int> number 1
  1 7 12          // deque<int> number 2
  4 5 7 9 1112    // deque<int> number 3

我想创建一个迭代器,以升序遍历deque&lt;deque&lt;int&gt;&gt; 中的所有数字。这意味着我的迭代器可以在容器之间跳转,在我浏览完所有容器后,我将按以下顺序遍历这些数字:1 4 5 5 7 7 9 11 12 22 44 1112。我怎样才能做到这一点?我想把所有数字放在一个容器中并对其进行排序,但是稍后如果我想说*it = 10 我将无法做到,因为我不知道it 指向哪个容器位置。所以欢迎任何想法和解决方案:)

【问题讨论】:

  • 允许非常量迭代器似乎是个坏主意,因为这意味着您不能再保证您的不变量(每个双端队列都已排序)。
  • @OliverCharlesworth 如果我也能找到一个 const 迭代器,我会很高兴的。只是为了按想要的顺序遍历元素。一种前向迭代器。
  • 看看 merge-sort 如何进行合并,您会受到启发。
  • @pesho 我看到你接受了我的回答;但它有一些小问题。我更新了它,并将代码发布为一个似乎可以工作的 ideone 演示。如果您有任何问题,您可以参考该代码。 ideone.com/NTlk4f

标签: c++ iterator containers deque


【解决方案1】:

让我们关注 const 迭代器。这样的迭代器应该为每个双端队列保存一个迭代器,但也应该为它们的每个端保存一个迭代器(为什么需要这个在下面解释)。但是这些迭代器应该保存在向量而不是双端队列中,因为您永远不会从这些容器的任何一端推送或弹出,因为此类迭代器的生命周期会随着数据结构的修改而结束。

所以基本上,你需要以下结构:

struct const_iterator {
    vector<deque<int>::const_iterator>   iterators;
    vector<deque<int>::const_iterator>   ends;
    //...
};

现在,您需要实现递增运算符(也许您还需要一个递减运算符,可以类似地实现),以及取消引用运算符。

自增操作符需要找到当前指向最小元素的双端队列迭代器,并自增。

解引用操作符还需要找到当前指向最小元素的deque迭代器,并解引用那个。

如果您正在寻找当前最小的元素,请忽略已经指向其末尾的双端队列。为此,您需要所有双端队列的结束迭代器。记住另一个成员变量中当前最小的元素可能会有所帮助,这样取消引用就变成了一个常数时间的操作。我们将当前的迭代器作为迭代器存储到迭代器的向量中,这样我们就可以递增它(因此向量中的迭代器会改变)。

struct nested_deque_iterator {
    vector<deque<int>::const_iterator>            iterators;
    vector<deque<int>::const_iterator>            ends;
    vector<deque<int>::const_iterator>::iterator  current;
    bool                                          at_end = false;
};

更新最小元素可以在辅助函数中实现,它修改成员变量current 以及at_end。这需要在构造函数中调用才能正确初始化成员变量:

void update_current() {
    if (!at_end && iterators.size() > 0) {
        // At the beginning, we assume that we didn't find any
        // new "next smaller element" in any deque.
        at_end = true;

        // Iterate through the deques (with two iterators in parallel)
        for (auto i = iterators.begin(), e = ends.begin();
             i != iterators.end() && e != ends.end();
             ++i, ++e)
        {
            // We ignore deques which are already at their end
            if (i != e) {
                // If we found a smaller next element (or the first try)...
                if (at_end || *i < *next) {
                    // ... then replace the current iterator with it:
                    at_end = false;
                    current = i;
                }
            }
        }
    }
}

然后,解引用变得像解引用当前迭代器一样简单两次(因为它是迭代器向量的迭代器......我知道这有点令人困惑......)

int operator *() const {
    return **current;
}

而自增将自增(取消引用的)当前迭代器,并调用辅助函数对其进行更新(这是预自增运算符):

nested_deque_iterator& operator++() {
    if (!at_end) {
        ++(*current);
        update_current();
    }
}

你可以通过预自增的方式实现后自增运算符:

nested_deque_iterator operator++(int) {
    nested_deque_iterator old(*this);
    ++(*this);
    return old;
}

我们还需要相等运算符来比较迭代器:

bool operator==(const nested_deque_iterator &o) const {
    // If either iterator is at the end, don't dereference current!
    if (at_end || o.at_end) {
        return at_end == o.at_end;
    }
    return *current == *(o.current);
}

最后是不等式运算符:

bool operator!=(const nested_deque_iterator &o) const {
    return !(*this == o);
}

最后,为嵌套的双端队列编写一个开始和结束构造辅助函数。

nested_deque_iterator nested_deque_begin(const deque<deque<int>> & deques) {
    vector<deque<int>::const_iterator>   iterators;
    vector<deque<int>::const_iterator>   ends;
    for (const auto & d : deques) {
        iterators.push_back(d.begin());
        ends.push_back(d.end());
    }
    return { iterators, ends };
}

nested_deque_iterator nested_deque_end(const deque<deque<int>> & deques) {
    vector<deque<int>::const_iterator>   ends;
    for (const auto & d : deques) {
        ends.push_back(d.end());
    }
    return { ends, ends };
}

如果你愿意,还有一个容器适配器(如果你还没有这样的),它使用这些构造辅助函数作为它们的默认开始和结束方法:

struct nested_deque {
    deque<deque<int>> deques;
    //...
}

nested_deque_iterator begin(const nested_deque & nd) {
    return nested_deque_begin(nd.deques);
}
nested_deque_iterator end(const nested_deque & nd) {
    return nested_deque_end(nd.deques);
}

所以你可以写:

deque<deque<int>> mydeque = ...;

for (int i : nested_deque{mydeque}) {
    // Here you go.
}

完整的实现是可用的here

【讨论】:

    【解决方案2】:

    实现你自己的迭代器:

    struct sorted_iterator {
        int& operator*() { return *(*this->it); }
        sorted_iterator& operator++() { ++(this->it); return *this;}
        bool operator==( const sorted_iterator& other ) const;
        bool operator!=( const sorted_iterator& other ) const;
    
        private:
            std::vector<int*> sorted;
            decltype(sorted)::iterator it;
    };
    

    在其中,在内部构建一个int*的向量

    std::vector<int*> sorted;
    
    for( std::deque<int> x : main_container )
        for( int& i : x )
            sorted.push_back(&i);
    
    auto compare = []( int* i, int* j ) { return *i < *j; }
    std::sort( sorted.begin(), sorted.end(), compare );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-16
      • 2017-05-08
      • 1970-01-01
      • 2015-03-11
      • 2011-08-06
      • 2021-02-14
      • 1970-01-01
      相关资源
      最近更新 更多