Live data from Hacker News

Linked List Problems (2002) [pdf]

cslibrary.stanford.edu

91–100 of 113 posts

Re: Linked List Problems (2002) [pdf]

#91
post #72

Earlier quoted context omitted.

That's why I mentioned the LRU implementation. It does not iterate over the list, only adds elements to the front, deletes from the back and moves from the middle to the front. Refs to nodes are stored in a map, so iteration is not necessary to find an element.

But how do you find the element to be moved from the middle if not by iterating over the list?

You use a hash map, and make the linked list a linked list of hash entries. So, if you're using chaining (as opposed to the many variations on open addressing):

    class Entry {
        Entry younger;  // LRU doubly linked list
        Entry older;    // LRU doubly linked list
        Entry next;     // for hash map bucket chaining
        V value;
        K key;
    }
The naive solution using two separate data structures would look like:

    class MapEntry {
        Entry next;
        DoublyLinkedListEntry> LruEntry;
        K key;
        V value;
    }

    class DoublyLinkedListEntry {
        ListEntry prev;
        LintEntry next;
        T value;
    }

Re: Linked List Problems (2002) [pdf]

#92
post #88

Earlier quoted context omitted.

But how do you find the element to be moved from the middle if not by iterating over the list?

The commenter mentions that in the last sentence. There is some separate data structure that also has references to nodes in the middle of the linked list.

Or, you've removed one indirection and made the linked list actually a part of another data structure, as in how LRU caches are generally implemented.

Re: Linked List Problems (2002) [pdf]

#93
post #92
post #88

Earlier quoted context omitted.

The commenter mentions that in the last sentence. There is some separate data structure that also has references to nodes in the middle of the linked list.

Or, you've removed one indirection and made the linked list actually a part of another data structure, as in how LRU caches are generally implemented.

The entire LRU used multiple data structures, but the ability to efficiently remove from the middle of the linked list is still important.

Re: Linked List Problems (2002) [pdf]

#94

Earlier quoted context omitted.

> It is easy to see that they will eventually meet on the cycle. Not easy for me, but thanks for the algorithm, maybe I will find time and energy to understand and believe. Why by two at a time and not by 3?

