How to find tha't circular list's begin? - c++

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.

Related

Can I use a map's iterator type as its mapped type?

I have a tree whose nodes are large strings. I don't really need to navigate the tree other than to follow the path from a node back to the root, so it suffices for each node to consist of the string and a pointer to its parent. I also need to be able to quickly find strings in the tree. The nodes of the tree themselves are not ordered, so this would require some sort of index. However, the strings are big enough that I would rather not duplicate them by storing them both in my tree and in my index.
I could implement both my tree and the index with a single std::map if the key for the map was the string and the mapped value was the pointer to its parent. However, I cannot figure out a way to write either of these types. My best guess would be something like this:
using Tree = std::map<std::string, typename Tree::const_iterator>;
or maybe:
using Node = std::pair<std::string const, typename Node const*>;
using Tree = std::map<std::string, Node const*>;
But these recursive type definitions don't compile. Is there any way to create this type in C++? Or a better way to do what I am trying to do?
You can wrap the iterator in a type of your own and reference that type instead to avoid the recurisve type problem.
struct const_iterator_wrapper {
using iterator_type = map<string, const_iterator_wrapper>::const_iterator;
iterator_type iter;
const_iterator_wrapper() {}
const_iterator_wrapper(iterator_type _iter) : iter(_iter) {}
};
using tree = map<string, const_iterator_wrapper>;
Your using Node definition doesn't compile, but an actual structure would:
struct Node {
std::string const s;
Node const* n;
};
It was not mentioned whether or not a node's parent might change after creation. If it does not, then a set might be a better fit than a map. (If it does change, then the set option is not completely off the table, but it might require weakening const correctness guarantees, possibly by making the parent pointer mutable.) In fact, you might not have to change your data structure much to use a set.
Let's say your nodes currently look like the following.
struct Node {
std::string data;
const Node * parent; // Might need to add `const`
};
You want these sorted by the data, ignoring the parent pointer. This might require defining a new function. If the following operator< is already defined as something else, then it takes a little more work to define your set, but still not hard.
bool operator<(const Node &a, const Node &b) {
return a.data < b.data;
}
This is all you need to define a set of these nodes that will function much like your desired map.
std::set<Node> tree;
// Add a root element.
auto result = tree.emplace("root", nullptr);
auto root_it = result.first;
// Add a child to the root.
tree.emplace("child", &*root_it);
// The `&*` combination may look odd. It is, though, a way to
// convert an iterator to a pointer.
There are a few gotchas that some people might find unexpected, but nothing other than what comes from using a map for this role.
In the end, as far as the structure of the data is concerned, a map<K, const V> is equivalent to a set<pair<K, V>> with a suitable comparison function. While the member functions differ, the biggest real functional difference between a map and a set of pairs is that the map's values can be changed (hence const V instead of V earlier).

STL-like List made of linked list with nodes

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.

std::forward_list -- erasing with a stored iterator

