So I have a custom linked list. Every node is a struct which has a next pointer to a the next node and the last->next is null.
struct nodo {
T value;
nodo *next;
nodo() : next(0) {}
nodo(const T &v, nodo *n=0): value(v), next(n){}
};
I want to implement iterators in my class and since my class supports random access with operator[] then I chose to implement Random Access Iterators.
Now, my problem is on the following operator:
difference_type operator-(const iterator &other) {
}
It returns the number of elements between this iterator and other iterator, but I'm not sure what's the best to implement it.
Linked lists are not random access containers. You cannot meaningfully implement random access iteration, nor a conventional operator[](size_t) for regular single or double linked lists.
People who use your list class will not expect random access iteration, and will be confused by it. People who use your "random access" iterators and find out they don't conform to standards and conventions will also be confused.
A RandomAccessIterator is a BidirectionalIterator that can be moved to point to any element in constant time.
Only if your container can access elements by index in constant time should you expose random access interfaces.
Related
I'm trying to implement about list and iterator of list like C++ STL.
The node in list is defined like this:
struct Node{
Node *prev,*next;
value_type data;
};
And I want to overloading operator > and < :
bool list_iterator::operator>(const iterator_impl_base &rhs) const
bool list_iterator::operator<(const iterator_impl_base &rhs) const
which means if I need to call next to reach rhs.node , it will return 0 in > and return 1 in <.
if I need to call prev to reach rhs.node , it return 1 in > and return 0 in <.
And I implement list using circular list. Below is one part of list class :
class List : public ordered_container {
protected:
Node* begin_;
Node* end_;
size_type size_;
public:
List::List() : end_(new Node){
begin_ = end_->prev = end_->next = end_;
size_=0;
}
}
So , I don't know how to distinguish whether I just pass the begin_ of list. Can someone help me about that? Thankyou.
Firstly, using operator< to mean "precedes" is weird. I know it's an exercise, I just don't want you thinking this is normal.
Now, your circular list stores the begin and end in the top-level container object, so there's no way for a node itself to tell whether it's the head, or the trail, or whether a reversal wraps around. Only the container can tell this.
The usual solution for circular lists is to have a sentinel node between head and tail. Then sentinel.next is the head, sentinel.prev is the tail, and you need some way to mark the sentinel itself (either a magic value of data or an extra flag). This sentinel node can then replace the two pointers in your container object (so you're not wasting any space).
When you traverse the list, it's still circular, but you can tell if you pass the sentinel that you've wrapped around.
The sentinel has the additional benefit that you never have to worry about nullptrs in an empty list.
Incidentally, I find it very strange that instructors keep using doubly-linked lists and don't show the sentinel arrangement. It's described within a couple of pages in a copy of Elson's Data Structures book I've inherited, and that was published in 1975. What's the point of deliberately teaching a bad doubly-linked list?
If they wanted you to figure this out for yourself, they ought to have you working through the fundamental list operations rather than these odd precedes/succeeds operators, as the basic operations can actually work without a sentinel but are visibly improved with its addition.
An element a is less than another element b iff you can reach b before end by following next.
An element a is greater than another element b iff b is less than a.
Is there a possiblity to write a template for List (like in STL) that will be made of double linked list using nodes connected to themself and to provide ability to use iterators like begin or end?
If I had nested class:
class Node{
T data;
Node* previous, next;
Node(T &data, Node* next);
};
And my list would have begin() function:
template<class T>
class List {
Node *data; //first element
...
public:
T* begin() { return data->data; }; //return content of the first element
...
I assume that if I would like to use that list with for example std::copy function like
copy(l.begin(), l.end(), out);
then copy function iterates through the list using "begin++" then it would like to increment a pointer that points to the "data" object inside of node. Then it would not take a data from next node.
So is it possible to make that kind of a list?
First of all, there's std::list - which is probably what you want.
Secondly, your implementation of begin() does not fit the expectation for what that function returns for containers. You'll want to return something that at the very least models ForwardIterator (and since it's doubly-linked, BidirectionalIterator). Basically, this needs to work:
List<int> my_list = ...;
auto it = my_list.begin();
int& x = *it; // first value in the list
++it; // next element in the list
int& y = *it; // next value in the list
Right now, begin() yields a List<int>::Node*. That dereferences to a List<int>::Node, but it should dereference to an int. Wrong type and leaking the abstraction. Incrementing the pointer compiles, but it will point to some arbitrary spot in memory rather than the next node. There is no guarantee after all that the next node will be adjacent in memory (almost certainly it isn't!)
So you need to write your own iterator type which wraps your Node class, which will have to do those operations correctly based on the iterator concepts. Basically you're just mapping the iterator concept operations to what those look like for Node. To get you started as an example:
Node* underlying;
iterator& operator++() {
underlying = underlying->next;
return *this;
}
T& operator*() {
return underlying->data;
}
Also, check out the Boost's Iterator Facade library, which is helpful for writing iterators correctly.
In the past I've implemented a linked list using nodes.
I am looking at some of the properties of the standard library list and it has iterators and the appropriate member functions.
What are the iterators in a list exactly? Are they the node pointers?
For a vector, basically you have pointers to the element type and the data structures is built on an underlying dynamic array of that given type.
For the lists, it seems it is just a sequence of nodes, array of nodes. So are the iterators the node pointers rather than a pointer to the node data type?
Basically what I am asking is if for a vector I had this iterator:
tyepdef T* iterator;
Would the iterator for the list be
typedef node* iterator;
where node is something like:
template <class T> struct node {
node() { next = 0; }
node(T i, node* n = 0) : data(i), next(n) {}
node* next;
T data;
}
If this is the case, it seems that operations like dereferencing will have to be overloaded.
The std::list<T>::iterator objects internally point to a node but have operators which appropriately follow the pointers to next or previoys node. That is, they are not pointers as incrementing a pointer just adds one rather than follow a link. You can inagine a list iterator looks somewhat like this:
template <typename T>
class list_iterator {
friend list<T>
Node* node;
list_iterator(T* node):node(node) {}
list_iterator& operator++() {
node = node->next;
return *this;
}
T& operator*() { return *node; }
// ...
};
The iterator on lists should behave similar to the iterators on other sequence containers like vector. I.e. it should behave like a pointer to the list::value_type as if it were in an array or similar (with ++ and -- doing the expected operation going to next and previous). The internals of the holding structure aren't really exposed through the iterator. The iterator abstraction generally frees the programmer from thinking about how the data is stored. In the future, you could theoretically swap your std::list for a std::vector without changing your code, so long as you're only using operations available to both.
I have a class that (when simplified) looks like this:
class TreeNode
{
ptrdiff_t sibling_offset, first_child_offset;
public:
long whatever;
// ...
};
The tree nodes must contain offsets instead of pointers, because it needs to be possible for them to be embedded in containers (like std::vector) that may reallocate their storage when necessary, without having to spend time re-linking all the nodes.
Now, if I have a suitably defined class TreeIterator<Iter> (perhaps defined as a friend of TreeNode) whose job it is to iterate over a TreeNode's children, then any STL-style client of my class should be able to use it to iterate over the children of a node in a standard, STL fashion:
typedef std::vector<TreeNode> Tree;
Tree tree = ...;
TreeIterator<Tree::iterator> const root = tree.begin();
for (TreeIterator<Tree::iterator> i = root->begin(); i != root->end(); ++i)
{
foo(i->whatever);
process_further(i);
}
The trouble is, root->begin() is impossible because the TreeNode doesn't know anything about the container it's in.
(And it shouldn't! The only thing it cares about is that the container has suitable iterators.)
And yet, I (the author of TreeNode) am the only one who could possibly how to iterate over its children.
How do I resolve this issue, without restricting the type of the container that a TreeNode may be stored in?
Obviously this is easy if I force the user to use std::vector, but he should be free to use any arbitrary STL-compliant container.
You just define functions begin() and end() in TreeNode. And then use them in your code.
class TreeNode {
...
std::vector<T>::iterator begin() {return vec.begin();}
std::vector<T>::iterator end() {return vec.end();}
...
private:
std::vector<T> vec;
}
Is it possible to access an element of an STL linked list directly by it's pointer? My program requires quick insertion, removal and access of elements.
STL containers use iterators instead of pointers. If you have an iterator that points to an element of your linked list, you can access element's data through it, insert at the iterator's position using the list's insert method, and delete at iterator's position using the erase method.
Instead of using STL linked list, you may want to define your own linked list implementation using pointers. For example:
template <class E>
struct Node {
E data;
Node * next;
};
So define a Node class that will be an element in the linked list. As Kerrek SB suggested, redesigning the program with iterators in mind might be quicker and better in the long term.