Consider a cycle of length n. Consider two integers, i and j that have arbitrary initial values in [0, n). We want to prove that the following loop always terminates: while i % n != j % n: i += 1 j += 2 If we represent this as an equation over time, where t is the number of loops, we want to prove that for some t the following is true: (i + t) % n = (j + 2t) % n Solving for t: (i % n) + (t % n) = (j % n) + (2t % n) (…

Note that if you add the requirement that i and j start on the same node, then no matter what step size you use for x and y, as long as they are integers > 0 and x != y, then i and j will meet again if and only if there is a cycle.

For particular values of x, y, and loop period there may be values of i and j such that going forward from those they never meet, but it is not possible to get into one of those positions if a past state had i == j.

Proof:

In the following I'll use your notation for the most part, except allowing for a "lead in" of length L from that common starting node to the start of the loop, so the nodes are numbered 0, 1, 2, ..., L-1, L, L+1, ..., L+n-1, with the nodes in the loop being {L, L+1, L+2, ..., L+n-1}.

At time t, i has taken xt steps and j has taken yt steps. Let t >= L/x and t >= L/y, so that i and j are both past the lead in into the loop.

Then i is xt-L steps into the loop, and j is yt-L into the loop. These will be at the same spot in the loop if xt-L = yt-L mod n, which happens whenever (x-y)t = 0 mod n. All multiples of n are solutions of this, so just pick any that are >= L/x and L/y, and you have a solution.

If i and j do not start at the same place, all bets are off. That 0 is replaced with the differences between the starting node numbers, and as your example shows may not have a solution for some combinations of parameters.

Re: Linked List Problems (2002) [pdf]

#95

Earlier quoted context omitted.

> It is easy to see that they will eventually meet on the cycle. Not easy for me, but thanks for the algorithm, maybe I will find time and energy to understand and believe. Why by two at a time and not by 3?

Consider a cycle of length n. Consider two integers, i and j that have arbitrary initial values in [0, n). We want to prove that the following loop always terminates: while i % n != j % n: i += 1 j += 2 If we represent this as an equation over time, where t is the number of loops, we want to prove that for some t the following is true: (i + t) % n = (j + 2t) % n Solving for t: (i % n) + (t % n) = (j % n) + (2t % n) (…

Hi! Just a question, since I've never been good with proofs. Why use the modulo operator in the while-loop? Couldn't we just test if i != j?

Re: Linked List Problems (2002) [pdf]

#96
post #82

Earlier quoted context omitted.

No not the specific solution, but the concept of having to pointers moving at different speeds did be pretty clear no? It is really not a hard problem. If you are dealing with cirular lists you will end up having to solve it sooner or later. The "open question in CS for 12 years" is probably easier explained by "nobody could be bothered" than "it is hard".

Considering there are limited use cases for pointers moving at different speeds in other fields, no, I wouldn't say it would be easy. The idea itself, once you hear it, instantly makes sense. But having the ingenuity to thinking of it during a stressful period shouldn't be used as a measure of how good a candidate would be for a position. Especially considering there are hundreds of different ways of approaching such…

I think the opposite. It is a simple problem. I wouldn't expect someone to write a working solution on a whiteboard, but in a reasoning discussion come up with the answer.

Say if you have one list that might be circular from the "starting" element or not circular at all. You simply save the pointer to the first element an compare every subsequent element to that. If you find the end of the list it is not circular. If you find the first element it is circular.

The step from that to a general approach for finding whether a list contains circular references should be simple.

I am however coming from scheme where linked lists are abundant.

Edit: not to say I think it is a good problem for an interview, but I would expect someone to be able to solve the problem in one way or another it without googling. What I am questioning is that it is a hard problem, or a very hard solution.

Re: Linked List Problems (2002) [pdf]

#97

Earlier quoted context omitted.

Consider a cycle of length n. Consider two integers, i and j that have arbitrary initial values in [0, n). We want to prove that the following loop always terminates: while i % n != j % n: i += 1 j += 2 If we represent this as an equation over time, where t is the number of loops, we want to prove that for some t the following is true: (i + t) % n = (j + 2t) % n Solving for t: (i % n) + (t % n) = (j % n) + (2t % n) (…

Hi! Just a question, since I've never been good with proofs. Why use the modulo operator in the while-loop? Couldn't we just test if i != j?

The modulo represents the cycle.

Maybe it would be helpful to rewrite the loop with a condition as you described, and %= i and j with n after incrementing (by 1 or by 2) both variables in the loop body.

Re: Linked List Problems (2002) [pdf]

#98
post #11

Earlier quoted context omitted.

He says because of cache misses due to each element being allocated individually. But then working with references is bad in general? If your vector stores references to objects it's bad? Your object fields point to strings - bad too. Should we ditch Lisp and Java? Note, data should not be continuous to stay in cache. Cache is more like paged virtual memory, it consists of cache lines. Before subscribing to the "neve…

Yes, organizing your data in an array of structures is also bad for performance.

Doesn’t this entirely depend on access patterns?

If you read one field of all elements all at once, sure, a structure of arrays is probably right. But what if you instead read all fields of one element at once? Isn’t it advantageous to have those fields adjacent in memory with an array of structures?

Re: Linked List Problems (2002) [pdf]

#99
post #39

Earlier quoted context omitted.

> if you're accessing data sequentially it's more likely the data you're going to access next is already in cache Why?

Cache prefetching. ( https://en.wikipedia.org/wiki/Cache_prefetching ) Essentially, many workloads access data sequentially and therefore modern cache architectures have special optimizations to make these memory accesses as fast as possible, by prefetching the next item in the sequence before it is actually needed.

Ah, yes.

Well, anyways I value code simplicity more than anything.

Maybe CPUs will learn to do cache prefetch for link oriented languages: if a "load and dereference" pattern is detected, CPU could prefetch the data referenced by pointers it has in registers or recently fetched cache line.

BTW, linked list elements are not necessary located far away from each other, if we allocated them one after another chance are they are near each other in memory.

Re: Linked List Problems (2002) [pdf]

#100
post #71

Earlier quoted context omitted.

Are you suggesting computer scientists should be able to derive non trivial results on job interviews? Really?

This amount of nontrivial, yes. Similarly, I'd expect a computer scientist to come up with a proof of correctness for either binary search or merge sort (the out of place variant) in ~30 minutes. It's not particularly difficult.

The number of incorrect binary search algorithms published in the literature over the years would indicate otherwise…

I agree that reasoning about the correctness of a binary search algorithm is an important job skill for a computer scientist. Deriving the tortoise and hare algorithm on the fly, though, is not.

Post reply on HN