I'm trying to keep a global list of a particular (base) class's instances so that I can track them down by iterating through this global list at any time.
I believe the most proper way to address this is with an intrusive list. I have heard that one can encounter these creatures by digging into the Linux kernel, for example.
In the situation where I'm in, I don't really need such guarantees of performance, and using intrusive lists will complicate matters somewhat for me.
Here's what I've got so far to implement this concept of a class that knows about all of its instances.
class A {
static std::forward_list<A*> globallist;
std::forward_list<A*>::iterator listhandle;
public:
A() {
globallist.push_front(this);
listhandle = globallist.begin();
}
virtual ~A() {
globallist.erase_after(...); // problem
}
};
The problem is that there is no forward_list::erase(), and it really does not appear like saving globallist.before_begin() in the ctor would do me much good. I'm never supposed to dereference before_begin()'s iterator. Will it actually hold on to the position? If I save out before_begin's iterator, and then push_front() a new item, that iterator is probably still not capable of being dereferenced, but will it be serviceable for sending to erase_after()?
forward_list is a singly linked list. To remove a node in the middle of that, you must have a pointer to previous node, somehow. For example, you could do something like this:
class A {
static std::forward_list<A*> globallist;
std::forward_list<A*>::iterator prev_node;
public:
A() {
A* old_head = globallist.front();
globallist.push_front(this);
prev_node = globallist.before_begin();
old_head->prev_node = globallist.begin();
}
};
The case of pushing the first element into an empty list, as well as the removal logic, are left as an exercise for the reader (when removing, copy your prev_node to the next node's prev_node).
Or, just use std::list and avoid all this trouble.

Correct way of erasing a linked list

Suppose, I have a singly linked list and its basic building block is,
struct Node {
Data d;
Node *pNext;
// methods
~Node();
};
The head of the linked list is stored as,
Node *m_Head; // member of some class
When, I am done with the list, I will clean it by deleting each node as,
void Erase()
{
Node *pIter, *pTemp = m_Head;
while((pIter = pTemp) != 0)
{
pTemp = pIter->pNext;
delete pIter;
pIter = pTemp;
}
}
I thought, if I can simplify this. So I came up with an idea where I can clean this whole linked list with just a single instruction !
delete m_Head;
and destructor will look like:
Node::~Node() { delete this->pNext; }
Here my concern is, will it cause recursion (implicitly due to delete) ? If yes, then it's definitely a concern for bigger linked lists. Will compiler be able to help in any way for optimizing that ?
[Note: Not using any library facility like std::list or other.]
I think the question that you have to ask is, does each Node in the list own its pNext Node? If not, then it has no business deleting its pNext node in its destructor.
In most linked list implementations all the nodes are owned by the list, a node doesn't own all the nodes after it in the list. It makes more sense to keep the nodes as dumb (POD-structs) and let all of the logic reside in the list.
It's definitely a design "smell" that your node has a destructor but no copy constructor or copy assignment operator. I think this approach will cause more complexity when you come to code implementing insert, splice and erase single element functions as you will have to manually manage the pNext pointers in any case to avoid unintentional destruction of the entire tail of a list.
Of course: Only do this for learning purposes or when you are sure that your own List is really better for your use case
It depends. Possibly your compiler will detect a tail recursion and emit code that is conceptually equivalent to using a loop.
If not, then yes, it will recurse. Usually, some thousands of recursions should be possible on commodity boxes, if stack pressure is small (like in your case). However, there is no guarantee, and indeed, for really large lists, this can be a problem.
Also, I think that recursion is indeed not entirely appropriate for the concept of sibling nodes. A node hierarchy, like with quadtrees, cries for recursion, but I have a not so good time thinking in recursion (which forms a call hierarchy) when the list-concept is about sibling-nodes.
You may also consider the manual loop as a easy-to-achieve optimization over the recursion that will make your code more robust in a guaranteed way.
Btw, you could also should rip out the deletion of nodes into a holder class:
class List {
public:
~List() {
for-each-node
delete-node
}
private:
class Node {
Node *node_;
...
};
...
};
This is basically how the standard library's list is usually implemented. It makes the whole implementation easier to achieve and conceptually more correct (Nodes don't own their sibling logically)
Most compiler do tail call elimination in default setting. Some smarter one can convert non-tail calls to tail calls.
So, this method okay as long as you have some optimization turned on.
Raw pointers ? Manual calls to delete ?
Why not, simply:
struct Node {
Data d;
std::unique_ptr<Node> next;
};
Then you don't even have to worry about memory management at all, it's automatic!

Item in multiple lists

