Compilers can produce warnings - make the compiler programmers happy: Use them!
Please don't PM me for help - and no, I don't do help over instant messengers.
hey thanx matsp. that's exactly what i was hoping for. quickly skimming through the code i guess what was most confusing to me was how to construct the iterator class. the fact that Node was private and Iterator was public, and trying to allow iterator access to the private node was confusing as all hell. One bit of confusion I see is this:
but then you have:Code:iterator(Node* n = 0) : curr(n) {}if in the ctor curr is initialized to 0, how then can you specify to initialize it to head?Code:iterator begin() const {return iterator(head);}
Me = confused
says that "iterator is constructed using a node n, which has a default value of 0".Code:iterator(Node* n = 0) : curr(n) {}
So we can do:
iterator i; // curr = 0;
or
iterator i(43); // curr = 43 [ignoring that the type isn't a Node * for now].
So, when we dothe iterator is constructed with the value of head, not with zero.Code:iterator begin() const {return iterator(head);}
--
Mats
Compilers can produce warnings - make the compiler programmers happy: Use them!
Please don't PM me for help - and no, I don't do help over instant messengers.
gotya. thankx.
also, let's say I have a member function display(). It is possible to use an iterator to traverse the list? I mean, obviously I need a list object or pointer to call begin() or end(), so can "this" call those functions?
obviously that won't work, but is there a simple workaround to get it working?Code:template <typename T> void List<T>::display(){ for(mlist<int>::iterator i = this->begin(); i != this->end(); i++) { std::cout << "node = " << *i << std::endl; } }
haha! actually that DID work!
Some selective replacements will probably make it work. The red bit is quite obviously from my code and should most likely be "List<T>" instead.Code:template <typename T> void List<T>::display(){ for(mlist<int>::iterator i = this->begin(); i != this->end(); i++) { std::cout << "node = " << *i << std::endl; } }
since *i (in my case) returns an object of type T, you also need to have operator<<(ostream, T) [not that you would have to be responsible for writing that, but it needs to exist somewhere].
Edit: And it would probably work just as well without the "this->" because that is the default for any function within the class.
--
Mats
Compilers can produce warnings - make the compiler programmers happy: Use them!
Please don't PM me for help - and no, I don't do help over instant messengers.
another thing i'd like to add, and i don't understand why, but moving the private node before the public interface, cleared up some of the errors i was getting like:
SOME_ERROR: cannot declare someFunc() of type Node with no type
Compilers can produce warnings - make the compiler programmers happy: Use them!
Please don't PM me for help - and no, I don't do help over instant messengers.
oh geez, after playing around with this for a while, i'm confused about something.
in my design i had this:matsp designed this:Code:list() : head(new Node(T())), tail(new Node(T())) {}
i'd like to have Node pointers "next" and "prev" so i can iterate in both directions from either the head or tail respectively.Code:list() : head(0), tail(0) {}
What confuses me, is do the pointers "head" and "prev" actually have both "next" and "prev" pointers?
I mean, if they are just Node pointers, don't they only point to one thing? But an actual instance of a Node would have both "next" and "prev"?
This confusion came about because when I tried to implement matsp's design with a "prev" pointer as well, i ran into problems.
Please help me understand what the porblem is?
Do you want to loop circularly? I assume you don't. You only need tail->next and head->prev to point to valid locations if you do.
Making the head and the tail null indicate that the list is empty. In your version, you created two nodes, one for the head and one for the tail. But that doesn't really make sense if you want to start with an empty list. The only reason to do that would be if you were using head and tail as sentinal nodes and you add logic to the rest of your code to ignore their values.
The more common solution is to just assign pointers as necessary. When a new node is created the first time, you point head and tail to it and let the prev and next pointers point to 0. When a second node is added, you re-assign tail and then reassign the prev and next pointers as necessary.
Sherpa sent a PM asking how I would implement pop_back() and pop_front(), so I had to do that then...
This is the additional code to what I posted earlier:
As you see, the pop_back() is rather ugly with a big while-loop, since I only implemented a single-linked list, I can't use the tail to find the previous node, I have to walk all the way from the head to the end of the list. But it's an implementation. If it's a common operation to remove data from the back of the list, it's obviously a better idea to make the list double-linked [but that also makes the entire implementation more complex, and I wanted something that was trivial to implement - more code just makes it harder to follow].Code:// in class declaration: void pop_back(); void pop_front(); ... // And here's the implementation. template <typename T> void mlist<T>::pop_back() { Node *curr(head); Node *prev(0); while (curr != tail) { prev = curr; curr = curr->next; } if (prev) { delete prev->next; prev->next = 0; tail = prev; } else { head = tail = 0; } } template <typename T> void mlist<T>::pop_front() { if (head) { Node *temp(head); head = head->next; delete temp; if (!head) tail = 0; } }
--
Mats
Compilers can produce warnings - make the compiler programmers happy: Use them!
Please don't PM me for help - and no, I don't do help over instant messengers.
In a singly linked list, you usually wouldn't implement pop_back at all, just as your iterators are not bidirectional.
All the buzzt!
CornedBee
"There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
- Flon's Law
Yes. But if someone asks you "how do I implement this", it's not a good answer to say "well, I wouldn't" - or maybe it is, because it certainly wouldn't be a good idea to use this method if there are thousands or millions of entries in the linked list - very bad performance indeed.
--
Mats
Compilers can produce warnings - make the compiler programmers happy: Use them!
Please don't PM me for help - and no, I don't do help over instant messengers.
thanx for answering the pm matsp. anyways, the problem i was having w/my pop_back func was something really stupid.
I was looking through your header, while creating my class, but I added a prev pointer in mine. Well, suffice to say, i forgot to assign my prev pointers in my push functions, so when it got to pop.... you can see where I'm going with this...
thankx everyone!