Is there a library implementation or way to define singly linked lists in C++ that have a common tail from some element onwards? I'd like to be able to append a linked list to another, so that appending would just equal changing the final next pointer of one of the lists to point to the head of the other. Similarly, I would like be able to prepend an element to a list returning a new list where the head is just one step before the head of the other.
This would allow me to trivially get memory consumption down to linear from quadratic in a piece of code that I have... I.e. use the standard way of handling lists that all functional languages internally do.
Related
Here's what I want to do:
I have an arbitrary number of values of a different kind: string, int, float, bool, etc. that I need to store somehow. Multiple elements are often written and read as a whole, forming "contiguous blocks" that can also be extended and shortened at the users wish and even elements in the middle might be taken out. Also, the whole thing should be statically allocated.
I was thinking about using some kind of statically allocated forward lists. The way I imagine this to work is defining an array of a struct containing one std::variant field and a field "previous head" which always points to the location of the previous head of the list. A new element is always placed at the globally known "head" which it stores inside "previous head" field. This way I can keep track of holes inside my list because once an element is taken out, its location is written to global head and will be filled up by subsequent inserts.
This approach however has downsides: When a "contiguous block" is extended, there might be the case that further elements of other blocks have already queued up in the list past its last element. So I either need to move all subsequent entries or copy over the last element in the previous list and insert a link object that allows me to jump to the new location when traversing the contiguous block.
The priority to optimize this datastructure is following (by number of use cases):
Initially write contigous blocks
read the whole data structure
add new elements to contigous blocks
remove elements of contigous blocks
At the moment my data structure will have time complexity of O(1) für writes, O(n) for continous reads (with the caveat that in the worst case there is a jump to the next location inside the array every other element), O(1) for adding new elements and O(1) for removing elements. However, space complexity is S(2n) in the worst case (when I have to do a jump every second time the slot to store data is lost to the "link").
What I'm wondering now is: Is the described way the best viable way to accomplish what I'm trying or is there a better data structure? Is there an official name for this data structure?
I need a collection that is efficient when pre-appending and returning the first element. A stack does the job well.
Now, the objects of the stacks is also a collection. Let's say it is a list. So I have a Stack of Lists.
My question is the following:
If I want to append an element to the list of the head of the Stack, is my only choice to: pop the head, add the element to the list and push the new list?
Efficiently wise, all times are constant, correct?
If you're working with immutable collections the list you'd add and the outer stack(or List) would be new as well so it doesn't matter. Still lists are efficient in prepend and head operations (you can check doc for Collection - performance characteristics for details on the costs of operations)
Access to nodes in linked lists can get pretty slow if the list gets large. I did think of a way to speed up the access: there is an array (also a LL) with short cuts to every 100th node. This way if I want to get the 205th element, the program will have to go through this "path": short cut to [100] -> short cut to [200] -> [201] -> ... -> [205]. This is much faster that going through the whole LL to the 205th element- 5 "steps", instead of 204. Yes, it gets slower if I want the n-hundred-and-99-th element, but the program will skip a large part of the LL to get there- faster in the long run.
But those short cuts require readjusting after adding and removing more elements. Removing isn't a real problem- remove an element and set certain short cuts to point to the next nodes- those cuts that point at the formal n-hundredth nodes. Adding more data is a problem- when adding a new element, certain nodes must be set to point to the previous nodes. In order to get to these elements, the program must go ALL the way trough the list, starting from the last short cut that still points at an n-hundredth element. Unless the nodes also point to the previous elements, the whole process can get as slow as if I am removing an element from a vector.
Is there a way to speed up the access, keeping the processes for adding and removing elements fairly fast? This is just a question of curiosity, not if it is a good idea to use it in a real program.
You're using the wrong data structure. Linked lists are best used for sequentially-accessed lists, not for randomly-accessed collections. For that, you're better off with a hash table of some sort.
It seems like they both do the same thing in the same way: Lazy operations in a specific but not-necessarily-indexed order, and cannot necessarily backtrack.
Linked list is a specific way of representing sequences of data elements in memory, where each element is paired with a pointer of sorts to the next element in the sequence. Linked lists let you perform a range of operations on their subsequences: you can cut out or insert entire chains of elements, or delete elements from the middle at a very low cost.
Streams, on the other hand, are abstractions for accessing data in sequential order, without any specific requirements to their representation in memory. You can use a linked list to implement a stream, but you could also use another data structure for that, such as a plain array or a circular array buffer.
I think this is a little like trying to compare apples and oranges.
A linked list is a data structure where each node points to another node. They're a useful structure as inserting and removing items from a linked list is just a matter of re-pointing a node, rather than with an array where you need to do allot more shuffling. See http://en.wikipedia.org/wiki/Linked_list for more information.
A stream is an abstracted object used to represent a series of bytes. In most frameworks (Java, .NET etc) there are several concrete implementations of steams (memory stream, file stream etc) used to read the byte array from the relevant source (memory, file etc).
A linked list is a data structure where each element has a pointer to the next one, and possibly the same in the other direction. Circular linked lists even have a pointer from the last to the first element and vice versa. Those pointers (or references in languages that don't have pointers) are what defines the data structure. They imply a certain mode of operation, they don't force that, though. The LinkedList class in Java, for example, can be used like an array, although it won't be very effective then. It also can be used as (double-ended) queue or stack, depending on which functions you call.
A stream, on the other hand, is not defined as a data structure, but as a source or sink of elements. These elements could be bytes or characters, if you think of file streams, socket streams or reader/writer classes that wrap streams. The elements provided by a stream could also be more complex, e.g. tokens for a parser. In that case the stream likely uses some kind of queue internally, which could be implemented using a linked list or some array construction.
Just make sure to understand these two things are defined on different layers of abstraction. The linked list is defined on how it works internally, while the stream is defined on how it works externally.
There is a common abstraction between a read-only singly-linked list and an input stream, which C++ formalises as InputIterator: you can read a value and you can move forwards. In many stream APIs you have to do both simultaneously, but given that API it's fairly easy to see how to separate them out with a wrapper that caches one value: C++ calls this class istream_iterator.
However, a singly-linked list has a property that a stream does not always have, which C++ formalises as ForwardIterator: you can copy the current position, move the copy forward, but still read the value at the location of the original. A generalized stream cannot do this, because the underlying I/O only has one "current position". With a linked list you can have multiple pointers to different nodes in the list, with no troubles.
Some streams can be marked and reset, rewound, seeked (sought?) etc, adding facilities that are somewhat like a C++ ForwardIterator, or even RandomAccessIterator.
I use C++ as an example not because it's particularly important, but because the C++ concept of an iterator is designed in part to provide an abstraction common to data structures and streams. Not all languages have such a common abstraction, but for another example in Python you can write for x in y: if y is a container data structure or if y is a file-like object, or in general if y is "iterable".
Determining whether a singly-linked list has a loop is a common interview question. But why would a linked list exist with a loop? When would a linked list with a loop be useful?
Circularly linked lists can be useful if you want to iterate through the entire list starting from a random iterator or inserting in any position. They simplify the algorithms for those operations as you don't have to account for the beginning or end of the list.
It doesn't matter then, which of the elements you pass to the function as a parameter, for example. When using sentinel pattern, you will iterate over each elements all the same.
Apache uses circularly linked lists to store all its filters.
For some reason they gave it a fancy marketing name ("Bucket Brigades") and call it "a major innovation" - lol.
To use circularly linked lists, you can think about structures that are circular by nature. Such as pool of buffers that are used and released in FIFO order, or a set of processes that should be time-shared in round-robin order, or saving the nodes coordinates of a polygon in their specific order.
Many answers given here consider Completely looped Linked List.
The interview question is a bit different. We've to detect loop (can be partial) somewhere in the link
Eg: (sorry for poor graphics)
1 -> 2 -> 3 -> 4 -> 5
^ v
7 <----- 6
Answer to how it can happen: Link corruption.
a) People trying to crack in through UGC (User Generated Content). Bad data can come up.
b) Design flaws in early stages.
This loop detection is also part of testing we do on LinkedLists to look for suspected bugs.
You've not asked for solutions, but I'll put a few here in brief:
Keep pushing nodes to List (Arraylist in java). The time you find duplicate: Loop detected
Turtle & Hare approach. Turtle jumps one node at a time. Rabbit, two at a time. They meet if it's a loop
store boolean flag *visited* as you traverse. Any encounter of *true* is loop.