So I have some legacy code which I would love to use more modern techniques. But I fear that given the way that things are designed, it is a non-option. The core issue is that often a node is in more than one list at a time. Something like this:
struct T {
T *next_1;
T *prev_1;
T *next_2;
T *prev_2;
int value;
};
this allows the core have a single object of type T be allocated and inserted into 2 doubly linked lists, nice and efficient.
Obviously I could just have 2 std::list<T*>'s and just insert the object into both...but there is one thing which would be way less efficient...removal.
Often the code needs to "destroy" an object of type T and this includes removing the element from all lists. This is nice because given a T* the code can remove that object from all lists it exists in. With something like a std::list I would need to search for the object to get an iterator, then remove that (I can't just pass around an iterator because it is in several lists).
Is there a nice c++-ish solution to this, or is the manually rolled way the best way? I have a feeling the manually rolled way is the answer, but I figured I'd ask.
As another possible solution, look at Boost Intrusive, which has an alternate list class a lot of properties that may make it useful for your problem.
In this case, I think it'd look something like this:
using namespace boost::intrusive;
struct tag1; struct tag2;
typedef list_base_hook< tag<tag1> > base1;
typedef list_base_hook< tag<tag2> > base2;
class T: public base1, public base2
{
int value;
}
list<T, base_hook<base1> > list1;
list<T, base_hook<base2> > list2;
// constant time to get iterator of a T item:
where_in_list1 = list1.iterator_to(item);
where_in_list2 = list2.iterator_to(item);
// once you have iterators, you can remove in contant time, etc, etc.
Instead of managing your own next/previous pointers, you could indeed use an std::list. To solve the performance of remove problem, you could store an iterator to the object itself (one member for each std::list the element can be stored in).
You can extend this to store a vector or array of iterators in the class (in case you don't know the number of lists the element is stored in).
I think the proper answer depends on how performance-critical this application is. Is it in an inner loop that could potentially cost the program a user-perceivable runtime difference?
There is a way to create this sort of functionality by creating your own classes derived from some of the STL containers, but it might not even be worth it to you. At the risk of sounding tiresome, I think this might be an example of premature optimization.
The question to answer is why this C struct exists in the first place. You can't re-implement the functionality in C++ until you know what that functionality is. Some questions to help you answer that are,
Why lists? Does the data need to be in sequence, i.e., in order? Does the order mean something? Does the application require ordered traversal?
Why two containers? Does membership in the container indicated some kind of property of the element?
Why a double-linked list specifically? Is O(1) insertion and deletion important? Is reverse-iteration important?
The answer to some or all of these may be, "no real reason, that's just how they implemented it". If so, you can replace that intrusive C-pointer mess with a non-intrusive C++ container solution, possibly containing shared_ptrs rather than ptrs.
What I'm getting at is, you may not need to re-implement anything. You may be able to discard the entire business, and store the values in proper C++ containers.
How's this?
struct T {
std::list<T*>::iterator entry1, entry2;
int value;
};
std::list<T*> list1, list2;
// init a T* item:
item = new T;
item->entry1 = list1.end();
item->entry2 = list2.end();
// add a T* item to list 1:
item->entry1 = list1.insert(<where>, item);
// remove a T* item from list1
if (item->entry1 != list1.end()) {
list1.remove(item->entry1); // this is O(1)
item->entry1 = list1.end();
}
// code for list2 management is similar
You could make T a class and use constructors and member functions to do most of this for you. If you have variable numbers of lists, you can use a list of iterators std::vector<std::list<T>::iterator> to track the item's position in each list.
Note that if you use push_back or push_front to add to the list, you need to do item->entry1 = list1.end(); item->entry1--; or item->entry1 = list1.begin(); respectively to get the iterator pointed in the right place.
It sounds like you're talking about something that could be addressed by applying graph theory. As such the Boost Graph Library might offer some solutions.
list::remove is what you're after. It'll remove any and all objects in the list with the same value as what you passed into it.
So:
list<T> listOne, listTwo;
// Things get added to the lists.
T thingToRemove;
listOne.remove(thingToRemove);
listTwo.remove(thingToRemove);
I'd also suggest converting your list node into a class; that way C++ will take care of memory for you.
class MyThing {
public:
int value;
// Any other values associated with T
};
list<MyClass> listOne, listTwo; // can add and remove MyClass objects w/o worrying about destroying anything.
You might even encapsulate the two lists into their own class, with add/remove methods for them. Then you only have to call one method when you want to remove an object.
class TwoLists {
private:
list<MyClass> listOne, listTwo;
// ...
public:
void remove(const MyClass& thing) {
listOne.remove(thing);
listTwo.remove(thing);
}
};