I'm trying to write an iterator that iterates on multiple (sorted) lists. I have one that works but I'd like to improve it.
Here's what I have for now.
#ifndef __multi_iterator__
#define __multi_iterator__
#include <list>
template <typename T>
class multi_iterator
{
private:
typedef typename std::list<T>::const_iterator iterator;
typedef std::list<iterator> iterator_list;
public:
multi_iterator();
multi_iterator(const multi_iterator<T>& other);
multi_iterator& operator = (const multi_iterator<T>& other);
virtual ~multi_iterator();
void add_list(const std::list<T>& it);
const T& operator * ();
multi_iterator<T>& operator ++ ();
multi_iterator<T> operator ++ (int unused);
bool operator == (const multi_iterator<T>& other);
bool operator != (const multi_iterator<T>& other);
protected:
iterator_list _it_list;
iterator_list _end_list;
private:
iterator& next();
};
template <typename T>
multi_iterator<T>::multi_iterator()
: _it_list()
{
}
template <typename T>
multi_iterator<T>::multi_iterator(const multi_iterator<T>& other)
: _it_list(other._it_list)
{
}
template <typename T>
multi_iterator<T>& multi_iterator<T>::operator = (const multi_iterator<T>& other)
{
_it_list = other._it_list;
}
template <typename T>
multi_iterator<T>::~multi_iterator<T>()
{
}
template <typename T>
void multi_iterator<T>::add_list(const std::list<T>& l)
{
_it_list.push_back(l.begin());
_end_list.push_back(l.end());
}
template <typename T>
const T& multi_iterator<T>::operator * ()
{
return *(next());
}
template <typename T>
multi_iterator<T>& multi_iterator<T>::operator ++ ()
{
++(next());
return *this;
}
template <typename T>
typename multi_iterator<T>::iterator& multi_iterator<T>::next()
{
typename iterator_list::iterator it = _it_list.begin();
typename iterator_list::iterator end_it = _end_list.begin();
typename iterator_list::iterator cur_it = _it_list.end();
for (; it != _it_list.end(); ++it)
{
if (*it != *end_it)
{
if ((cur_it == _it_list.end()) || (**it < **cur_it))
{
cur_it = it;
}
}
++end_it;
}
return *cur_it;
}
template <typename T>
multi_iterator<T> multi_iterator<T>::operator ++ (int unused)
{
return ++(*this);
}
template <typename T>
bool multi_iterator<T>::operator == (const multi_iterator<T>& other)
{
return _it_list == other._it_list;
}
template <typename T>
bool multi_iterator<T>::operator != (const multi_iterator<T>& other)
{
return !(*this == other);
}
#endif /* defined(__multi_iterator__) */
Here are the questions I've been pondering:
What should a C++ iterator do when it reaches the end (trying to look like stdlib). Throw an exception?
I don't think my keeping the list of iterator "ends" is elegant. Neither is my way to find if all iterators are at the end in next()
. Does anyone have a cleaner solution?
Currently next()
runs in linear time and is called for both * and ++ operators. I'm thinking I could save the current iterator and get the * operator to run in constant time. Also, If I sort my list each time I call ++, would ++ run in nlog(n)? I heard that this can be done in log(n) time and I can't really find a way to do that. What are your thoughts on complexity and optimization for this?
What you're trying to do is pretty well covered by zip iterators -- the Boost.Iterator library provides one. Check out their implementation.
You should also check out this discussion if you need to be able to add containers dynamically:
Zip Several Iterators in C++
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With